📖A philosophy of software design
- authors
- Ousterhout, John
- year
- 2018
- The most fundamental problem in computer science is problem decomposition (p. vii)
- Complexity → Time-adjusted complexity definition where — complexity of part — time developers spend on this part
- “Isolating complexity in a place where it will never be seen is almost as good as eliminating the complexity entirely.” (p.6) → Time-adjusted complexity justifies pushing the complexity downward
- 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
- dependency
- 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
- exceptions encourage proliferation of exceptions/error conditions, and error conditions are hard to deal with (p.78)
- 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)
- comments can “provide” abstraction. p.101
p.128
The greater the distance between a name’s declaration and its uses, the longer the name should be.
—Gerrand
- TDD is tactical programming (p.155)
- do I agree?
- “incremental” performance issues (“death by a thousand cuts”) p.159