202602021747 A Philosophy of Software Design
Preface
Writing software is the practice of problem decomposition. This book is about strategies to achieve that goal while reducing complexity.1 If a design pattern or strategy doesn't actually reduce complexity, simply don't use it, but a great deal of thought and experience has gone into this book so think carefully before passing judgement.
Chapter 1: Introduction (It's All About Complexity)
- Simpler designs allow us to build larger and more powerful systems before complexity becomes overwhelming. (pp. 1)
- The first approach to fighting complexity is to eliminate it by making code simpler and more obvious. (pp. 2)
- The second approach to fighting complexity is to encapsulate it so programmers can work on the system without being exposed to all its complexity at once. (pp. 2)
- Software developers should always be thinking about design and reducing complexity is the most important aspect of design; therefore, software engineers should always be thinking about complexity. (pp. 3)
Chapter 2: The Nature of Complexity
- The ability to recognize complexity is a crucial design skill. (pp. 5)
- It's easier to be able to tell if a design is simple than it is to create a simple design. (pp. 5)
- Definition of 202602022023 Complexity
- Isolating complexity in a place where it will never be seen is almost as good as eliminating it entirely. (pp. 6)
- Complexity is more apparent to readers than to writers. (pp. 6)
- Complexity manifests itself in three ways, each of which make it harder to carry out development tasks (pp. 7)
- Change Amplification — simple changes require making changes in many places. Change amplification can be annoying but if it's clear what code needs to be changed, the change will be successful and bug-free. (pp. 7, 9)
- Cognitive Load — a developer needs to know a great deal about the system as a whole to complete a simple task. Sometimes an approach that requires more lines of code is actually simpler because it reduces cognitive load. High cognitive load will increase the time and cost of a change, but if the information required is clear, it's a matter of spending that time doing it in order to make a successful, bug-free change. (pp. 7, 9)
- Unknown unknowns — it is not obvious what code needs to be modified or even what a developer must know in order to complete the task successfully. Of the three manifestations of complexity, unknown unknowns are the worst. There is something you need to know, but there is no way for you to find out what it is, or even whether there is an issue. You won't find out about it until bugs appear after you make the change. There is no solution to this. Reading every line of code in the system is as good as we can do, and even then external factors can also manifest here that we have no ability to foresee. (pp. 8, 9)
- One of the most important goals of the design of a system is to be obvious.
- Complexity is caused by two things: dependencies and obscurity (pp. 9)
- A dependency exists when it's not possible to understand and modify a given piece of code in isolation. Dependencies lead to change amplification and high cognitive load. (pp. 9, 11)
- Obscurity is when important information is not obvious. Obscurity creates unknown unknowns (pp. 10, 11)
- These two are often combined when dependencies are non-obvious
- If a system has a clean and obvious design, it needs less documentation
- Complexity is incremental and accumulates in small pieces everywhere. The only viable strategy for combating it is a zero-tolerance policy. (pp. 11)
Chapter 3: Working Code Isn't Enough (Strategic vs. Tactical Programming)
- A strategic approach to programming produces better designs and is actually cheaper and faster than the tactical approach in the long run
- The tactical approach to programming focuses on getting something working. It is short term and leads to one small compromise after another, focusing on speed and ending up in a catastrophically complicated system. There is an organizational failure mode when the fastest and messiest developers are valued over engineers who take their time to do things correctly for the long run.
- The strategic approach focuses on the long term health and design of the system. It knows that working code is not enough favoring producing great designs as an investment (202304112152 Intellectual investment is like compound interest, 202109251140 Play long term-games)
-
Ousterhout, J. K. (2021). A philosophy of software design (Second edition). Yaknyam Press. ↩
Links to this note
Linked from this note