module-depth
Module depth
Every module has two sides, and its worth is the gap between them.
- Interface: everything a caller must know. Not just signatures, but exceptions, required ordering, side effects, config read, and errors to handle.
- Implementation: everything it does.
A module's value is functionality hidden minus interface cost.
A deep module has a small interface and substantial functionality behind it. A shallow module has an interface nearly as complex as its implementation, so it costs more to learn than it saves.
The framing is John Ousterhout's, from A Philosophy of Software Design. Unix file I/O is the canonical deep module: open, read, write, close, lseek hide disk scheduling, buffering, permissions, block allocation, device drivers, and the difference between a file, a pipe, and a socket.
Why this outranks "keep it small"
Advice to write small classes and small functions optimizes only the implementation side. Applied without the cost side it produces classitis: many tiny classes, each simple, with the complexity relocated into the relationships between them and thirty interfaces to learn instead of three.
Reconcile the two rules this way: