Codebase Design
Design deep modules: a lot of behavior behind a small interface, placed at a clean seam, testable through that interface.
Glossary
Use these terms exactly - consistent language is the point.
- Module - anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice.
- Interface - everything a caller must know to use the module correctly: type signature, invariants, ordering constraints, error modes, configuration, and performance characteristics.
- Implementation - what is inside a module, its body of code.
- Depth - leverage at the interface: the amount of behavior a caller can exercise per unit of interface they have to learn.
- Seam (Michael Feathers) - a place where you can alter behavior without editing in that place.
Principles
- Deep over shallow: prefer a small interface that hides lots of behavior
- Test through the interface: if the seam is clean, the test is simple
- Caller leverage: every line of interface should unlock multiple lines of behavior
Common Pitfalls
- Inconsistent terminology: Do not substitute 'component', 'service', 'API', or 'boundary' for the defined terms. Consistent language is the whole point.
- Depth over everything: Depth is a goal, but not the only one. Performance requirements, operational constraints, and team familiarity also matter.
- Seams placed at the wrong level: A seam should match a natural boundary in the domain, not an architectural fashion. Forcing seams where they do not belong creates accidental complexity.
Code Examples
// Deep module example: small interface, complex implementation
interface PaymentProcessor {
charge(amount: Money, source: PaymentSource): Result<Payment>;
refund(paymentId: string): Result<Payment>;
}
// Implementation handles: retries, idempotency, webhook verification,
// currency conversion, fee calculation, receipt email,
// fraud detection, dispute handling, logging
// But caller only sees charge() and refund()
class StripePaymentProcessor implements PaymentProcessor {
// ... complex internals hidden behind a simple interface
}
Verification Checklist
1---2name: codebase-design3description: Use when designing module interfaces, finding deepening opportunities, or making code testable4---56# Codebase Design78Design deep modules: a lot of behavior behind a small interface, placed at a clean seam, testable through that interface.910## Glossary11Use these terms exactly - consistent language is the point.1213- **Module** - anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice.14- **Interface** - everything a caller must know to use the module correctly: type signature, invariants, ordering constraints, error modes, configuration, and performance characteristics.15- **Implementation** - what is inside a module, its body of code.16- **Depth** - leverage at the interface: the amount of behavior a caller can exercise per unit of interface they have to learn.17- **Seam** (Michael Feathers) - a place where you can alter behavior without editing in that place.1819## Principles20- Deep over shallow: prefer a small interface that hides lots of behavior21- Test through the interface: if the seam is clean, the test is simple22- Caller leverage: every line of interface should unlock multiple lines of behavior2324## Common Pitfalls2526- **Inconsistent terminology**: Do not substitute 'component', 'service', 'API', or 'boundary' for the defined terms. Consistent language is the whole point.27- **Depth over everything**: Depth is a goal, but not the only one. Performance requirements, operational constraints, and team familiarity also matter.28- **Seams placed at the wrong level**: A seam should match a natural boundary in the domain, not an architectural fashion. Forcing seams where they do not belong creates accidental complexity.2930## Code Examples3132```typescript33// Deep module example: small interface, complex implementation3435interface PaymentProcessor {36 charge(amount: Money, source: PaymentSource): Result<Payment>;37 refund(paymentId: string): Result<Payment>;38}3940// Implementation handles: retries, idempotency, webhook verification,41// currency conversion, fee calculation, receipt email,42// fraud detection, dispute handling, logging43// But caller only sees charge() and refund()44class StripePaymentProcessor implements PaymentProcessor {45 // ... complex internals hidden behind a simple interface46}47```4849## Verification Checklist5051- [ ] Module terminology used consistently throughout52- [ ] Interface signatures are clear and minimal53- [ ] Depth evaluated: behavior per unit of interface54- [ ] Seam boundaries identified and justified55- [ ] Design principles documented