These are my ongoing reading notes for A Philosophy of Software Design by John Ousterhout. I’m still working through the book, so this post will be updated as I go.

1. The Root Causes of Complexity

Complexity in software systems is primarily driven by two interrelated forces:

  • Dependencies: When a given piece of code cannot be understood or modified in isolation.
  • Obscurity: When important information about the system is not obvious or easily discoverable to the developer.

2. Tactical vs. Strategic Programming

Simply writing “working code” isn’t enough to sustain a scalable system.

  • Tactical Programming: A short-sighted approach focused entirely on getting a feature to work right now. While it might feel 10–20% faster in the very beginning, accumulating technical debt guarantees that development will take significantly longer in the long run.
  • Strategic Programming: An approach focused on producing a great design that also happens to work.
  • The Investment Rule: Dedicate 10–20% of your development time to pure design investments to maintain a healthy, extensible codebase.

3. Module Design and Depth

  • Defining a Module: Any unit of code that consists of both an interface and an implementation.
  • Deep Modules: The best modules are “deep.” They hide tremendous complexity, providing powerful internal functionality behind extremely simple, narrow interfaces.
  • False Abstractions: An abstraction fails when it is “false”—meaning it omits important details the caller actually needs to know, failing to truly reduce cognitive load.
  • Interface Sizing: While interfaces are fundamentally good, having more interfaces or larger interfaces is not necessarily better. The goal is simplicity and encapsulation, not surface area.

To be continued as I read further…