A Philosophy of Software Design
Rate it:
Read between July 25 - August 24, 2020
8%
Flag icon
Incremental development means that software design is never done. Design happens continuously over the life of a system: developers should always be thinking about design issues. Incremental development also means continuous redesign. The initial design for a system or component is almost never the best one; experience inevitably shows better ways to do things. As a software developer, you should always be on the lookout for opportunities to improve the design of the system you are working on, and you should plan on spending some fraction of your time on design improvements.
10%
Flag icon
Complexity is more apparent to readers than writers. If you write a piece of code and it seems simple to you, but other people think it is complex, then it is complex. When you find yourself in situations like this, it’s worth probing the other developers to find out why the code seems complex to them; there are probably some interesting lessons to learn from the disconnect between your opinion and theirs. Your job as a developer is not just to create code that you can work with easily, but to create code that others can also work with easily.
11%
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 confident that the guess is correct.
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.
12%
Flag icon
Dependencies lead to change amplification and a high cognitive load. Obscurity creates unknown unknowns, and also contributes to cognitive load. If we can find design techniques that minimize dependencies and obscurity, then we can reduce the complexity of software.
13%
Flag icon
Your primary goal must be to produce a great design, which also happens to work. This is strategic programming.
17%
Flag icon
The key to designing abstractions is to understand what is important, and to look for designs that minimize the amount of information that is important.
17%
Flag icon
The best modules are those that provide powerful functionality yet have simple interfaces. I use the term deep to describe such modules.
21%
Flag icon
The best form of information hiding is when information is totally hidden within a module, so that it is irrelevant and invisible to users of the module.
21%
Flag icon
Information leakage occurs when a design decision is reflected in multiple modules.
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.
28%
Flag icon
Software systems are composed in layers, where higher layers use the facilities provided by lower layers. In a well-designed system, each layer provides a different abstraction from the layers above and below it; if you follow a single operation as it moves up and down through layers by invoking methods, the abstractions change with each method call.
33%
Flag icon
Without discipline, a context can turn into a huge grab-bag of data that creates nonobvious dependencies throughout the system.
33%
Flag icon
As a module developer, you should strive to make life as easy as possible for the users of your module, even if that means extra work for you. Another way of expressing this idea is that it is more important for a module to have a simple interface than a simple implementation.
34%
Flag icon
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?”
35%
Flag icon
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. On the other hand, 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.
36%
Flag icon
If you find the same pattern of code repeated over and over, see if you can reorganize the code to eliminate the repetition. One approach is to factor the repeated code out into a separate method and replace the repeated code snippets with calls to the method.
41%
Flag icon
You shouldn’t break up a method unless it makes the overall system simpler;
41%
Flag icon
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.
45%
Flag icon
The best way to reduce the complexity damage caused by exception handling is to reduce the number of places where exceptions have to be handled.
45%
Flag icon
The best way to eliminate exception handling complexity is to define your APIs so that there are no exceptions to handle: define errors out of existence.
46%
Flag icon
The second technique for reducing the number of places where exceptions must be handled is exception masking. With this approach, an exceptional condition is detected and handled at a low level in the system, so that higher levels of software need not be aware of the condition.
47%
Flag icon
The idea behind exception aggregation is to handle many exceptions with a single piece of code; rather than writing distinct handlers for many individual exceptions, handle them all in one place with a single handler.
Bitten Andreasen
Dette svarer til min main_exception handler
49%
Flag icon
In most applications there will be certain errors that it’s not worth trying to handle. Typically, these errors are difficult or impossible to handle and don’t occur very often. The simplest thing to do in response to these errors is to print diagnostic information and then abort the application.
50%
Flag icon
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.
52%
Flag icon
Eventually, everyone reaches a point where your first ideas are no longer good enough; if you want to get really great results, you have to consider a second possibility, or perhaps a third, no matter how smart you are. The design of large software systems falls in this category: no-one is good enough to get it right with their first try.
54%
Flag icon
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.
57%
Flag icon
Comments augment the code by providing information at a different level of detail. Some comments provide information at a lower, more detailed, level than the code; these comments add precision by clarifying the exact meaning of the code. Other comments provide information at a higher, more abstract, level than the code; these comments offer intuition, such as the reasoning behind the code, or a simpler and more abstract way of thinking about the code. Comments at the same level as the code are likely to repeat the code.
59%
Flag icon
The second way in which comments can augment code is by providing intuition. These comments are written at a higher level than the code. They omit details and help the reader to understand the overall intent and structure of the code.
60%
Flag icon
Higher-level comments are more difficult to write than lower-level comments because you must think about the code in a different way. Ask yourself: What is this code trying to do? What is the simplest thing you can say that explains everything in the code? What is the most important thing about this code?
62%
Flag icon
If the method has any side effects, these must be documented in the interface comment.
66%
Flag icon
Most methods are so short and simple that they don’t need any implementation comments: given the code and the interface comments, it’s easy to figure out how a method works.
67%
Flag icon
Loop comments are only needed for longer or more complex loops, where it may not be obvious what the loop is doing;
67%
Flag icon
In addition to describing what the code is doing, implementation comments are also useful to explain why.
71%
Flag icon
Take a bit of extra time to choose great names, which are precise, unambiguous, and intuitive.
72%
Flag icon
it’s fine to use generic names like i and j as loop iteration variables, as long as the loops only span a few lines of code.
75%
Flag icon
The best time to write comments is at the beginning of the process, as you write the code.
78%
Flag icon
Every development organization should plan to spend a small fraction of its total effort on cleanup and refactoring; this work will pay for itself over the long run.
81%
Flag icon
When working in a new file, look around to see how the existing code is structured.
82%
Flag icon
Bitten Andreasen
Der er klart undtagelser til denne regel - f.eks. Hvis den modul man skal arbejde i er lavet af en der ikke har fulgt standarden selv. I så fald kan det mange gange betale sig med en massiv refaktorering, hvor man tilpasser denne persons kode til at følge teamets kode standarder. Dette giver selvfølgelig kun mening, hvis synderen ikke længere er til stede i teamet eller endelig er blevet overbevist af standarden.
82%
Flag icon
If code is obvious, it means that someone can read the code quickly, without much thought, and their first guesses about the behavior or meaning of the code will be correct.
82%
Flag icon
“Obvious” is in the mind of the reader: it’s easier to notice that someone else’s code is nonobvious than to see problems with your own code. Thus, the best way to determine the obviousness of code is through code reviews. If someone reading your code says it’s not obvious, then it’s not obvious, no matter how clear it may seem to you. By trying to understand what made the code nonobvious, you will learn how to write better code in the future.
85%
Flag icon
Comments. Sometimes it isn’t possible to avoid code that is nonobvious. When this happens, it’s important to use comments to compensate by providing the missing information. To do this well, you must put yourself in the position of the reader and figure out what is likely to confuse them, and what information will clear up that confusion.
88%
Flag icon
One of the risks of agile development is that it can lead to tactical programming.
88%
Flag icon
With a good set of tests, developers can be more confident when refactoring because the test suite will find most bugs that are introduced. This encourages developers to make structural improvements to a system, which results in a better design.
89%
Flag icon
The problem with test-driven development is that it focuses attention on getting specific features working, rather than finding the best design. This is tactical programming pure and simple, with all of its disadvantages.
89%
Flag icon
One place where it makes sense to write the tests first is when fixing bugs.
95%
Flag icon
Design is a fascinating puzzle: how can a particular problem be solved with the simplest possible structure? It’s fun to explore different approaches, and it’s a great feeling to discover a solution that is both simple and powerful. A clean, simple, and obvious design is a beautiful thing.