A Philosophy of Software Design
A Philosophy of Software Design
By John Ousterhout
Overview
A Philosophy of Software Design by Stanford professor John Ousterhout presents a practical approach to software design focused on managing complexity. Unlike many software books that focus on specific patterns or languages, this book articulates fundamental principles for creating clean, maintainable systems that stand the test of time.
Key Ideas
Complexity is Incremental
- Small changes accumulate: Complexity builds up from hundreds of small decisions, not just major architectural choices
- The 10x rule: Spend 10-20% more time upfront to reduce complexity rather than accepting the first working solution
- Definition of complexity: Anything that makes software hard to understand or modify
Deep vs Shallow Modules
- Deep modules: Simple interface hiding complex functionality (e.g., Unix I/O with just 5 basic operations)
- Shallow modules: Complex interface with minimal functionality - creates cognitive overhead
- Best modules: Maximum functionality behind minimal interface
- Information hiding: The most important technique for achieving deep modules
Strategic vs Tactical Programming
- Tactical programming: Focus on getting features working quickly - leads to accumulated complexity
- Strategic programming: Invest time upfront in great design - produces simpler, more maintainable systems
- Working code isn’t enough: The goal is a great design that happens to work, not just code that works
Define Errors Out of Existence
- Exception proliferation: Too many exceptions make code harder to understand and use
- Define them away: Design interfaces where exceptional conditions become normal cases
- Special cases: Reduce special-case handling by making behavior more general
Comments Should Describe What Code Cannot
- Comments are design: If you can’t explain a class in a simple comment, the design is probably wrong
- Document the why: Code shows how, comments should explain why and the bigger picture
- Interface documentation: Essential for deep modules - explains abstraction without exposing implementation
Small Methods Are Overrated
- Length isn’t the enemy: Short methods can create shallow complexity and obscure system behavior
- Cognitive chunks: Group related functionality rather than splitting arbitrarily
- Each method should do one thing: But “one thing” can be substantial if it’s cohesive
Practical Takeaways for Staff Engineers
- Red flags to watch for: Shallow modules, information leakage, too many special cases, unclear comments
- Design twice: Always consider multiple options before committing to a design
- Pull complexity downward: Better for modules to have internal complexity than to export it to users
- Consistency: Creates cognitive leverage - make similar things look similar
- Different layer, different abstraction: Adjacent layers should provide different abstractions, not just pass-through
Why It Matters
This book provides concrete, actionable principles for technical leadership. It gives Staff Engineers a vocabulary and framework for advocating for quality design decisions and pushing back against tactical programming pressure. The principles apply across languages and frameworks, making it relevant for any senior engineer working on long-lived systems.