Jumping on the recent trend, I picked up a copy ofA Philosophy of Software Design基于John SuilthoutCindy’s recommendation。在160页很简洁,I skimmed through it over the last few days, writing up some notes along the way.
Michael Krause也很友好，以指出John Outshout的伟大的谈话涵盖相同的内容。
They particularly recommend the book as a useful tool to use during code reviews, providing a list of red flags along the lines of information leakage, shallow module, vague names, implementation documentation contaminates interfaces, conjoined methods, and general-specific mixture. (A full list of red-flags at bottom.)
Now, a list of snippets I found particularly interesting.
Complexity is anything that makes software hard to understand or to modify.
An old refrain, but a good one. It’s surprising how resistant folks can be to this feedback, including myself.
The book picks three symptoms of complexity: change amplification, cognitive load, unknown unknowns. Change amplification is when making a local change requires many changes elsewhere, and is best prevented when you
It then moves on to a definition of complexity:
Complexity is caused by obscurity and dependencies.
And definitions of complexity’s subcomponents:
Dependency is when code can't be understood in isolation. Obscurity is when important information is not obvious. This can often be due to lack of documentation.
Why is complexity so challenging to manage? It’s because
Complexity is incremental, the result of thousands of choices. Which makes it hard to prevent and even harder to fix.
打击复杂性蔓延，他建议区分strategic programming和tactical programming。
Tactical mindset is focused on getting something working, but makes it nearly impossible to produce good system design.
Interestingly, the proposal is not that you should do major upfront design phases, but instead that you should be doing lots of incremental design improvement work over time. This is slightly different than just “doing Agile”, because Agile is too focused with features, whereas
The increments of development should be abstractions, not features. ... Ideally, when you have finished with each change, the system will have the structure it would have had if you had designed it from the start with that change in mind.
Many folks would argue against this focus on abstractions, arguing that it’s not obviously useful, in terms of the你不会需要它，但他争辩说
That section is specifically a refutation of the startup mentality of launching quickly and fixing things later as a false dichotomy.
The most important way to manage complexity is by shifting it from interfaces and into implementation:
You have to be careful when designing modules thought, because
Done well this technique is known as information hding:
Each module should encapsulate a few pieces of knowledge, which represent design decisions. This knowledge should not appear in its interfaces, and hence are restricted to its implementation. Simpler interfaces correlate with better information hiding.
The opposite of information hiding is information leakage:
When a design decision is used across multiple modules, coupling them together.
The solution is to “define errors out of existance,” which is designing interfaces such that errors are not possible. The example of
Design it twice, taking radically different approaches.
There is an interesting aside on this topic, mentioning how very smart people often have been drilled by their early experiences that their first inclination is the right one because it’s good enough to get a good grade, and consequently they struggle to take advantage of this technique.
Most large software design problems are fundamentally different than school work in that they are not inherently designed to be solvable, and consequently they benefit from multiple different approaches.
Finally, a closing benediction to the strategic mindset:
If you're not making the design better, you are probably making it worse.
Altogether, this was a really good read, and I highly recommend it!
- Shallow module
- Information leakage
- Temporal decomposition
- Repetition of the same fragments of code
- General-specific mixture
- Conjoined methods
- Hard to describe
- Vague names
- Implementation documentation contaminates interfaces