System Design Space
Knowledge graphSettings

Updated: February 15, 2026 at 9:30 PM

A Philosophy of Software Design (short summary)

hard

The philosophy of dealing with complexity from John Osterhout: deep modules, information hiding, strategic programming and red flags.

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.

A Philosophy of Software Design - original coverOriginal

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

Where to find the book

Related materials

Enable tracking in Settings

System Design Space

© 2026 Alexander Polomodov