System Design Space
Knowledge graphSettings

Updated: March 24, 2026 at 12:33 PM

A Philosophy of Software Design (short summary)

hard

Bad design rarely arrives as one dramatic disaster. It usually feels like constant fatigue: it is hard to see where code should change, interfaces feel heavier than they should, and a small task pulls in too much context. This chapter is about fighting that kind of complexity before it becomes normal.

The strongest practical lens here is complexity management itself: deep modules, information hiding, red flags, and reduced cognitive load. That helps teams shape interfaces and boundaries so the system stays easier to understand and evolve.

The chapter is especially useful for discussing internal design quality. It gives you clear language for module boundaries, interface shape, and the difference between hiding complexity and merely spreading it across the codebase.

Practical value of this chapter

Complexity control

Keeps design focused on reducing accidental complexity and improving system clarity.

Deep modules

Helps design interfaces that hide internal complexity and reduce cognitive load.

Design debt

Trains early detection of design degradation signals and timely structural corrections.

Interview articulation

Provides strong language for discussing module boundaries and API contract quality.

Source

Code of Architecture — Recap

Review of the book in four issues of the CoA book club with the participation of T-Bank architects.

Read the article

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.

Original

About 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.

Read review

Part 1: The Nature of Complexity (Chapters 1-6)

Nature of complexity

Symptoms of difficulty:

🔄Change Amplification
🧠Cognitive Load
Unknown Unknowns

Reasons for difficulty:

Dependencies

Connections between modules

Obscurity

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.

Read review

Part 2: Modules and Abstractions (Chapters 7-11)

Deep vs Shallow modules

Deep Module ✅

interface
Lots of functionality

Small interface, many possibilities

Shallow Module ❌

big interface
Few functions

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

Shallow Module — The interface is more complex than the implementation
Information Leakage — Implementation details visible from the outside
Temporal Decomposition — Partitioning by time, not by function
Overexposure — Redundant public methods
Pass-Through Method — The method simply passes the call on
Repetition — Duplicate code in different places
Special-General Mixture — Mixing public and private code
Conjoined Methods — The methods are only clear together
Comment Repeats Code — The comment duplicates the code
Implementation in Interface — Implementation details in the documentation
Vague Name — Inaccurate or too general name
Hard to Pick Name — It's hard to come up with a good name
Hard to Describe — Difficult to describe purpose
Nonobvious Code — The code requires deep analysis

Code of Architecture video series

Key Ideas

1.

Complexity is incremental

Difficulty accumulates gradually, drop by drop

2.

Working code isn't enough

We need good design, not just working code

3.

Deep modules

Lots of functionality behind a simple interface

4.

Information hiding

Encapsulating implementation knowledge

5.

Pull complexity down

Complexity in implementation, simplicity in interface

6.

Define errors out

Design APIs without error states

7.

Comments as design tool

Write comments before the code

8.

Consistency matters

Consistency reduces cognitive load

Related chapters

Where to find the book

Enable tracking in Settings