Clean Architecture: A Craftsman's Guide to Software Structure and Design
Rate it:
Open Preview
4%
Flag icon
Not only does a good architecture meet the needs of its users, developers, and owners at a given point in time, but it also meets them over time.
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.
7%
Flag icon
The developers may think that the answer is to start over from scratch and redesign the whole system—but that’s just the Hare talking again. The same overconfidence that led to the mess is now telling them that they can build it better if only they can start the race over.
7%
Flag icon
Their overconfidence will drive the redesign into the same mess as the original project.
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
From the stakeholders’ point of view, they are simply providing a stream of changes of roughly similar scope. From the developers’ point of view, the stakeholders are giving them a stream of jigsaw puzzle pieces that they must fit into a puzzle of ever-increasing complexity.
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
Software development is not a mathematical endeavor, even though it seems to manipulate mathematical constructs. Rather, software is like a science. We show correctness by failing to prove incorrectness, despite our best efforts.
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.
15%
Flag icon
All race conditions, deadlock conditions, and concurrent update problems are due to mutable variables.
16%
Flag icon
Architects would be wise to push as much processing as possible into the immutable components, and to drive as much code as possible out of those components that must allow mutation.
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
A module should have one, and only one, reason to change.
17%
Flag icon
A module should be responsible to one, and only one, user or stakeholder.
18%
Flag icon
The SRP says to separate the code that different actors depend on.
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.
25%
Flag icon
For most applications, maintainability is more important than reusability. If the code in an application must change, you would rather that all of the changes occur in one component, rather than being distributed across many components.
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.
31%
Flag icon
a metric is not a god; it is merely a measurement against an arbitrary standard.
32%
Flag icon
Never fall for the lie that suggests that software architects pull back from code to focus on higher-level issues.
32%
Flag icon
Software architects may not write as much code as other programmers do, but they continue to engage in programming tasks. They do this because they cannot do their jobs properly if they are not experiencing the problems that they are creating for the rest of the programmers.
32%
Flag icon
Such a component-per-team architecture is not likely to be the best architecture for deployment, operation, and maintenance of the system. Nevertheless, it is the architecture that a group of teams will gravitate toward if they are driven solely by development schedule.
33%
Flag icon
The way you keep software soft is to leave as many options open as possible, for as long as possible.
35%
Flag icon
Any organization that designs a system will produce a design whose structure is a copy of the organization’s communication structure.
36%
Flag icon
If you decouple the elements of the system that change for different reasons, then you can continue to add new use cases without interfering with old ones.
37%
Flag icon
Another problem with service-level decoupling is that it is expensive, both in development time and in system resources. Dealing with service boundaries where none are needed is a waste of effort, memory, and cycles.
41%
Flag icon
The fact that the boundaries are not visible during the deployment of a monolith does not mean that they are not present and meaningful.
41%
Flag icon
Even in a monolithic, statically linked executable, this kind of disciplined partitioning can greatly aid the job of developing, testing, and deploying the project. Teams can work independently of each other on their own components without treading on each other’s toes. High-level components remain independent of lower-level details.
44%
Flag icon
Why are Entities high level and use cases lower level? Because use cases are specific to a single application and, therefore, are closer to the inputs and outputs of that system. Entities are generalizations that can be used in many different applications, so they are farther from the inputs and outputs of the system.
44%
Flag icon
The business rules should remain pristine, unsullied by baser concerns such as the user interface or database used.
44%
Flag icon
Just as the plans for a house or a library scream about the use cases of those buildings, so should the architecture of a software application scream about the use cases of the application.
44%
Flag icon
Frameworks are tools to be used, not architectures to be conformed to.
44%
Flag icon
If your architecture is based on frameworks, then it cannot be based on your use cases.
44%
Flag icon
The first concern of the architect is to make sure that the house is usable—not to ensure that the house is made of bricks. Indeed, the architect takes pains to ensure that the homeowner can make decisions about the exterior material (bricks, stone, or cedar) later, after the plans ensure that the use cases are met.
44%
Flag icon
A good software architecture allows decisions about frameworks, databases, web servers, and other environmental issues and tools to be deferred and delayed.
45%
Flag icon
A good architecture emphasizes the use cases and decouples them from peripheral concerns.
45%
Flag icon
Look at each framework with a jaded eye. View it skeptically. Yes, it might help, but at what cost? Ask yourself how you should use it, and how you should protect yourself from it. Think about how you can preserve the use-case emphasis of your architecture. Develop a strategy that prevents the framework from taking over that architecture.
46%
Flag icon
Thus, when we pass data across a boundary, it is always in the form that is most convenient for the inner circle.
48%
Flag icon
At each architectural boundary, we are likely to find the Humble Object pattern lurking somewhere nearby. The communication across that boundary will almost always involve some kind of simple data structure, and the boundary will frequently divide something that is hard to test from something that is easy to test. The use of this pattern at architectural boundaries vastly increases the testability of the entire system.
50%
Flag icon
This example is intended to show that architectural boundaries exist everywhere. We, as architects, must be careful to recognize when they are needed. We also have to be aware that such boundaries, when fully implemented, are expensive. At the same time, we have to recognize that when such boundaries are ignored, they are very expensive to add in later—even in the presence of comprehensive test-suites and refactoring discipline.
50%
Flag icon
Your goal is to implement the boundaries right at the inflection point where the cost of implementing becomes less than the cost of ignoring.
52%
Flag icon
First, let’s consider the notion that using services, by their nature, is an architecture. This is patently untrue. The architecture of a system is defined by boundaries that separate high-level policy from low-level detail and follow the Dependency Rule. Services that simply separate application behaviors are little more than expensive function calls, and are not necessarily architecturally significant.
52%
Flag icon
As for interfaces being well defined, that’s certainly true—but it is no less true for functions. Service interfaces are no more formal, no more rigorous, and no better defined than function interfaces.
52%
Flag icon
To the extent that they are coupled by data or behavior, the development, deployment, and operation must be coordinated.
54%
Flag icon
The architecture of a system is defined by the boundaries drawn within that system, and by the dependencies that cross those boundaries. That architecture is not defined by the physical mechanisms by which elements communicate and execute.
54%
Flag icon
Fragile tests often have the perverse effect of making the system rigid. When developers realize that simple changes to the system can cause massive test failures, they may resist making those changes.
54%
Flag icon
The first rule of software design—whether for testability or for any other reason—is always the same: Don’t depend on volatile things.
54%
Flag icon
GUIs are volatile. Test suites that operate the system through the GUI must be fragile. Therefore design the system, and the tests, so that business rules can be tested without using the GUI.