codebase-design
Codebase Design
Design deep modules: a lot of behaviour tucked behind a small interface, sited at a clean seam, and tested through that interface. Apply this language and these principles anywhere code is being designed or reshaped. You are chasing three payoffs — leverage for callers, locality for maintainers, and testability for everyone.
Glossary
Use these terms precisely. Don't swap in "component," "service," "API," or "boundary" — the consistency is the whole point.
Module — anything that pairs an interface with an implementation. Intentionally scale-agnostic: a function, a class, a package, or a slice that spans tiers. Avoid: unit, component, service.
Interface — everything a caller must know to use the module correctly: the type signature, yes, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. Avoid: API, signature (both too narrow — they name only the type-level surface).
Implementation — the code inside a module, its body. Not the same as Adapter: a thing can be a small adapter wrapping a large implementation (a Postgres repo) or a large adapter wrapping a small one (an in-memory fake). Say "adapter" when the seam is the subject; "implementation" otherwise.
Depth — leverage at the interface: how much behaviour a caller (or test) can reach per unit of interface it must learn. A module is deep when a lot of behaviour hides behind a small interface, shallow when the interface is nearly as complex as the implementation.
Seam (Michael Feathers) — a place where behaviour can change without editing that place; the location where a module's interface sits. Choosing where the seam goes is a design decision in its own right, separate from deciding what lives behind it. Avoid: boundary (already overloaded by DDD's bounded context).
Adapter — a concrete thing that satisfies an interface at a seam. It names a role (which slot it fills), not a substance (what's inside).