Clean Architecture: A Craftsman's Guide to Software Structure and Design
Rate it:
Open Preview
4%
Flag icon
If you think good architecture is expensive, try bad architecture. —Brian Foote and Joseph Yoder
5%
Flag icon
getting something to work—once—just isn’t that hard.
6%
Flag icon
The goal of software architecture is to minimize the human resources required to build and maintain the required system.
6%
Flag icon
The measure of design quality is simply the measure of the effort required to meet the needs of the customer. If that effort is low, and stays low throughout the lifetime of the system, the design is good. If that effort grows with each new release, the design is bad. It’s as simple as that.
6%
Flag icon
When systems are thrown together in a hurry, when the sheer number of programmers is the sole driver of output, and when little or no thought is given to the cleanliness of the code or the structure of the design, then you can bank on riding this curve to its ugly end.
7%
Flag icon
“Slow and steady wins the race.” • “The race is not to the swift, nor the battle to the strong.” • “The more haste, the less speed.”
7%
Flag icon
developers buy into a familiar lie: “We can clean it up later; we just have to get to market first!” Of course, things never do get cleaned up later, because market pressures never abate.
7%
Flag icon
The bigger lie that developers buy into is the notion that writing messy code makes them go fast in the short term, and just slows them down in the long term. Developers who accept this lie exhibit the hare’s overconfidence in their ability to switch modes from making messes to cleaning up messes sometime in the future, but they also make a simple error of fact. The fact is that making messes is always slower than staying clean, no matter which time scale you are using.
7%
Flag icon
The only way to go fast, is to go well.
8%
Flag icon
Every software system provides two different values to the stakeholders: behavior and structure. Software developers are responsible for ensuring that both those values remain high.
8%
Flag icon
Software was invented to be “soft.” It was intended to be a way to easily change the behavior of machines. If we’d wanted the behavior of machines to be hard to change, we would have called it hardware.
8%
Flag icon
If you give me a program that works perfectly but is impossible to change, then it won’t work when the requirements change, and I won’t be able to make it work. Therefore the program will become useless. • If you give me a program that does not work but is easy to change, then I can make it work, and keep it working as requirements change. Therefore the program will remain continually useful.
10%
Flag icon
Notice how well those three align with the three big concerns of architecture: function, separation of components, and data management.
11%
Flag icon
Nowadays we are all structured programmers, though not necessarily by choice. It’s just that our languages don’t give us the option to use undisciplined direct transfer of control.
11%
Flag icon
Dijkstra once said, “Testing shows the presence, not the absence, of bugs.” In other words, a program can be proven incorrect by a test, but it cannot be proven correct. All that tests can do, after sufficient testing effort, is allow us to deem a program to be correct enough for our purposes.
15%
Flag icon
OO is the ability, through the use of polymorphism, to gain absolute control over every source code dependency in the system. It allows the architect to create a plugin architecture, in which modules that contain high-level policies are independent of modules that contain low-level details. The low-level details are relegated to plugin modules that can be deployed and developed independently from the modules that contain high-level policies.
16%
Flag icon
Event sourcing is a strategy wherein we store the transactions, but not the state. When state is required, we simply apply all the transactions from the beginning of time.
17%
Flag icon
The goal of the principles is the creation of mid-level software structures that: • Tolerate change, • Are easy to understand, and • Are the basis of components that can be used in many software systems. The term “mid-level” refers to the fact that these principles are applied by programmers working at the module level. They are applied just above the level of the code and help to define the kinds of software structures used within modules and components.
17%
Flag icon
SRP: The Single Responsibility Principle An active corollary to Conway’s law: The best structure for a software system is heavily influenced by the social structure of the organization that uses it so that each software module has one, and only one, reason to change.
17%
Flag icon
OCP: The Open-Closed Principle Bertrand Meyer made this principle famous in the 1980s. The gist is that for software systems to be easy to change, they must be designed to allow the behavior of those systems to be changed by adding new code, rather than changing existing code.
17%
Flag icon
LSP: The Liskov Substitution Principle Barbara Liskov’s famous definition of subtypes, from 1988. In short, this principle says that to build software systems from interchangeable parts, those parts must adhere to a contract that allows those parts to be substituted one for another.
17%
Flag icon
ISP: The Interface Segregation Principle This principle advises software designers to avoid depending on things that they don’t use.
17%
Flag icon
DIP: The Dependency Inversion Principle The code that implements high-level policy should not depend on the code that implements low-level details. Rather, details should depend on policies.
18%
Flag icon
“cohesive” implies the SRP.
19%
Flag icon
The Single Responsibility Principle is about functions and classes—but it reappears in a different form at two more levels. At the level of components, it becomes the Common Closure Principle. At the architectural level, it becomes the Axis of Change responsible for the creation of Architectural Boundaries.
19%
Flag icon
The Open-Closed Principle (OCP) was coined in 1988 by Bertrand Meyer.1 It says: A software artifact should be open for extension but closed for modification.
19%
Flag icon
If component A should be protected from changes in component B, then component B should depend on component A.
20%
Flag icon
Transitive dependencies are a violation of the general principle that software entities should not depend on things they don’t directly use.
20%
Flag icon
In 1988, Barbara Liskov wrote the following as a way of defining subtypes. What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of
22%
Flag icon
The Dependency Inversion Principle (DIP) tells us that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions.
22%
Flag icon
Don’t refer to volatile concrete classes. Refer to abstract interfaces instead. This rule applies in all languages, whether statically or dynamically typed. It also puts severe constraints on the creation of objects and generally enforces the use of Abstract Factories.
22%
Flag icon
Don’t derive from volatile concrete classes. This is a corollary to the previous rule, but it bears special mention. In statically typed languages, inheritance is the strongest, and most rigid, of all the source code relationships; consequently, it should be used with great care. In dynamically typed languages, inheritance is less of a problem, but it is still a dependency—and caution is always the wisest choice.
22%
Flag icon
Don’t override concrete functions. Concrete functions often require source code dependencies. When you override those functions, you do not eliminate those dependencies—indeed, you inherit them. To manage those dependencies, you should make the function abstract and create multiple implementations.
22%
Flag icon
Never mention the name of anything concrete and volatile. This is really just a restatement of the principle itself.
23%
Flag icon
Regardless of how they are eventually deployed, well-designed components always retain the ability to be independently deployable and, therefore, independently developable.
25%
Flag icon
the three principles of component cohesion: • REP: The Reuse/Release Equivalence Principle • CCP: The Common Closure Principle • CRP: The Common Reuse Principle
25%
Flag icon
The Reuse/Release Equivalence Principle (REP) is a principle that seems obvious, at least in hindsight. People who want to reuse software components cannot, and will not, do so unless those components are tracked through a release process and are given release numbers.
25%
Flag icon
Gather into components those classes that change for the same reasons and at the same times. Separate into different components those classes that change at different times and for different reasons.
26%
Flag icon
Gather together those things that change at the same times and for the same reasons. Separate those things that change at different times or for different reasons.
26%
Flag icon
Don’t force users of a component to depend on things they don’t need.
27%
Flag icon
Allow no cycles in the component dependency graph.
28%
Flag icon
Depend in the direction of stability.
29%
Flag icon
Any component that we expect to be volatile should not be depended on by a component that is difficult to change.
29%
Flag icon
something is stable if it is “not easily moved.”
29%
Flag icon
Stability is related to the amount of work required to make a change.
29%
Flag icon
One sure way to make a software component difficult to change, is to make lots of other software components depend on it. A component with lots of incoming dependencies is very stable because it requires a great deal of work to reconcile any changes with all the dependent components.
29%
Flag icon
Fan-in: Incoming dependencies. This metric identifies the number of classes outside this component that depend on classes within the component.
29%
Flag icon
Fan-out: Outgoing dependencies. This metric identifies the number of classes inside this component that depend on classes outside the component.
29%
Flag icon
I: Instability: I = Fan-out / (Fan-in + Fan-out). This metric has the range [0, 1]. I = 0 indicates a maximally stable component. I = 1 indicates a maximally unstable component.
29%
Flag icon
The SDP says that the I metric of a component should be larger than the I metrics of the components that it depends on. That is, I metrics should decrease in the direction of dependency.