A Philosophy of Software Design ================================================================================ by John Ousterhout -------------------------------------------------------------------------------- Started: December 2023 Completed: January 2024 When my former employer announced that we would start using SAFE agile, I was concerned. I didn't know what "SAFE" was, but I had been burned by my prior exposure to agile at the company. This meant an obsession with Jira tickets and a daily standup meeting where you tell a manager why your homework isn't done. I hated watching my colleagues squirm and the whole thing felt childish. I had also been newly promoted to supervisor (i.e. leading a team of engineers) and I wanted to keep an open mind. I decided to create a reading group to learn more about agile. The group was a voluntary mix of engineers and supervisors and we met every two weeks. I bought a few books off Amazon and selected the one that seemed the most promising based on the introductions. We read "The Art of Agile" by James Shore. I ended up hating SAFE, but being very intrigued by Agile. When the official training arrived, my team were prepared to fight off the consultancy drones that tried to teach us Agile via PowerPoint. Beyond the immediate purpose of learning agile, the book club was a success and other books were suggested as follow-ups. We read Robert Martin's "Clean Code" the next year. I enjoyed reading a book and considering somebody else's opinions on software design. Possibly more enjoyable were the discussions with my colleagues. A lot of the time work discussion is very narrowly focused on the problem at hand. I liked learning how other engineers responded to the same text. What did they like? What were they skeptical about? John Osterhout's "A Philosopy of Software Design" was on the list of books to read, but we did not get to it before I left the company. Instead, I read it last month on my own. The book is a good complement to Clean Code, since a lot of the author's opinions contradict the sort of things that you hear in clean code. For example, Clean Code wants a function to read a bit like an outline. Inside the body, a few well-named function calls give a high level description of what is being done. To see more detail, enter one of the functions and find another list of well-named function calls at a lower level. Keep probing and you'll eventually find a small, easy to read, encapsulated piece of logic. Each function is relatively small and all of the function calls operate at the same level of abstraction. This is an appealing idea, when function grows in length beyond a screenful and can be difficult to follow what's going on. Additionally, massive nesting (e.g. an if statement inside a loop inside another if statement) can be hard to comprehend. That said, jumping from small function to small function has its own cognitive burden. Many of the small functions turn out to be "well-named" wrappers of other functions, hardly adding anything to the mix. Getting from one piece of logic to the next involved following the thread of function calls 10 layers back up to the parent caller and then 10 layers back down to find the next bit of logic. Ousterhout is skeptical of functions that wrap other functions without any value add. I think he would urge the reader to consider if it is more straightforward to simply include the logic directly in the parent caller with an appropriate explanatory comment giving the high level gist. I'm happy to see this alternative viewpoint as the Clean Code approach can be taken to an extreme. Compared to Clean Code, APSD is much more openly in favor of comments. The book was not written in a vacuum and often cites Clean Code as a source of alternate opinions. When digging into the examples of how to comment, I got the feeling that the two authors are not so far apart. Where Ousterhout is most compelling on comments are his descriptions of how to document a function. The documentation should describe the inputs, outputs and error behaviors, while avoiding description of the implementation details. Users should be able to understand how to use the function without digging into the implementation. I don't get the sense that Robert Martin would disagree. A major focus of the book is Ousterhout's concept of narrow and deep interface. According to his idea, interfaces should do the most (depth) given the fewest inputs (narrowness). This is a concept that's hard to argue with. I'm not sure how groundbreaking it is, but narrow and deep give a nice visual. Just as we want to encapsulate member variables inside the private portion of a class, we want to encapsulate our algorithms inside of function bodies. To the greatest extent possible we want functions to expose what they do, but not how they do it. While the book does provide examples the advice is generally at a higher level. Usually the advice comes with a caveat that it should only be followed within reason. This is where I found the book to be at its weakest. All good advice is only good so long as it isn't taken too far. There were times where I would agree with a point that the author was making, but could also think of cases where I thought the advice was not applicable. Was that because it was an example of taking the advice too far or was I not open-minded enough. This is, of course, the art of software development. When do we follow the rules and when do we break the rules. As a follow-up to Clean Code, this book helps us consider some different perspectives, but I don't think it stands on its own.