Source
Code of Architecture — Recap
Review of the book in four issues of the CoA book club with the participation of T-Bank architects.
A Philosophy of Software Design
Authors: John K. Ousterhout
Publisher: Yaknyam Press
Length: 190 pages
The philosophy of dealing with complexity from John Osterhout: deep modules, information hiding, strategic programming and red flags.
OriginalAbout the book
"A Philosophy of Software Design" is one of the most cited modern books on software design. John Osterhout, Stanford professor and author of Tcl/Tk, presents a philosophy for dealing with complexity through proper modularization, information hiding, and strategic thinking.
The book originated from a CS 190 course at Stanford, where students designed and reviewed real-life software systems. It is a collection of practical principles derived from the analysis of thousands of student projects.
Detailed review
Review Part I
Detailed analysis of the first chapters: complexity, tactical vs strategic programming.
Part 1: The Nature of Complexity (Chapters 1-6)
Nature of complexity
Symptoms of difficulty:
Reasons for difficulty:
Connections between modules
Unclear code intent
Formula:
Complexity = Σ (cₚ × tₚ)
where c is the complexity of the component, t is the time it takes to work with it
Tactical vs Strategic programming
Tactical ❌
- "The main thing is that it works"
- Quick patches and hacks
- Accumulation of technical debt
- Local optimization
Strategic ✅
- "Good design = working code"
- Invest 10-20% of time in design
- Proactively Eliminate Complexity
- Global optimization
Detailed review
Review Part II
Deep dive into chapters 7-11: levels of abstraction, moving complexity, exceptions.
Part 2: Modules and Abstractions (Chapters 7-11)
Deep vs Shallow modules
Deep Module ✅
Small interface, many possibilities
Shallow Module ❌
Large interface, few features
Examples of deep modules: Unix file I/O (5 system calls), garbage collector (null interface). Shallow: Java I/O classes, many exceptions.
Information Hiding
Each module should encapsulate design knowledge while exposing a minimal interface to the outside.
❌ Information Leakage - implementation details are visible from the outside
❌ Temporal Decomposition - partitioning by execution time
Different Layer, Different Abstraction
Each level of the system must have its own abstractions. Pass-through methods are a sign of problems.
✅ Pull Complexity Downward
Move complexity down to the implementation, not the interface
Define Errors Out of Existence
Instead of throwing exceptions, design the API so that error states are not possible. Example: unset() in Tcl does not throw an exception for a non-existent variable - this makes the code simpler.
Part 3: Comments and Documentation (Chapters 12-16)
Why comments are important
Comments do not duplicate code - they describe abstractions, which the code cannot express.
• Interface comments - module contract
• Implementation comments - “what” and “why”
• Cross-module comments — connections between modules
Comments First
Write comments before code. This helps:
- Think through the design before implementation
- Define the right abstractions
- Find design problems early
- Stay motivated to write documentation
🎯 Rules for good naming
Accuracy
The name must accurately describe the entity
Consistency
Same patterns for similar things
Avoid unnecessary words
fileCount, not numberOfFiles
Part 4: Consistency and Obviousness (Chapters 17-21)
Consistency
- •Naming conventions - uniform names
- •Coding style - formatting, structure
- •Design patterns - typical solutions
- •Invariants - guaranteed properties
Code obviousness
Code is obvious if the reader can quickly understand it without deep analysis.
✅ Good names and comments
✅ Consistency
❌ Event-driven programming (difficult to track)
❌ Generic containers (semantics are lost)
🚩 Red Flags - signs of bad design
Code of Architecture video series
The book was reviewed in four editions of the Code of Architecture book club with the participation of T-Bank architects:
Key Ideas
Complexity is incremental
Difficulty accumulates gradually, drop by drop
Working code isn't enough
We need good design, not just working code
Deep modules
Lots of functionality behind a simple interface
Information hiding
Encapsulating implementation knowledge
Pull complexity down
Complexity in implementation, simplicity in interface
Define errors out
Design APIs without error states
Comments as design tool
Write comments before the code
Consistency matters
Consistency reduces cognitive load
