chore: bootstrap skills library — 19 skills + installer + CI auto-tag
Some checks failed
release / tag (push) Has been cancelled
Some checks failed
release / tag (push) Has been cancelled
Phase 1 of mathias/skills extraction (infra#62 Track D — homelab next-step plan addendum). Imports ~/dev/.skills/ verbatim (19 skill dirs + SKILLS_INDEX.md) and adds the installation surface: - Taskfile.yml — install / update / list / release / check targets - install.sh — bootstrap installer for hosts without Task. Idempotent symlink wirer; default checkout at ~/.local/share/skills/ on every host; SKILLS_REF env var pins a tag (default: main). - .gitea/workflows/release.yml — auto-tag every push to main by Bump-Type footer (major/minor/patch, default patch). Skipped when commit contains [skip-release]. - README — usage, versioning, contribution flow, secret-hygiene rule. Phase 1 wires Claude Code only (~/.claude/skills/<name> global + <repo>/.claude/skills/<name> per-repo). Phase 2 adds Crush, opencode, antigravity, and gitea-resident agents (cobalt-dingo, agentsquad) once their skill conventions are researched. Public repo, markdown-only — no secrets, no client names. Verified via pre-push grep before initial push. [skip-release]
This commit is contained in:
286
solid/references/complexity.md
Normal file
286
solid/references/complexity.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Managing Complexity
|
||||
|
||||
## The Two Types of Complexity
|
||||
|
||||
### Essential Complexity
|
||||
Inherent to the problem domain. Cannot be removed, only managed.
|
||||
- Business rules
|
||||
- Domain logic
|
||||
- User requirements
|
||||
|
||||
### Accidental Complexity
|
||||
Introduced by our solutions. CAN and SHOULD be minimized.
|
||||
- Poor abstractions
|
||||
- Unnecessary indirection
|
||||
- Framework ceremony
|
||||
- Technical debt
|
||||
|
||||
**Goal: Minimize accidental complexity while clearly expressing essential complexity.**
|
||||
|
||||
---
|
||||
|
||||
## Detecting Complexity
|
||||
|
||||
### 1. Change Amplification
|
||||
Small changes require touching many files.
|
||||
|
||||
**Symptom:** "To add this field, I need to update 15 files."
|
||||
|
||||
**Cause:** Scattered responsibilities, poor abstraction boundaries.
|
||||
|
||||
### 2. Cognitive Load
|
||||
Code is hard to understand, requires holding too much in memory.
|
||||
|
||||
**Symptom:** "I need to understand 10 other classes to understand this one."
|
||||
|
||||
**Cause:** Tight coupling, hidden dependencies, unclear naming.
|
||||
|
||||
### 3. Unknown Unknowns
|
||||
Behavior is surprising, side effects are hidden.
|
||||
|
||||
**Symptom:** "I changed this, and something completely unrelated broke."
|
||||
|
||||
**Cause:** Global state, hidden dependencies, implicit contracts.
|
||||
|
||||
---
|
||||
|
||||
## The XP Values for Fighting Complexity
|
||||
|
||||
From Extreme Programming:
|
||||
|
||||
### 1. Communication
|
||||
Code should communicate clearly. Names, structure, tests all contribute.
|
||||
|
||||
### 2. Simplicity
|
||||
Do the simplest thing that could possibly work.
|
||||
|
||||
### 3. Feedback
|
||||
Fast feedback loops catch complexity early. TDD, CI, code review.
|
||||
|
||||
### 4. Courage
|
||||
Refactor aggressively. Don't let complexity accumulate.
|
||||
|
||||
### 5. Respect
|
||||
Respect future readers (including yourself). Write for humans first.
|
||||
|
||||
---
|
||||
|
||||
## KISS - Keep It Simple, Silly
|
||||
|
||||
> "The simplest solution that works is usually the best."
|
||||
|
||||
### How to Apply:
|
||||
1. Start with the obvious solution
|
||||
2. Only add complexity when REQUIRED
|
||||
3. Prefer boring, well-understood approaches
|
||||
4. Question every abstraction
|
||||
|
||||
```typescript
|
||||
// Over-engineered
|
||||
class UserServiceFactoryProvider {
|
||||
private static instance: UserServiceFactoryProvider;
|
||||
|
||||
static getInstance(): UserServiceFactoryProvider { ... }
|
||||
createFactory(): UserServiceFactory { ... }
|
||||
}
|
||||
|
||||
// KISS
|
||||
class UserService {
|
||||
getUser(id: string): User { ... }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## YAGNI - You Aren't Gonna Need It
|
||||
|
||||
> "Don't build features until they're actually needed."
|
||||
|
||||
### Warning Signs:
|
||||
- "We might need this later"
|
||||
- "It would be nice to have"
|
||||
- "Just in case"
|
||||
- "For future extensibility"
|
||||
|
||||
### The Cost of YAGNI Violations:
|
||||
1. **Development time** - Building unused features
|
||||
2. **Maintenance burden** - Code that must be maintained
|
||||
3. **Cognitive load** - More to understand
|
||||
4. **Wrong abstraction** - Guessing future needs incorrectly
|
||||
|
||||
```typescript
|
||||
// YAGNI violation: Building for hypothetical needs
|
||||
class User {
|
||||
// "We might need these someday"
|
||||
middleName?: string;
|
||||
secondaryEmail?: string;
|
||||
faxNumber?: string;
|
||||
linkedinProfile?: string;
|
||||
twitterHandle?: string;
|
||||
}
|
||||
|
||||
// YAGNI: Only what's needed NOW
|
||||
class User {
|
||||
name: string;
|
||||
email: Email;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DRY - Don't Repeat Yourself (with The Rule of Three)
|
||||
|
||||
> "Every piece of knowledge should have a single, unambiguous representation."
|
||||
|
||||
### BUT: The Rule of Three
|
||||
|
||||
**Don't extract duplication until you see it THREE times.**
|
||||
|
||||
Why? The wrong abstraction is worse than duplication.
|
||||
|
||||
```
|
||||
Duplication #1 → Leave it
|
||||
Duplication #2 → Note it, leave it
|
||||
Duplication #3 → NOW extract it
|
||||
```
|
||||
|
||||
### Example:
|
||||
```typescript
|
||||
// First time - leave it
|
||||
function processUserOrder(order) {
|
||||
validate(order);
|
||||
calculateTax(order);
|
||||
save(order);
|
||||
}
|
||||
|
||||
// Second time - note the similarity, but leave it
|
||||
function processGuestOrder(order) {
|
||||
validate(order);
|
||||
calculateTax(order);
|
||||
save(order);
|
||||
sendGuestEmail(order);
|
||||
}
|
||||
|
||||
// Third time - NOW extract
|
||||
function processCorporateOrder(order) {
|
||||
validate(order);
|
||||
calculateTax(order);
|
||||
save(order);
|
||||
applyCorporateDiscount(order);
|
||||
}
|
||||
|
||||
// After three, extract the common parts
|
||||
function processOrder(order: Order, postProcessing: (o: Order) => void) {
|
||||
validate(order);
|
||||
calculateTax(order);
|
||||
save(order);
|
||||
postProcessing(order);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Separation of Concerns
|
||||
|
||||
> "Each module should address a single concern."
|
||||
|
||||
### Concerns to Separate:
|
||||
- **Business logic** vs **Infrastructure**
|
||||
- **What** (policy) vs **How** (mechanism)
|
||||
- **Input** vs **Processing** vs **Output**
|
||||
- **Data** vs **Behavior**
|
||||
|
||||
### Example:
|
||||
```typescript
|
||||
// BAD: Mixed concerns
|
||||
class OrderProcessor {
|
||||
process(order: Order) {
|
||||
// Validation
|
||||
if (!order.items.length) throw new Error('Empty');
|
||||
|
||||
// Business logic
|
||||
let total = 0;
|
||||
for (const item of order.items) {
|
||||
total += item.price * item.quantity;
|
||||
}
|
||||
|
||||
// Persistence
|
||||
const db = new Database();
|
||||
db.query(`INSERT INTO orders...`);
|
||||
|
||||
// Notification
|
||||
const email = new EmailClient();
|
||||
email.send(order.customer.email, 'Order confirmed');
|
||||
}
|
||||
}
|
||||
|
||||
// GOOD: Separated concerns
|
||||
class OrderProcessor {
|
||||
constructor(
|
||||
private validator: OrderValidator,
|
||||
private calculator: OrderCalculator,
|
||||
private repository: OrderRepository,
|
||||
private notifier: OrderNotifier
|
||||
) {}
|
||||
|
||||
process(order: Order): ProcessResult {
|
||||
this.validator.validate(order);
|
||||
const total = this.calculator.calculateTotal(order);
|
||||
const savedOrder = this.repository.save(order);
|
||||
this.notifier.notifyConfirmation(savedOrder);
|
||||
return ProcessResult.success(savedOrder);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Managing Technical Debt
|
||||
|
||||
### Types of Technical Debt:
|
||||
1. **Deliberate** - Conscious trade-off for speed
|
||||
2. **Accidental** - Mistakes, lack of knowledge
|
||||
3. **Bit rot** - Code degrades over time
|
||||
|
||||
### The Boy Scout Rule:
|
||||
> "Leave the code better than you found it."
|
||||
|
||||
Every time you touch code:
|
||||
- Improve one small thing
|
||||
- Fix one naming issue
|
||||
- Extract one method
|
||||
- Add one missing test
|
||||
|
||||
### When to Pay Down Debt:
|
||||
- When it's in your path (you're already there)
|
||||
- When it's blocking new features
|
||||
- When it's causing bugs
|
||||
- During dedicated refactoring time
|
||||
|
||||
### When NOT to Refactor:
|
||||
- Code that works and won't change
|
||||
- Code being replaced soon
|
||||
- When you don't have tests
|
||||
|
||||
---
|
||||
|
||||
## The Four Elements of Simple Design
|
||||
|
||||
In priority order (from XP):
|
||||
|
||||
1. **Runs all the tests**
|
||||
- If it doesn't work, nothing else matters
|
||||
|
||||
2. **Expresses intent**
|
||||
- Clear names, obvious structure
|
||||
- Code tells the story
|
||||
|
||||
3. **No duplication**
|
||||
- DRY (but Rule of Three)
|
||||
- Single source of truth
|
||||
|
||||
4. **Minimal**
|
||||
- Fewest classes and methods possible
|
||||
- Remove anything unnecessary
|
||||
|
||||
If these four are true, the design is simple enough.
|
||||
Reference in New Issue
Block a user