codebase-design
Codebase Design
Put related rules and behavior in modules that callers can use without understanding their internals. Judge a design by what callers must know, how many places must change when a rule changes, and how easily its behavior can be tested.
Terms
Use the project's existing names. These distinctions help explain a design; they are not a reason to rename code or domain concepts.
- Module: a function, class, package, or other unit with an interface and an implementation.
- Interface: everything a caller must know to use a module correctly, including types, required call order, errors, configuration, and performance constraints. This means more than a TypeScript
interfacedeclaration. - Implementation: the code behind that interface.
- Adapter: an implementation that connects an interface to a particular dependency, such as a database or external service. The term describes its role, not its size.
- Seam: a place where behavior or a dependency can be substituted, including for a test. State whether it is internal to a module or exposed to application callers when that distinction matters.
A deep module hides decisions that callers would otherwise have to make themselves. A shallow wrapper adds an interface without reducing that work. Code size, method count, and the ratio of interface to implementation lines do not establish either one.
Design from callers
Sketch representative call sites before types or methods. Derive the interface from what those callers need. Keep processing stages, storage details, and coordination inside the module unless callers need to control them.