Craft of code
Writing code others can maintain
Managing complexity with deep modules, clear naming, honest comments, consistent style, and error strategies that shrink the blast radius of change.
Software spends most of its life being changed by people who did not write it. The feature you ship this week will be edited next quarter by a teammate who has never opened the file, under a deadline, at 11pm, with half the original context gone. Maintainable code is not "pretty" code. It is code that keeps the cost of that next change low.
The enemy is complexity: anything that makes the system hard to understand or hard to modify. John Ousterhout's framing separates three symptoms that feel different but share a root cause: change amplification, cognitive load, and unknown unknowns.
Concepts in this section
Read them in order. Each one builds on the one before.
| Step | Concept | What it answers |
|---|---|---|
| 1 | Software complexity | What are you actually fighting? |
| 2 | Deep modules | How do you hide complexity behind a small interface? |
| 3 | Naming and comments | What does the next reader see first? |
| 4 | Error handling and illegal states | How do failures stay visible and rare? |
| 5 | Duplication vs the wrong abstraction | When is copy-paste the right call? |
| 6 | Interfaces that age well | What can you not change cheaply later? |
Prefer boring consistency, deep modules at the right boundaries, and tests that lock behavior (see testing strategy). Code review is where this craft shows up daily.
A one-line product change
Checkout applied a percentage discount, then tax, with names like d and t. A one-line product change — "discount applies after tax in EU, before tax in US" — forced reverse-engineering of units and order.
After a maintainability pass: subtotalCents, applyPercentDiscount, applyTax, explicit MoneyCents, validated rates. The next engineer changes EU vs US policy without decoding the original.
That is the whole topic in one picture: spend an hour now so the next stranger's change is calm. Beck's move under a deadline is the same idea: a tidy commit that makes the change easy, then a behavior commit reviewers can actually see.
Common mistakes
- Shallow pass-through layers that add names without hiding decisions.
- Clever one-liners and premature frameworks that raise cognitive load.
- DRY on text that is not the same knowledge.
- Swallowing errors so production looks like "no rows."
- Two house styles in one repo.
Key takeaways
- Optimize for the next change by a stranger: minimize change amplification, cognitive load, and unknown unknowns.
- Prefer deep modules with small interfaces over shallow pass-through layers.
- Names and function boundaries carry most of the documentation; comments explain why.
- Match the codebase's conventions; two styles cost more than one imperfect style.
- Fail fast, make errors explicit, and redesign away avoidable failure modes.
- Duplicate until you know the right abstraction; YAGNI for imaginary futures.
Further learning
Ousterhout's Talks at Google session is the fastest way to internalize deep modules and complexity symptoms.
Related
Code review
Author small, reviewable PRs and give reviews that improve both the code and the author — design first, tone that teaches, turnaround that unblocks.
Refactoring and legacy code
Change code you did not write without breaking it. Start here for characterization, seams, tiny steps, and incremental migrations.
Testing strategy
What to test, at which level, and how to keep a suite fast, reliable, and worth the maintenance — from pyramid trade-offs to production safety nets.