A Philosophy of Software Design
Rate it:
Open Preview
Read between February 24 - March 4, 2025
8%
Flag icon
red flags: signs that a piece of code is probably more complicated than it needs to be.
8%
Flag icon
Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.
9%
Flag icon
If a software system is hard to understand and modify, then it is complicated; if it is easy to understand and modify, then it is simple.
9%
Flag icon
Change amplification: The first symptom of complexity is that a seemingly simple change requires code modifications in many different places.
9%
Flag icon
Cognitive load: The second symptom of complexity is cognitive load, which refers to how much a developer needs to know in order to complete a task.
Kai Chevannes
How much information you need to store in your mental RAM when making a change.
10%
Flag icon
Unknown unknowns: The third symptom of complexity is that it is not obvious which pieces of code must be modified to complete a task, or what information a developer must have to carry out the task successfully.
10%
Flag icon
One of the most important goals of good design is for a system to be obvious.
10%
Flag icon
In an obvious system, a developer can quickly understand how the existing code works and what is required to make a change.
10%
Flag icon
An obvious system is one where a developer can make a quick guess about what to do, without thinking very hard, and yet be c...
This highlight has been truncated due to consecutive passage length restrictions.
10%
Flag icon
Complexity is caused by two things: dependencies and obscurity.
10%
Flag icon
For the purposes of this book, a dependency exists when a given piece of code cannot be understood and modified in isolation; the code relates in some way to other code, and the other code must be considered and/or modified if the given code is changed.
Kai Chevannes
Changes dependent on other changes.
11%
Flag icon
one of the goals of software design is to reduce the number of dependencies and to make the dependencies that remain as simple and obvious as possible.
11%
Flag icon
The best way to reduce obscurity is by simplifying the system design.
11%
Flag icon
As complexity increases, it leads to change amplification, a high cognitive load, and unknown unknowns.
12%
Flag icon
The first step towards becoming a good software designer is to realize that working code isn’t enough. It’s not acceptable to introduce unnecessary complexities in order to finish your current task faster. The most important thing is the long-term structure of the system.
12%
Flag icon
Strategic programming requires an investment mindset. Rather than taking the fastest path to finish your current project, you must invest time to improve the design of the system. These investments will slow you down a bit in the short term, but they will speed you up in the long term,
13%
Flag icon
I suggest spending about 10–20% of your total development time on investments.
15%
Flag icon
The goal of modular design is to minimize the dependencies between modules.
15%
Flag icon
In order to identify and manage dependencies, we think of each module in two parts: an interface and an implementation.
15%
Flag icon
The best modules are those whose interfaces are much simpler than their implementations.
16%
Flag icon
An abstraction is a simplified view of an entity, which omits unimportant details.
16%
Flag icon
An abstraction that omits important details is a false abstraction: it might appear simple, but in reality it isn’t.
16%
Flag icon
The best modules are deep: they allow a lot of functionality to be accessed through a simple interface.
17%
Flag icon
Module depth is a way of thinking about cost versus benefit. The benefit provided by a module is its functionality. The cost of a module (in terms of system complexity) is its interface.
Kai Chevannes
If a module is shallow, it might be better to change the abstraction being used.
18%
Flag icon
It is no simpler to think about the interface than to think about the full implementation.
18%
Flag icon
Red Flag: Shallow Module
18%
Flag icon
Small modules tend to be shallow.
18%
Flag icon
Classitis may result in classes that are individually simple, but it increases the complexity of the overall system.
18%
Flag icon
Small classes don’t contribute much functionality, so there have to be a lot of them, each with its own interface. These interfaces accumulate to create tremendous complexity at the system level. Small classes also result in a verbose programming style, due to the boilerplate required for each class.
19%
Flag icon
interfaces should be designed to make the common case as simple as possible
Kai Chevannes
Sane defaults, don't require opting out of deleting the private cloud after 1 year.
19%
Flag icon
The most important issue in designing classes and other modules is to make them deep, so that they have simple interfaces for the common use cases, yet still provide significant functionality. This maximizes the amount of complexity that is concealed.
20%
Flag icon
Information leakage occurs when a design decision is reflected in multiple modules. This creates a dependency between the modules: any change to that design decision will require changes to all of the involved modules.
Kai Chevannes
Classes shouldn't be tightly coupled.
20%
Flag icon
“How can I reorganize these classes so that this particular piece of knowledge only affects a single class?”
20%
Flag icon
If the affected classes are relatively small and closely tied to the leaked information, it may make sense to merge them into a single class. Another possible approach is to pull the information out of all of the affected classes and create a new class that encapsulates just that information. However, this approach will be effective only if you can find a simple interface that abstracts away from the details;
21%
Flag icon
In temporal decomposition, the structure of a system corresponds to the time order in which operations will occur.
21%
Flag icon
  Red Flag: Information Leakage   Information leakage occurs when the same knowledge is used in multiple places, such as two different classes that both understand the format of a particular type of file.
21%
Flag icon
When designing modules, focus on the knowledge that’s needed to perform each task, not the order in which tasks occur.
21%
Flag icon
  Red Flag: Temporal Decomposition   In temporal decomposition, execution order is reflected in the code structure: operations that happen at different times are in different methods or classes. If the same knowledge is used at different points in execution, it gets encoded in multiple places, resulting in information leakage.
22%
Flag icon
information hiding can often be improved by making a class slightly larger.
Kai Chevannes
Think about the API that would be the simplest for another developer to use.
22%
Flag icon
rather than having separate methods for each of three steps of a computation, have a single method that performs the entire computation.
23%
Flag icon
Whenever possible, classes should “do the right thing” without being explicitly asked.
24%
Flag icon
  Red Flag: Overexposure   If the API for a commonly used feature forces users to learn about other features that are rarely used, this increases the cognitive load on users who don’t need the rarely used features.
24%
Flag icon
it’s important to recognize which information is needed outside a module and make sure it is exposed.
Kai Chevannes
"What is the smallest possible API surface area for this module?"
24%
Flag icon
(general-purpose APIs result in more information hiding).
24%
Flag icon
When writing detailed code, one of the most effective ways to simplify the code is by eliminating special cases, so that the common-case code handles the edge cases as well.
25%
Flag icon
In my experience, the sweet spot is to implement new modules in a somewhat general-purpose fashion. The phrase “somewhat general-purpose” means that the module’s functionality should reflect your current needs, but its interface should not.
26%
Flag icon
One of the goals in class design is to allow each class to be developed independently, but the specialized approach tied the user interface and text classes together.
27%
Flag icon
What is the simplest interface that will cover all my current needs? If you reduce the number of methods in an API without reducing its overall capabilities, then you are probably creating more general-purpose methods.
27%
Flag icon
In how many situations will this method be used? If a method is designed for one particular use, such as the backspace method, that is a red flag that it may be too special-purpose.
27%
Flag icon
Is this API easy to use for my current needs? This question can help you to determine when you have gone too far in making an API simple and general-purpose.
« Prev 1 3