A Philosophy of Software Design Part 2 - Working Code Is Not
Enough A Philosophy of Software Design treats software design
less as architectural theater and more as the daily work of
managing complexity.
This part covers Chapter 3 Working Code Isn't Enough and Chapter
4 Modules Should Be Deep.
It uses only short key phrases from the source and turns the
reading into summary, interpretation, and application.
The guiding question is: Where does quickly working code diverge
from code that remains understandable tomorrow?
How to use this note This is part 2 of a ten-part reading of A
Philosophy of Software Design.
The scope is Chapter 3 Working Code Isn't Enough and Chapter 4
Modules Should Be Deep.
The operating principle remains: book notes are storage; insight
cards are currency.
L0 · Entry Core sentence: Strategic programming treats future
change cost as part of the design problem, not as a later
cleanup task.
Why read this: As AI tools and automation make code faster to
produce, I want sharper standards for code that remains
understandable and changeable.
Initial hypothesis: In practice, working behavior can dominate
design judgment.
This range lowers working behavior to a minimum condition and
treats deep modules as units of long-term investment.
Author context: John Ousterhout is a computer scientist known
for work in operating systems, distributed systems, Tcl/Tk, and
software design education at Stanford.
Scope: Chapter 3 Working Code Isn't Enough and Chapter 4 Modules
Should Be Deep L1 · Captures Short phrase · design "tactical
programming" This names the habit of solving only the immediate
problem.
Fast local fixes can slowly make the structure slower to change.
Short phrase · design "strategic programming" This treats future
change cost as part of today's work.
The habit needed here is small recurring design investment.
Short phrase · design "deep modules" This describes a module
with a simple interface and substantial hidden capability.
The useful measure is not class count but functionality per
interface burden.
Copyright boundary This public note does not reproduce long
source passages.
It uses chapter-level concepts and short phrases as anchors,
then provides transformative summary and commentary.
L2 · Map Range Summary Main claim --- ------ ---------
------------ 1 Tactical programming Prioritizes getting behavior
to work while delaying structural cost Completion may be fast
while future change becomes slow 2 Strategic programming Adds
small design investments consistently Design is a daily choice
rather than a later rewrite 3 Module interface Reduces the
surface users must understand A simpler interface lowers memory
burden 4 Deep modules Provide large functionality behind a small
interface Good abstractions absorb internal complexity 5 Shallow
modules Split code without reducing user burden Division alone
does not guarantee design quality Argument in one paragraph:
Strategic programming treats future change cost as part of the
design problem, not as a later cleanup task.
In practice, working behavior can dominate design judgment.
This range lowers working behavior to a minimum condition and
treats deep modules as units of long-term investment.
In practice, this moves review questions from "does it work?"
toward "what must the next reader know in order to change it
safely?" Design is not a separate ceremony; it is embedded in
names, boundaries, exceptions, comments, layers, and performance
choices.
L3 · Insight Cards A Philosophy of Software Design - I2.1
Working behavior is the start of design judgment, not its finish
line A Philosophy of Software Design - I2.2 A deep module is
evaluated by the burden it removes from users A Philosophy of
Software Design - I2.3 Strategic programming is repeated small
investment, not a heroic rewrite L4 · Production Board Outputs
Blog draft: Part 2 as "Working Code Is Not Enough" Code review
question: Where does quickly working code diverge from code that
remains understandable tomorrow?
Insight card: Working behavior is the start of design judgment,
not its finish line L5 · Review Connections: This stands in
tension with YAGNI: avoid speculative generality, but also avoid
tactical blindness to future change.
Open questions: Where does this part's red flag appear most
clearly in my current codebase?
What check would an AI coding agent need in order to apply this
principle reliably?
Final takeaway: A deep module is not one that hides for its own
sake; it lets users know less while doing more.