Clean Architecture: A Craftsman's Guide to Software Structure and Design
Rate it:
Open Preview
4%
Flag icon
Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change. —Grady Booch
4%
Flag icon
Architecture is a hypothesis, that needs to be proven by implementation and measurement. —Tom Gilb
4%
Flag icon
My conclusion is that the rules of software architecture are independent of every other variable.
6%
Flag icon
When software is done right, it requires a fraction of the human resources to create and maintain. Changes are simple and rapid. Defects are few and far between. Effort is minimized, and functionality and flexibility are maximized.
6%
Flag icon
The goal of software architecture is to minimize the human resources required to build and maintain the required system.
7%
Flag icon
The only way to go fast, is to go well.
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.
8%
Flag icon
I have two kinds of problems, the urgent and the important. The urgent are not important, and the important are never urgent.1
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.
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.
16%
Flag icon
Structured programming is discipline imposed upon direct transfer of control. • Object-oriented programming is discipline imposed upon indirect transfer of control. • Functional programming is discipline imposed upon variable assignment.
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
A module should be responsible to one, and only one, actor.
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.
20%
Flag icon
This is how the OCP works at the architectural level. Architects separate functionality based on how, why, and when it changes, and then organize that separated functionality into a hierarchy of components. Higher-level components in that hierarchy are protected from the changes made to lower-level components.
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.
24%
Flag icon
We were, of course, experiencing Murphy’s law of program size: Programs will grow to fill all available compile and link time.
25%
Flag icon
THE COMMON CLOSURE PRINCIPLE 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. This is the Single Responsibility Principle restated for components.
26%
Flag icon
THE COMMON REUSE PRINCIPLE Don’t force users of a component to depend on things they don’t need. The Common Reuse Principle (CRP) is yet another principle that helps us to decide which classes and modules should be placed into a component. It states that classes and modules that tend to be reused together belong in the same component.
26%
Flag icon
Figure 13.1 is a tension diagram2 that shows how the three principles of cohesion interact with each other. The edges of the diagram describe the cost of abandoning the principle on the opposite vertex.
26%
Flag icon
A good architect finds a position in that tension triangle that meets the current concerns of the development team, but is also aware that those concerns will change over time. For example, early in the development of a project, the CCP is much more important than the REP, because develop-ability is more important than reuse.
26%
Flag icon
In the past, our view of cohesion was much simpler than the REP, CCP, and CRP implied. We once thought that cohesion was simply the attribute that a module performs one, and only one, function. However, the three principles of component cohesion describe a much more complex variety of cohesion. In choosing the classes to group together into components, we must consider the opposing forces involved in reusability and develop-ability. Balancing these forces with the needs of the application is nontrivial. Moreover, the balance is almost always dynamic.
27%
Flag icon
THE ACYCLIC DEPENDENCIES PRINCIPLE Allow no cycles in the component dependency graph.
27%
Flag icon
Over the last several decades, two solutions to this problem have evolved, both of which came from the telecommunications industry. The first is “the weekly build,” and the second is the Acyclic Dependencies Principle (ADP).
27%
Flag icon
ELIMINATING DEPENDENCY CYCLES The solution to this problem is to partition the development environment into releasable components. The components become units of work that can be the responsibility of a single developer, or a team of developers. When developers get a component working, they release it for use by the other developers. They give it a release number and move it into a directory for other teams to use. They then continue to modify their component in their own private areas. Everyone else uses the released version.
27%
Flag icon
Figure 14.1 Typical component diagram Notice one more thing: Regardless of which component you begin at, it is impossible to follow the dependency relationships and wind up back at that component. This structure has no cycles. It is a directed acyclic graph (DAG).
28%
Flag icon
Apply the Dependency Inversion Principle (DIP). In the case in Figure 14.3, we could create an interface that has the methods that User needs. We could then put that interface into Entities and inherit it into Authorizer. This inverts the dependency between Entities and Authorizer, thereby breaking the cycle.
28%
Flag icon
Create a new component that both Entities and Authorizer depend on. Move the class(es) that they both depend on into that new component (Figure 14.4).
28%
Flag icon
When cycles occur, they must be broken somehow. Sometimes this will mean creating new components, making the dependency structure grow.
28%
Flag icon
The component structure cannot be designed from the top down. It is not one of the first things about the system that is designed, but rather evolves as the system grows and changes.
28%
Flag icon
As the application continues to grow, we start to become concerned about creating reusable elements. At this point, the CRP begins to influence the composition of the components. Finally, as cycles appear, the ADP is applied and the component dependency graph jitters and grows.
28%
Flag icon
Thus the component dependency structure grows and evolves with the logical design of the system.
28%
Flag icon
THE STABLE DEPENDENCIES PRINCIPLE Depend in the direction of stability.
28%
Flag icon
By conforming to the Common Closure Principle (CCP), we create components that are sensitive to certain kinds of changes but immune to others. Some of these components are designed to be volatile. We expect them to change.
29%
Flag icon
Any component that we expect to be volatile should not be depended on by a component that is difficult to change. Otherwise, the volatile component will also be difficult to change.
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 changeable components are on top and depend on the stable component at the bottom. Putting the unstable components at the top of the diagram is a useful convention because any arrow that points up is violating the SDP (and, as we shall see later, the ADP).
30%
Flag icon
THE STABLE ABSTRACTIONS PRINCIPLE A component should be as abstract as it is stable.
30%
Flag icon
INTRODUCING THE STABLE ABSTRACTIONS PRINCIPLE The Stable Abstractions Principle (SAP) sets up a relationship between stability and abstractness. On the one hand, it says that a stable component should also be abstract so that its stability does not prevent it from being extended. On the other hand, it says that an unstable component should be concrete since its instability allows the concrete code within it to be easily changed.
30%
Flag icon
The SAP and the SDP combined amount to the DIP for components. This is true because the SDP says that dependencies should run in the direction of stability, and the SAP says that stability implies abstraction. Thus dependencies run in the direction of abstraction.
31%
Flag icon
Zone of Pain Consider a component in the area of (0, 0). This is a highly stable and concrete component. Such a component is not desirable because it is rigid. It cannot be extended because it is not abstract, and it is very difficult to change because of its stability. Thus we do not normally expect to see well-designed components sitting near (0, 0). The area around (0, 0) is a zone of exclusion called the Zone of Pain.
31%
Flag icon
Another example of software that sits near the area of (0, 0) is a concrete utility library.
31%
Flag icon
Nonvolatile components are harmless in the (0, 0) zone since they are not likely to be changed.
« Prev 1 3 4