📖A Philosophy of Software Design

Ousterhout, John
  • The most fundamental problem in computer science is problem decomposition (p. vii)
  • Complexity → Time-adjusted complexity definition C=pcptpC = \sum_{p} c_p t_p where cpc_p — complexity of part tpt_p — time developers spend on this part
  • Symptoms of complexity: (pp.7-8)
    • change amplification
    • cognitive load
      • the total number of things you need to keep in the head
    • unknown unknowns
      • when you have to know something but you don’t know that you have to
      • absolutely the worst—you can’t deal with it
  • Causes of complexity
    • dependency
      • changes in one part require changes in other parts
      • causes change amplification and cognitive load
    • obscurity
      • something is harder to understand than it needs to be
      • causes cognitive load and unknown unknowns
  • complexity is incremental
    • similar to performance issue with no high cost centers
    • Slight Edge?
      • same way out
  • “tactical tornadoes” are the fastest to produce features but others have to clean up after them (p.14)
  • invest 10-20% of time (p.15)
  • p.21

    An abstraction is a simplified view of an entity, which omits unimportant details.

  • Deep/shallow modules
  • A smell: pass-through methods (methods that just call to other methods, passing the same parameters)
  • p.55

    Most modules have more users that developers, so it is better for the developers to suffer than the users.

  • If class has general-purpose methods, it should provide general-purpose methods only. Specializations should be handled in different class. (pp.62,64)
  • red flag: conjoined methods. “it should be possible to understand each method independently” (without looking what other method does) (p.72)
  • exceptions
    • exceptions encourage proliferation of exceptions/error conditions, and error conditions are hard to deal with (p.78)
      • 90% of all failures is caused by incorrect error handling (p.77)
    • exceptions lead to “the more errors detected, the better” thinking. but more exceptions complicate system (p.78)
    • exceptions in interface make class shallower. a class that handles its own error conditions is deeper (re: Deep/shallow modules)
    • how to deal with exceptions:
      • push down (mask)
      • request-level handler (clean up, serve next request)
      • crash
  • comments
    • comments can “provide” abstraction. p.101
      • code is too low-level to provide useful abstractions (p.110)
    • write comments before writing code (§15)
      • it’s more fun
      • it helps design better software (long complex comments may serve as a red flag)
      • you’re most likely to write useful comments that do not repeat code if you write comments first
    • in C++, keep comments in .cpp, not .h. This way, it’s more likely the comments will be updated when code changes. (p.137)
    • if commit message is important, duplicate it in code comment (p.138)
  • p.128

    The greater the distance between a name’s declaration and its uses, the longer the name should be.


  • TDD is tactical programming (p.155)
    • do I agree?
  • “incremental” performance issues (“death by a thousand cuts”) p.159