Minimize Reader Load
Maintainability is the work a reader must do to understand code. Track two axes:
- Layers to trace. How many indirections sit between the question and the answer.
- State to hold. How much hidden or mutable context the reader must keep in their head.
Why: Code is read far more than it is written. LOC, cyclomatic complexity, and "clean architecture" are proxies. Reader load is the thing that matters. The two axes are independent. A flat file with 50 globals can be as hard to reason about as a 6-layer adapter stack. Guard both. This is the human analog of Guard the Context Window: working memory is finite for readers too.
The pattern:
- Collapse layers that do not earn their keep: wrappers with one caller, adapters with no second implementation, indirection introduced for a future that never came. Inline them.
- Make adjacent layers change the abstraction. A layer that repeats the same methods and arguments adds reader load without compression. Collapse pass-through layers.
- Demand interface compression. A broad interface that hides little complexity makes readers learn both the surface and the implementation. Prefer boundaries that hide meaningful decisions.
- Shrink state scope: prefer pure functions (returns over mutations), locals over fields, fields over module state, and module state over globals. Derive instead of sync.
- Name the invariant at the boundary, not in every consumer, so the reader learns it once.
- Before adding a layer or a piece of state, ask: does this reduce reader load somewhere else by at least as much?
The test: Can a new reader answer "where does X come from?" and "what can change X?" in under 30 seconds? If not, cut layers or cut state.
Battle-tested, and mechanically checkable: a fix updated one reader of a shared mutable timestamp's staleness check but missed a second reader with a different, undocumented assumption about the same field — reproducing the identical bug shape weeks later. Before closing out a fix that touches a field, flag, or timestamp read by more than one function, grep every other reader of that identifier and ask whether it needs the same fix. This one is a real mechanical step, not just a judgment call — "what can change X?" only answers half the question; "what else reads X?" is the other half, and it's greppable.
Also applies to conversational output, not just code: a corpus retrospective found a mid-task status update crammed with internal jargon and multi-step abbreviations that got a direct "uhhh what" from the user, followed by the agent apologizing and re-explaining in plain language. The same two axes apply outside code — a status update with many undefined internal terms forces the reader to hold state (what does each term mean) just to parse one sentence. Write status updates for a reader who wasn't in your head while you worked, the same way you'd write code for a reader who wasn't in the room when you wrote it.