refactor(plugin)!: ship as a Claude Code plugin, one dir link per harness
Skills move to skills/<name>/SKILL.md and the repo gains both manifests, so it is now a marketplace hosting exactly one plugin whose root is the repo root (source: "."). Claude Code installs it from git; no symlinks involved. Why: install.sh wired the library into every consuming repo as an ABSOLUTE symlink to $CHECKOUT_DIR. The checkout moved three times, most recently when local-dev@1966d5a dropped the embedded .skills/ copy, and nothing migrated the links — 243 dangling links across 12 repos, hidden from git by the **/.claude/skills/ ignore rule. Worse, ~/dev spans two path roots (/Users/mathias on the iCloud-shared Macs, /home/mathias on koala), so an absolute link stored there is broken on one side by construction. Re-running the installer cannot fix that; only removing the mechanism can. install.sh keeps the harnesses with no plugin system and drops from 42 links per harness to one directory link, via the convergent ~/.agents/skills convention that Pi and OpenCode both read: ~/.agents/skills -> $CHECKOUT_DIR/skills ~/.config/crush/skills -> ~/.agents/skills ~/.config/opencode/skills -> ~/.agents/skills wire_claude_repo is deleted outright rather than gated behind a flag — on a mixed-root fleet it cannot be made correct. Antigravity and Vibe targets go too; both unused. CHECKOUT_DIR keeps its host-local default deliberately: pointing it into ~/dev would put a git working tree inside iCloud with two concurrent writers. Taskfile drops five near-identical wiring loops (they had already drifted) and delegates to install.sh. `task check` gains frontmatter validation, a stray-root-entry gate, and manifest/tag version parity — the loose secret-hygiene.md sat unloadable for months because nothing checked layout. Verified: claude plugin validate . passes clean; a probe skill loaded as skills:zzprobe through --plugin-dir; task check green at 42 skills. Refs: #23 Bump-Type: minor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m
This commit is contained in:
@@ -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