The ratio of benefit (functionality provided) to cost (interface complexity). A deep module delivers powerful functionality behind a small, stable interface; a shallow module exposes nearly as much complexity as it…
Deep Modules
Details
- Also known as
-
Module Depth, Deep Classes
Core Concepts:
- Module depth
-
The ratio of benefit (functionality provided) to cost (interface complexity). A deep module delivers powerful functionality behind a small, stable interface; a shallow module exposes nearly as much complexity as it contains.
- Shallow module
-
A module whose public interface is almost as complex as its implementation. Shallow modules shift the complexity burden onto callers rather than hiding it — adding interface cost without proportional abstraction benefit.
- Interface as cost
-
Every element of a public API — parameters, types, configuration options, side effects — is cognitive cost that every caller must pay. Deep modules minimise this cost while maximising what they deliver.
- Information hiding
-
Modules should encapsulate design decisions likely to change: data structures, algorithms, file formats, protocols. Those decisions remain invisible to callers, so the interface stays stable even as the implementation evolves.
- Classitis
-
Ousterhout’s term for the anti-pattern of decomposing a system into many tiny, shallow classes. Each class adds its own interface to the collective cognitive load without reducing overall implementation complexity.
- Different layer, different abstraction
-
Each architectural layer should offer abstractions meaningfully different from the layer below. A layer that only renames lower-level calls without adding substance is a shallow passthrough and a sign of poor design.
- Key Proponents
-
John Ousterhout ("A Philosophy of Software Design", 2nd ed., Yaknyam Press, 2021; 1st ed. 2018 — Chapter 4: "Modules Should Be Deep")
When to Use:
-
Designing a module’s public API — evaluate whether the interface is simpler than the implementation it hides
-
Reviewing a proposed class decomposition for whether it reduces complexity or merely redistributes it
-
Identifying pass-through methods and wrapper chains that add interface cost without hiding detail
-
Instructing an LLM to design APIs or class boundaries with minimal caller-visible surface area
-
Choosing between a general-purpose and a special-purpose API — prefer the deeper, more general option
Related Anchors:
Criticism:
-
Andrey Lebedev, "Not My Philosophy of Software Design" (Medium) — argues that forcing depth into a single class violates the Single Responsibility Principle; the Java I/O example conflates file reading with buffering, two genuinely separate concerns; deep general-purpose classes also resist composition and create coupling that contradicts domain-driven design practice
-
"Modules Should Be Deep!" (Software Engineering: A Modern Approach) — adds nuance:
String.isEmpty()provides semantic clarity and safe encapsulation despite its trivial implementation, challenging a purely quantitative interpretation of depth; Bertrand Meyer’s iceberg metaphor — small visible tip over large submerged base — is cited as a complementary framing