Clean Architecture: A Craftsman's Guide to Software Structure and Design
Rate it:
Open Preview
Kindle Notes & Highlights
37%
Flag icon
For example, it’s not difficult to imagine that a system that runs comfortably on one server right now might grow to the point where some of its components ought to run on separate servers.
37%
Flag icon
As the development, deployment, and operational issues increase, I carefully choose which deployable units to turn into services, and gradually shift the system in that direction.
37%
Flag icon
A good architecture will allow a system to be born as a monolith, deployed in a single file, but then to grow into a set of independently deployable units, and then all the way to independent services and/or micro-services. Later, as things change, it should allow for reversing that progression and sliding all the way back down into a monolith.
37%
Flag icon
Recall that the goal of an architect is to minimize the human resources required to build and maintain the required system. What it is that saps this kind of people-power? Coupling—and especially coupling to premature decisions.
37%
Flag icon
These include decisions about frameworks, databases, web servers, utility libraries, dependency injection, and the like.
37%
Flag icon
A good system architecture allows those decisions to be made at the latest possible moment, without significant impact.
39%
Flag icon
You draw lines between things that matter and things that don’t.
39%
Flag icon
The business rules don’t need to know about the schema, or the query language, or any of the other details about the database. All the business rules need to know is that there is a set of functions that can be used to fetch or save data. This allows us to put the database behind an interface.
39%
Flag icon
This implies that the DatabaseInterface classes live in the BusinessRules component, while the DatabaseAccess classes live in the Database component.
40%
Flag icon
This may be hard to grasp at first. We often think about the behavior of the system in terms of the behavior of the IO.
40%
Flag icon
Boundaries are drawn where there is an axis of change.
40%
Flag icon
This is simply the Single Responsibility Principle again. The SRP tells us where to draw our boundaries.
40%
Flag icon
To draw boundary lines in a software architecture, you first partition the system into components. Some of those components are core business rules; others are plugins that contain necessary functions that are not directly related to the core business. Then you arrange the code in those components such that the arrows between them point in one direction—toward the core business.
41%
Flag icon
The trick to creating an appropriate boundary crossing is to manage the source code dependencies.
41%
Flag icon
It is simply a disciplined segregation of functions and data within a single processor and a single address space. In a previous chapter, I called this the source-level decoupling mode.
41%
Flag icon
From a deployment point of view, this amounts to nothing more than a single executable file—the so-called monolith.
41%
Flag icon
With that one exception, deployment-level components are the same as monoliths. The functions generally all exist in the same processor and address space. The strategies for segregating the components and managing their dependencies are the same.
42%
Flag icon
The services assume that all communications take place over the network.
42%
Flag icon
Software systems are statements of policy. Indeed, at its core, that’s all a computer program actually is. A computer program is a detailed description of the policy by which inputs are transformed into outputs.
42%
Flag icon
Part of the art of developing a software architecture is carefully separating those policies from one another, and regrouping them based on the ways that they change.
42%
Flag icon
A strict definition of “level” is “the distance from the inputs and outputs.”
42%
Flag icon
The farther a policy is from both the inputs and the outputs of the system, the higher its level. The policies that manage input and output are the lowest-level policies in the system.
42%
Flag icon
We want source code dependencies to be decoupled from data flow and coupled to level.
43%
Flag icon
Higher-level policies—those that are farthest from the inputs and outputs—tend to change less frequently, and for more important reasons, than lower-level policies.
43%
Flag icon
Another way to look at this issue is to note that lower-level components should be plugins to the higher-level components.
43%
Flag icon
If we are going to divide our application into business rules and plugins, we’d better get a good grasp on just what business rules actually are.
43%
Flag icon
Strictly speaking, business rules are rules or procedures that make or save the business money. Very strictly speaking, these rules would make or save the business money, irrespective of whether they were implemented on a computer. They would make or save money even if they were executed manually.
43%
Flag icon
We shall call these rules Critical Business Rules, because they are critical to the business itself, and would exist even if there were no system to automate them. Critical Business Rules usually require some data to work with. For example, our loan requires a loan balance, an interest rate, and a payment schedule.
43%
Flag icon
We shall call this data Critical Business Data. This is the data that would exist even if the system were not automated. The critical rules and critical data are inextricably bound, so they are a good candidate for an object. We’ll call this kind of object an Entity.1
43%
Flag icon
An Entity is an object within our computer system that embodies a small set of critical business rules operating on Critical Business Data.
43%
Flag icon
All that is required is that you bind the Critical Business Data and the Critical Business Rules together in a single and separate software module.
43%
Flag icon
This is a use case.2 A use case is a description of the way that an automated system is used. It specifies the input to be provided by the user, the output to be returned to the user, and the processing steps involved in producing that output. A use case describes application-specific business rules as opposed to the Critical Business Rules within the Entities.
44%
Flag icon
Use cases contain the rules that specify how and when the Critical Business Rules within the Entities are invoked. Use cases control the dance of the Entities.
44%
Flag icon
A use case is an object. It has one or more functions that implement the application-specific business rules. It also has data elements that include the input data, the output data, and the references to the appropriate Entities with which it interacts. Entities have no knowledge of the use cases that control them.
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.
44%
Flag icon
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
REQUEST AND RESPONSE MODELS
44%
Flag icon
The use case class accepts simple request data structures for its input, and returns simple response data structures as its output. These data structures are not dependent on anything. They do not derive from standard framework interfaces such as HttpRequest and HttpResponse. They know nothing of the web, nor do they share any of the trappings of whatever user interface might be in place.
44%
Flag icon
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.
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.
45%
Flag icon
If your system architecture is all about the use cases, and if you have kept your frameworks at arm’s length, then you should be able to unit-test all those use cases without any of the frameworks in place.
45%
Flag icon
Your architecture should tell readers about the system, not about the frameworks you used in your system.
45%
Flag icon
Source code dependencies must point only inward, toward higher-level policies.
46%
Flag icon
Entities encapsulate enterprise-wide Critical Business Rules. An entity can be an object with methods, or it can be a set of data structures and functions.
46%
Flag icon
INTERFACE ADAPTERS
46%
Flag icon
The software in the interface adapters layer is a set of adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external agency such as the database or the web.
46%
Flag icon
The presenters, views, and controllers all belong in the inter...
This highlight has been truncated due to consecutive passage length restrictions.
46%
Flag icon
The models are likely just data structures that are passed from the controllers to the use cases, and then back from the use...
This highlight has been truncated due to consecutive passage length restrictions.
46%
Flag icon
Similarly, data is converted, in this layer, from the form most convenient for entities and use cases, to the form most convenient for whatever persistence f...
This highlight has been truncated due to consecutive passage length restrictions.