A Philosophy of Software Design
A very good little book (~170 pages) about software design, very much in the style of Clean Code and The Pragmatic Programmer.
Here is the site for the course that the author, John Ousterhout teaches at Standford: CS190 lectures.
I’ve taken some notes to internalise the contents of the book better.
Key takeaways
It has a chapter about complexity, where the author summarises the key factors in the difficulty of programming.
The overall complexity of a system (C) is determined by the complexity of each part () weighted by the fraction of time developers spend working on that part (). Isolating complexity in a place where it will never be seen is almost as good as eliminating the complexity entirely.
It talks about change amplification, cognitive load and unkown unknowns.
It also writes about tactical versus strategic programming - an almost daily battle in the life of a software engineer. Do you want to fix it quickly, or do you want to fix it well? The author strongly encourages strategic programming and emphasises that it’s an investment that will pay off pretty soon.
It writes about modules and interfaces - the author argues that modules should be deep: a shallow module, only consisting of a minor functionality and having a broad interface, is a red flag. A deep module is the key for appropriate abstraction: a shallow module doesn’t simplify much. A deep module which hides complexity and which exposes a simple interfacce is ideal.
Information hiding is topic similar to the above: information leakage and “temporal decomposition” are a red flags to avoid.
It talks about how exception handling add complexity to the code, and gives suggestions about how to avoid it: either define them out of existence (default to some behaviour if an exception happens), mask them, or aggregate them so that they can be handled in one central place.
It also has a pretty long section about comments. This might sound tedious, as we have all heard about the importance of code documentation ad nauseum. However, the seemingly trivial task of writing comments can still be relatively hard to do well. Rather than repeating the author, I suggest reading this and reviewing the slides for the code examples. The key takeaways for me were to pay attention to the abstraction level of the comments (e.g. don’t just repeat the code!), make sure I comment at the right place, and that I don’t rely solely on version control commit messages for important information (if an idea expressed in a Git commit is important to understand the code, then it should be a comment as well). An interesting idea was to write the comments first (comment-driven development?) - I understand this can help formulate thoughts on the design of a class/module.
Naming is hard, and this book has an interesting example of a real-life bug which was introduced into a program due to bad naming.
About inheritance:
Class hierarchies that use implementation inheritance exstensively tend to have high complexity.
This is something that has bitten me before: I sometimes feel like inheritance, above a certain level, is just not worth it if you have to have complete knowledge about the whole inheritance tree to implement a subclass.
Interestingly, the book has a short section about Agile development: it argues that while it has many benefits, it can encourage tactical programming: it tends to focus on features and not abstractions and favors small iterations, which can lead to increased complexity.