📖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