I picked up a copy of A Philosophy of Software Design By John Ousterhout on recommendation from a blog I follow (the author of which picked up the book on recommendation from elsewhere). Only a few chapters in I’m already decently impressed with it. I’d like to do a bit of a review of the book, chapter-by-chapter because some of it lines up quite neatly with things I’ve written about in the past and some of it comes across at odds with my experience. The content really starts in Chapter 2, so that’s where I’m going to start my review.
Chapter 2: The Nature of Complexity
Right off the bat he starts out with this definition of complexity, which is quite an interesting divergence from the way the term is commonly used:
Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.
It’s not what the program does that’s complicated, it’s how the software is organized and structured that makes it complicated. Not complexity from the point of view of the computer, but complexity from the point of view of the programmer. And, further, it’s from the point of view of the unfamiliar programmer, one who is trying to understand and modify the system without deep prior knowledge of it. This is actually kind of deep and revolutionary. My code isn’t simple when I say it’s simple, but instead only when the next coder to work on it confirms it so.
Next he goes on to say something which I’ve been saying for years, though not quite so eloquently:
If a system has a few parts that are very complicated, but those parts almost never need to be touched, then they don’t have much impact on the overall complexity of the system.
Call it something like an “80/20” rule or whatever, but this is an important idea and as we’ll see the same kind of idea reoccurs over and over again.
A question that has come up frequently, such as when in a job interview or when talking to a junior developer is, “what is the most important programming concept?” to which I tend to reply “encapsulation”. Encapsulation is all about hiding details and complexity behind an interface which is much easier to understand and consume. This is the reason why I was attracted to the Parrot project so many years ago, and why I’ve focused my career on back-end concerns (services, infrastructure and shared libraries): Because hiding complexity in a way that most people will never have to deal with accelerates the entire team. Instead of all the developers mucking about with a tricky bit of code, they can instead consume a nice, simple interface which hides all the tricks and traps safely away.
Look at Acquaintance for example, which aims to wrap up some of the complexities of multi-threaded programming and provide a much easier, higher-level interface to them. Look also at CastIron which aims to help programmers avoid some common traps and problems of data access by exposing simple interfaces and patterns. I believe this stuff down to the very core and I hope this blog, if it serves any purpose at all, helps to share those ideas with others.
John lists two causes of complexity as “dependencies” and “obscurities”, and then talks about how these two causes combine to create three symptoms: “change amplification” (a small need leads to large work), “cognitive load” (more knowledge and thinking required to perform tasks) and “unknown unknowns” (what needs to be changed, and to what, is not obvious).
He then goes on to talk about something I’ve posted about just recently (in fact, the very last post I published before purchasing the book): complexity is incremental. Developers build huge complexity one step at a time by separating the idea of “doneness” from the idea of “rightness”, and allowing code to be published which satisfies the former but not the later. So much of what is “bad code” was built over in small bits over the years because the discipline and quality controls to prevent them are absent. This absence may be intentional (“I’ll fix it later”) or unintentional (inexperienced or inattentive developers).
I agree with everything he’s written in this chapter 100%. I’ve said some of it myself over the years, and I definitely appreciate some of the standardized vocabulary he brings to the discussion.
Up Next
I don’t know if I’m going to review every single chapter, or how in-depth I will go when I do, but I figure this is a good exercise to both force me to finish reading the whole book and to make sure I understand it all well enough to share the ideas with others. Next time I’ll be looking at Chapter 3.