Clean Architecture: A Craftsman's Guide to Software Structure and Design
Rate it:
Open Preview
63%
Flag icon
Notice that the arrows do not all flow from the right to the left. In fact, most of them point from left to right. This is because the architecture is following the Dependency Rule. All dependencies cross the boundary lines in one direction, and they always point toward the components containing the higher-level policy. Also notice that the using relationships (open arrows) point with the flow of control, and that the inheritance relationships (closed arrows) point against the flow of control. This depicts our use of the Open–Closed Principle to make sure that the dependencies flow in the ...more
64%
Flag icon
The first is the separation of actors based on the Single Responsibility Principle; the second is the Dependency Rule. The goal of both is to separate components that change for different reasons, and at different rates. The different reasons correspond to the actors; the different rates correspond to the different levels of policy.
64%
Flag icon
Once you have structured the code this way, you can mix and match how you want to actually deploy the system.
64%
Flag icon
The first, and perhaps simplest, design approach is the traditional horizontal layered architecture, where we separate our code based on what it does from a technical perspective. This is often called “package by layer.”
64%
Flag icon
In this typical layered architecture, we have one layer for the web code, one layer for our “business logic,” and one layer for persistence.
64%
Flag icon
Martin Fowler says that adopting such a layered architecture is a good way to get started.
64%
Flag icon
The problem, as Martin points out, is that once your software grows in scale and complexity, you will quickly find that having three large buckets of code isn’t sufficient, and you will need to think about modularizing further.
64%
Flag icon
Another problem is that, as Uncle Bob has already said, a layered architecture doesn’t scream anything about the business domain. Put the code for two layered architectures, from two very different business domains, side by side and they will likely look eerily similar: web, services, and repositories.
64%
Flag icon
Another option for organizing your code is to adopt a “package by feature” style. This is a vertical slicing, based on related features, domain concepts, or aggregate roots (to use domain-driven design terminology).
64%
Flag icon
we have the same interfaces and classes as before, but they are all placed into a single Java package rather than being split among three packages. This is a very simple refactoring from the “package by layer” style, but the top-level organization of the code now screams something about the business domain. We can now see that this code base has something to do with orders rather than the web, services, and repositories.
64%
Flag icon
approaches such as “ports and adapters,” the “hexagonal architecture,” “boundaries, controllers, entities,” and so on aim to create architectures where business/domain-focused code is independent and separate from the technical implementation details such as frameworks and databases.
65%
Flag icon
you often see such code bases being composed of an “inside” (domain) and an “outside” (infrastructure),
65%
Flag icon
Figure 34.3 A code base with an inside and an outside
65%
Flag icon
The “inside” region contains all of the domain concepts, whereas the “outside” region contains the interactions with the outside world (e.g., UIs, databases, third-party integrations). The major rule here is that the “outside” depends on the “inside”—never the other way around. Figure 34.4 shows a version of how the “view orders” use case might be implemented.
65%
Flag icon
The dependency arrows still point downward, but the OrdersController is now additionally bypassing the OrdersService for some use cases. This organization is often called a relaxed layered architecture, as layers are allowed to skip around their adjacent neighbor(s). In some situations, this is the intended outcome—if you’re trying to follow the CQRS5 pattern, for example. In many other cases, bypassing the business logic layer is undesirable, especially if that business logic is responsible for ensuring authorized access to individual records, for example.
65%
Flag icon
34.5 Relaxed layered architecture
65%
Flag icon
This brings us to the “package by component” option. It’s a hybrid approach to everything we’ve seen so far, with the goal of bundling all of the responsibilities related to a single coarse-grained component into a single Java package. It’s about taking a service-centric view of a software system, which is something we’re seeing with micro-service architectures as well.
66%
Flag icon
“package by component” keeps the user interface separate from these coarse-grained components. Figure 34.6 shows what the “view orders” use case might look like.
66%
Flag icon
In essence, this approach bundles up the “business logic” and persistence code into a single thing, wh...
This highlight has been truncated due to consecutive passage length restrictions.
66%
Flag icon
Components are the units of deployment. They are the smallest entities that can be deployed as part of a system. In Java, they are jar files.
66%
Flag icon
“C4 software architecture model,”7 which
66%
Flag icon
A key benefit of the “package by component” approach is that if you’re writing code that needs to do something with orders, there’s just one place to go—the OrdersComponent. Inside the component, the separation of concerns is still maintained, so the business logic is separate from data persistence, but that’s a component implementation detail that consumers don’t need to know about.
66%
Flag icon
You can think of well-defined components in a monolithic application as being a stepping stone to a micro-services architecture.
66%
Flag icon
Looking at this issue another way, if you make all types in your Java application public, the packages are simply an organization mechanism (a grouping, like folders), rather than being used for encapsulation.
66%
Flag icon
All four architectural approaches are the same
66%
Flag icon
Grayed-out types are where the access modifier can be made more restrictive
67%
Flag icon
The fewer public types you have, the smaller the number of potential dependencies. There’s now no way9 that code outside this package can use the OrdersRepository interface or implementation directly, so we can rely on the compiler to enforce this architectural principle.
67%
Flag icon
I’m enthusiastic that the Java 9 module system will give us another tool to build better software, and spark people’s interest in design thinking once again.
67%
Flag icon
Another option is to decouple your dependencies at the source code level, by splitting code across different source code trees.
67%
Flag icon
A simpler approach that some people follow for their ports and adapters code is to have just two source code trees: • Domain code (the “inside”) • Infrastructure code (the “outside”)
67%
Flag icon
be aware of the potential trade-off. It’s what I call the “Périphérique anti-pattern of ports and adapters.”
67%
Flag icon
Having all of your infrastructure code in a single source code tree means that it’s potentially possible for infrastructure code in one area of your application (e.g., a web controller) to directly call code in another area of your application (e.g., a database repository), without navigating through the domain. This is especially true if you’ve forgotten to apply appropriate access modifiers to that code.
67%
Flag icon
The whole point of this chapter is to highlight that your best design intentions can be destroyed in a flash if you don’t consider the intricacies of the implementation strategy. Think about how to map your desired design on to code structures, how to organize that code, and which decoupling modes to apply during runtime and compile-time. Leave options open where applicable, but be pragmatic, and take into consideration the size of your team, their skill level, and the complexity of the solution in conjunction with your time and budgetary constraints. Also think about using your compiler to ...more
68%
Flag icon
Like riding a bicycle, you can’t master software design just by reading about it. To get the best from a book like this, you need to get practical. Analyze your code and look for the kinds of problems Bob highlights, then practice refactoring the code to fix these problems. If you’re new to the refactoring discipline, then this will be a doubly valuable experience.
1 2 4 Next »