A Philosophy of Software Design
Core thesis: The greatest limitation in writing software is our ability to understand the systems we are creating. Complexity is the root cause of most software problems, and the primary job of software design is to manage and reduce it.
Core Ideas
- Complexity is the enemy. The most fundamental problem in computer science is problem decomposition: how to take a complex problem and divide it up into pieces that can be solved independently. Every design decision should be evaluated through the lens of “does this increase or decrease the system’s complexity?”
- Recognize complexity as a skill. The ability to recognize complexity is a crucial design skill. Most developers don’t actively look for complexity — they create it accidentally through a thousand small decisions. Training yourself to see complexity is as important as knowing how to reduce it.
- Waterfall fails because software is inherently complex. It isn’t possible to visualize the design for a large software system well enough to understand all of its implications before building anything. Problems don’t become apparent until implementation is underway. Developers patch around problems without changing the overall design, producing an explosion of complexity.
- Incremental development means continuous redesign. The antidote to waterfall isn’t just iterating — it’s being willing to redesign continuously. Each increment should improve the design, not just add features on top of an existing structure.
- Always be thinking about complexity. If reducing complexity is the most important element of software design, and software developers should always be thinking about design, then software developers should always be thinking about complexity. It’s not a separate activity — it’s the through-line of all engineering work.
Why It Matters to Me
This book distills what separates senior engineers from everyone else: the ability to see and fight complexity. It’s the engineering counterpart to the management principle that the leader’s job is designing the system, not doing the work. Ousterhout gives a vocabulary for the thing experienced engineers do intuitively — evaluate every decision through the lens of cognitive load on future readers.
Relevance to Dave (Mar 2026):
- DO role: Walking into a 17-year codebase with an Elixir/Phoenix stack I don’t know yet. Ousterhout’s framework gives me a language for evaluating architecture decisions even before I know the language idioms. “Does this reduce or increase the complexity a new developer faces?” is a stack-agnostic question.
- Tech leadership philosophy: As VP Eng, I won’t be writing most of the code. My leverage is in design reviews, architecture discussions, and hiring. Ousterhout’s complexity lens is the through-line for all of those: hire people who see complexity, review designs that manage it, build culture that fights it.
- WCP/Show Notes: Both small codebases. The temptation in small codebases is to skip design work because “it’s simple.” Ousterhout says complexity accumulates through many small decisions — the time to fight it is now.
Key Concepts
| Concept | Description |
|---|---|
| Problem decomposition | The most fundamental CS problem: dividing complexity into independently-solvable pieces. |
| Complexity recognition | A learnable design skill. If you can’t see complexity, you can’t fight it. |
| Continuous redesign | Incremental development requires willingness to redesign, not just add. Each increment should improve the design. |
| Waterfall’s failure mode | Patching problems without changing overall design produces an explosion of complexity. |
| Always be thinking about complexity | Not a separate activity — the through-line of all engineering decisions. |
Cross-References
- Creative-Selection — Kocienda’s taste-driven design is the product-level analog to Ousterhout’s complexity management; both argue that judgment (not process) is the primary tool
- Use-Equals-Build — Ousterhout’s continuous redesign principle: the system improves through the act of working on it