update skills
This commit is contained in:
1 parent
9fb18f57ec
commit
ff86cf48b4
82 files changed
+2156
-650
No files matched your search
@@ -8,7 +8,7 @@ When assessing a candidate for deepening, classify its dependencies. The categor
|
||||
|
||||
### 1. In-process
|
||||
|
||||
Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed.
|
||||
Pure computation, in-memory state, no I/O. Merge only when it concentrates a cohesive responsibility and reduces caller complexity. Test through the resulting behavior-level interface; no adapter is needed for pure computation.
|
||||
|
||||
### 2. Local-substitutable
|
||||
|
||||
@@ -26,12 +26,12 @@ Third-party services (Stripe, Twilio, etc.) you don't control. The deepened modu
|
||||
|
||||
## Seam discipline
|
||||
|
||||
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
|
||||
- **Justify a seam by its current benefit.** Test isolation, ownership, real variability, or an external contract can justify it; adapter count alone cannot. Do not manufacture a second implementation or an unused port.
|
||||
- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
|
||||
|
||||
## Testing strategy: replace, don't layer
|
||||
## Testing strategy: preserve behavioral coverage
|
||||
|
||||
- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them.
|
||||
- Before deleting old tests, map their success, failure, and edge-case coverage to the replacement checks. Delete only redundant or obsolete tests after confirming equivalent meaningful coverage; keep tests that catch distinct failures.
|
||||
- Write new tests at the deepened module's interface. The **interface is the test surface**.
|
||||
- Tests assert on observable outcomes through the interface, not internal state.
|
||||
- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.
|
||||
- Prefer tests that survive behavior-preserving refactors. A test change is a signal to review coupling, not proof that the test is worthless; integration, algorithm, and concurrency checks may protect distinct contracts.
|
||||
@@ -18,14 +18,13 @@ Show this to the user, then immediately proceed to Step 2. The user reads and th
|
||||
|
||||
### 2. Spawn sub-agents
|
||||
|
||||
Spawn 3+ sub-agents in parallel. Each must produce a **radically different** interface for the deepened module.
|
||||
Honor the requested number of alternatives; two is a useful default. Use independent subagents through the available delegation tool when useful and within available slots, or compare directly when delegation is unavailable. Each option should explore a meaningfully different trade-off for the same requirements.
|
||||
|
||||
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
|
||||
|
||||
- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point."
|
||||
- Agent 2: "Maximise flexibility — support many use cases and extension."
|
||||
- Agent 3: "Optimise for the most common caller — make the default case trivial."
|
||||
- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
|
||||
- One option can optimize for the primary caller's workflow.
|
||||
- Another can emphasize explicit state transitions or failure handling.
|
||||
- Add a dependency-focused option only when that is an actual design question; do not invent flexibility, adapters, or a target method count.
|
||||
|
||||
Include both [SKILL.md](SKILL.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
|
||||
|
||||
@@ -39,6 +38,6 @@ Each sub-agent outputs:
|
||||
|
||||
### 3. Present and compare
|
||||
|
||||
Present designs sequentially so the user can absorb each one, then compare them in prose. Contrast by **depth** (leverage at the interface), **locality** (where change concentrates), and **seam placement**.
|
||||
Use the requested or clearest concise format. Contrast **depth** (leverage at the interface), **locality** (where change concentrates), **seam placement**, implementation effort, and risk.
|
||||
|
||||
After comparing, give your own recommendation: which design you think is strongest and why. If elements from different designs would combine well, propose a hybrid. Be opinionated — the user wants a strong read, not a menu.
|
||||
@@ -9,17 +9,17 @@ Design **deep modules**: a lot of behaviour behind a small interface, placed at
|
||||
|
||||
## Glossary
|
||||
|
||||
Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
|
||||
Use these concepts to explain the design, while preserving the repository's actual names and domain vocabulary. A component, service, or API can be the module or interface under discussion; explain the distinction when it matters instead of banning familiar terms.
|
||||
|
||||
**Module** — anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service.
|
||||
**Module** — anything with an interface and an implementation: a function, component, service, class, package, or tier-spanning slice.
|
||||
|
||||
**Interface** — everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow — they refer only to the type-level surface).
|
||||
**Interface** — everything a caller must know: signatures, invariants, ordering, errors, configuration, and relevant performance characteristics. An API signature alone may describe only part of that contract.
|
||||
|
||||
**Implementation** — what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
|
||||
|
||||
**Depth** — leverage at the interface: the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation.
|
||||
|
||||
**Seam** _(Michael Feathers)_ — a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context).
|
||||
**Seam** _(Michael Feathers)_ — a place where behavior can be varied without editing that place. Distinguish a test or substitution seam from a domain or deployment boundary when the difference affects the design.
|
||||
|
||||
**Adapter** — a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
|
||||
|
||||
@@ -61,8 +61,8 @@ When designing an interface, ask:
|
||||
|
||||
- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
|
||||
- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
|
||||
- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape.
|
||||
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
|
||||
- **Prefer behavior-level test surfaces.** Test through the relevant contract, while retaining focused checks for internal algorithms or integration invariants when they catch failures the higher interface does not.
|
||||
- **Justify seams by a current need.** Test isolation, ownership, external integration, or real variation may justify a boundary even with one runtime implementation. Do not add an adapter merely to satisfy a count, or a speculative abstraction with no concrete benefit.
|
||||
|
||||
## Designing for testability
|
||||
|
||||
@@ -80,7 +80,7 @@ Good interfaces make testing natural:
|
||||
}
|
||||
```
|
||||
|
||||
2. **Return results, don't produce side effects.**
|
||||
2. **Prefer pure results for calculations; keep necessary effects explicit.**
|
||||
|
||||
```typescript
|
||||
// Testable
|
||||
@@ -106,7 +106,7 @@ Good interfaces make testing natural:
|
||||
|
||||
- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
|
||||
- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know.
|
||||
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
|
||||
- **Unqualified boundaries**: clarify whether a boundary concerns tests, domain ownership, deployment, or caller contracts when that distinction matters.
|
||||
|
||||
## Going deeper
|
||||
|
||||
|
||||
Reference in new issue
Block a user