Library
A Philosophy of Software Design · 9 of 11
A Philosophy of Software Design
AI Software Development HIGH

Design Principles and Red Flags

checklist code-review design-principles red-flags heuristics

Key Principle

Ousterhout distills the entire book into two checklists: 16 design principles that guide construction, and 14 red flags that diagnose problems. The principles tell you what to aim for; the red flags tell you when you have missed. Together they form a complete quick-reference rubric for code review and self-review.

Why This Matters

Design judgment is hard to apply in the moment. When writing or reviewing code, developers need concrete, actionable checks — not abstract philosophy. These checklists convert the book's deep arguments into surface-level tests that can be applied line by line and module by module. Individual red flag instances can sometimes be justified, but patterns of them across a codebase demand redesign.

The investment asymmetry makes these checklists especially valuable: "Good design doesn't really take much longer than quick-and-dirty design, once you know how." (Chapter 22) The checklists accelerate the learning curve by giving developers specific things to look for before the underlying intuition has fully developed.

Good Examples

  • The 16 Design Principles (use as a pre-commit self-check):

    1. Complexity is incremental — sweat the small stuff
    2. Working code isn't enough
    3. Make continual small investments to improve design
    4. Modules should be deep
    5. Interfaces should make common usage simple
    6. Simple interface over simple implementation
    7. General-purpose modules are deeper
    8. Separate general-purpose and special-purpose code
    9. Different layers, different abstractions
    10. Pull complexity downward
    11. Define errors out of existence
    12. Design it twice
    13. Comments describe what's not obvious from code
    14. Design for ease of reading, not writing
    15. Increments of development should be abstractions, not features
    16. Separate what matters from what doesn't; emphasize what matters
  • The 14 Red Flags (use as diagnostic heuristics during review):

    1. Shallow Module — interface not much simpler than implementation
    2. Information Leakage — same knowledge encoded in multiple places
    3. Temporal Decomposition — structure mirrors execution order, not information boundaries
    4. Overexposure — interface reveals unnecessary details
    5. Pass-Through Method — method does nothing but delegate
    6. Repetition — same code/pattern appears in multiple places
    7. Special-General Mixture — special-case logic tangled with general-purpose code
    8. Conjoined Methods — methods that cannot be understood independently
    9. Comment Repeats Code — comment restates what code already says
    10. Implementation Documentation Contaminates Interface — interface docs describe how, not what
    11. Vague Name — name conveys little useful information
    12. Hard to Pick Name — difficulty naming signals a design problem
    13. Hard to Describe — needing lengthy docs signals the abstraction boundary is wrong
    14. Nonobvious Code — reader cannot understand behavior without extensive study

Counterpoints

  • Meta-flags operate at a different level: Flags 12 ("Hard to Pick Name") and 13 ("Hard to Describe") do not diagnose surface problems — they diagnose the abstraction itself. "If you cannot name it crisply, the entity is likely doing too much or cutting across concerns." These signal that decomposition needs to change, not just the code within it.
  • Treating symptoms instead of causes: Developers may spend hours polishing names and writing elaborate documentation for an entity that should not exist in its current form. The naming difficulty is a design problem, not a writing problem.
  • The experience trap: Teams that treat design as a luxury tax defer it indefinitely and never develop the skill that would make it free. "The reward for being a good designer is that you get to spend a larger fraction of your time in the design phase, which is fun. Poor designers spend most of their time chasing bugs in complicated and brittle code." (Chapter 22)

Key Quotes

"Good design doesn't really take much longer than quick-and-dirty design, once you know how." — John Ousterhout, Chapter 22

"The reward for being a good designer is that you get to spend a larger fraction of your time in the design phase, which is fun. Poor designers spend most of their time chasing bugs in complicated and brittle code." — John Ousterhout, Chapter 22

"If someone reading your code says it's not obvious, then it's not obvious, no matter how clear it may seem to you." — John Ousterhout, Chapter 18

"Software should be designed for ease of reading, not ease of writing." — John Ousterhout, Chapter 18

Rules of Thumb

  • Use the 16 principles as a pre-commit self-check before submitting code for review
  • Use the 14 red flags as a diagnostic scan during code review — one instance may be fine, a pattern demands redesign
  • When naming is hard, stop and reconsider the abstraction boundary before iterating on names
  • When documentation is long, suspect the interface is drawn wrong rather than under-documented
  • Form design hypotheses, commit to them, build under that assumption, then reflect — this builds the "good taste" that distinguishes strong designers

Related References