More on this book
Community
Kindle Notes & Highlights
special cases should be eliminated wherever possible. The best way to do this is by designing the normal case in a way that automatically handles the edge conditions without any extra code.
Red Flag: Pass-Through Method A pass-through method is one that does nothing except pass its arguments to another method, usually with the same API as the pass-through method. This typically indicates that there is not a clean division of responsibility between the classes.
the interface to a piece of functionality should be in the same class that implements the functionality.
“Exactly which features and abstractions is each of these classes responsible for?”
it is more important for a module to have a simple interface than a simple implementation.
you should avoid configuration parameters as much as possible. Before exporting a configuration parameter, ask yourself: “will users (or higher-level modules) be able to determine a better value than we can determine here?”
Ideally, each module should solve a problem completely; configuration parameters result in an incomplete solution, which adds to system complexity.
the smaller the components, the simpler each individual component is likely to be. However, the act of subdividing creates additional complexity that was not present before subdivision:
If the components are truly independent, then separation is good: it allows the developer to focus on a single component at a time, without being distracted by the other components.
if there are dependencies between the components, then separation is bad: developers will end up flipping back and forth between the components. Even worse, they may not be aware of the dependencies, which can lead to bugs.
Bring together if information is shared
Bring together if it will simplify the interface
Bring together to eliminate duplication
Separate general-purpose and special-purpose code
Red Flag: Repetition If the same piece of code (or code that is almost the same) appears over and over again, that’s a red flag that you haven’t found the right abstractions.
Red Flag: Special-General Mixture This red flag occurs when a general-purpose mechanism also contains code specialized for a particular use of that mechanism. This makes the mechanism more complicated and creates information leakage between the mechanism and the particular use case: future modifications to the use case are likely to require changes to the underlying mechanism as well.
In general, developers tend to break up methods too much. Splitting up a method introduces additional interfaces, which add to complexity. It also separates the pieces of the original method, which makes the code harder to read if the pieces are actually related.
You shouldn’t break up a method unless it makes the overall system simpler;
Methods containing hundreds of lines of code are fine if they have a simple signature and are easy to read. These methods are deep (lots of functionality, simple interface), which is good.
Each method should do one thing and do it completely. The method should have a simple interface, so that users don’t need to have much information in their heads in order to use it correctly. The method should be deep: its interface should be much simpler than its implementation. If a method has all of these properties, then it probably doesn’t matter whether it is long or not.
(a) someone reading the child method doesn’t need to know anything about the parent method and (b) someone reading the parent method doesn’t need to understand the implementation of the child method.
Red Flag: Conjoined Methods It should be possible to understand each method independently. If you can’t understand the implementation of one method without also understanding the implementation of another, that’s a red flag. This red flag can occur in other contexts as well: if two pieces of code are physically separated, but each can only be understood by looking at the other, that is a red flag.
classes with lots of exceptions have complex interfaces, and they are shallower than classes with fewer exceptions.
reduce the number of places where exceptions have to be handled.
I should have changed the definition of unset slightly: rather than deleting a variable, unset should ensure that a variable no longer exists.
With exceptions, as with many other areas in software design, you must determine what is important and what is not important. Things that are not important should be hidden, and the more of them the better. But when something is important, it must be exposed
You’ll end up with a much better result if you consider multiple options for each major design decision: design it twice.
Try to pick approaches that are radically different from each other; you’ll learn more that way.
The most important consideration for an interface is ease of use for higher level software.
Sometimes none of the alternatives is particularly attractive; when this happens, see if you can come up with additional schemes. Use the problems you identified with the original alternatives to drive the new design(s).
The design-it-twice principle can be applied at many levels in a system. For a module, you can use this approach first to pick the interface, as described above. Then you can apply it again when you are designing the implementation:
The design of large software systems falls in this category: no-one is good enough to get it right with their first try.
the process of writing comments, if done correctly, will actually improve a system’s design.
a good software design loses much of its value if it is poorly documented.
If users must read the code of a method in order to use it, then there is no abstraction: all of the complexity of the method is exposed.
The overall idea behind comments is to capture information that was in the mind of the designer but couldn’t be represented in the code.
comments should describe things that aren’t obvious from the code.
Developers should be able to understand the abstraction provided by a module without reading any code other than its externally visible declarations.
Every class should have an interface comment, every class variable should have a comment, and every method should have an interface comment.
could someone who has never seen the code write the comment just by looking at the code next to the comment? If the answer is yes, as in the examples above, then the comment doesn’t make the code any easier to understand.
Red Flag: Comment Repeats Code If the information in a comment is already obvious from the code next to the comment, then the comment isn’t helpful. One example of this is when the comment uses the same words that make up the name of the thing it is describing.
Comments augment the code by providing information at a different level of detail.
When documenting a variable, think nouns, not verbs. In other words, focus on what the variable represents, not how it is manipulated.
If you want code that presents good abstractions, you must document those abstractions with comments.
If interface comments must also describe the implementation, then the class or method is shallow.
The developer should not need to read the body of the method in order to invoke it, and the interface comment provides no information about how the method is implemented, such as how it scans its internal data structures to find the desired data.

