More on this book
Community
Kindle Notes & Highlights
Finally, as cycles appear, the ADP is applied and the component dependency graph jitters and grows.
THE STABLE DEPENDENCIES PRINCIPLE
Depend in the direction of stability.
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.
By conforming to the Stable Dependencies Principle (SDP), we ensure that modules that are intended to be easy to change are not depended on by modules that are harder to change.
Stability is related to the amount of work required to make a change. On the one hand, the standing penny is not stable because it requires very little work to topple
On the other hand, a table is very stable because it takes a considerable amount of effort to turn it over.
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).
A component should be as abstract as it is stable.
classes that are flexible enough to be extended without requiring modification. Which kind of classes conform to this principle? Abstract classes.
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 pre...
This highlight has been truncated due to consecutive passage length restrictions.
the other hand, it says that an unstable component should be concrete since it its instability allows the concrete co...
This highlight has been truncated due to consecutive passage length restrictions.
Thus, if a component is to be stable, it should consist of interfaces and abstract classes ...
This highlight has been truncated due to consecutive passage length restrictions.
Thus dependencies run in the direction of abstraction.
The A metric is a measure of the abstractness of a component. Its value is simply the ratio of interfaces and abstract classes in a component to the total number of classes in the component. • Nc: The number of classes in the component. • Na: The number of abstract classes and interfaces in the component. • A: Abstractness. A = Na ÷ Nc.
is very common for one abstract class to derive from another abstract class.
Some software entities do, in fact, fall within the Zone of Pain. An example would be a database schema.
Database schemas are notoriously volatile, extremely concrete, and highly depended on. This is one reason why the interface between OO applications and databases is so difficult to manage, and why schema updates are generally painful.
Another example of software that sits near the area of (0, 0) is a con...
This highlight has been truncated due to consecutive passage length restrictions.
Thus this area is called the Zone of Uselessness. The software entities that inhabit this region are a kind of detritus. They are often leftover abstract classes that no one ever implemented. We find them in systems
The locus of points that are maximally distant from each zone is the line that connects (1, 0) and (0, 1). I call this line the Main Sequence.
A component that sits on the Main Sequence is not “too abstract” for its stability, nor is it “too unstable” for its abstractness.
is neither useless nor particularly painful. It is depended on to the extent that it is abstract, and it depends on others to the extent that it is concrete.
Good architects strive to position the majority of their components at those endpoints. However, in my experience, some small fraction of the components in a large system are neither perfectly abstract nor perfectly stable.
create a metric that measures how far away a component is from this ideal.
D3: Distance. D = |A+I–1| . The range of this metric is [0, 1]. A value of 0 indicates that the component is directly on the Main Sequence. A value of 1 indicates that the component is as far away as possible from the Main Sequence.
Another way to use the metrics is to plot the D metric of each component over time.
The dependency management metrics described in this chapter measure the conformance of a design to a pattern of dependency and abstraction that I think is a “good” pattern.
a metric is not a god; it is merely a measurement against an arbitrary standard. These metrics are imperfect, at best, but it is my hope that you find them useful.
First of all, a software architect is a programmer; and continues to be a programmer. Never fall for the lie that suggests that software architects pull back from code to focus on higher-level issues. They do not!
Software architects are the best programmers, and they continue to take programming tasks, while they also guide the rest of the team toward a design that maximizes productivity. Software architects may not write as much code as other programmers do, but they continue to engage in programming tasks.
The architecture of a software system is the shape given to that system by those who build it. The form of that shape is in the division of that system into components, the arrangement of those components, and the ways in which those components communicate with each other.
The purpose of that shape is to facilitate the development, deployment, operation, and maintenance of the software system contained within it.
The strategy behind that facilitation is to leave as many options open as possible,...
This highlight has been truncated due to consecutive passage length restrictions.
There are many systems out there, with terrible architectures, that work just fine. Their troubles do not lie in their operation; rather, they occur in their deployment, maintenance, and ongoing development.
This is not to say that architecture plays no role in supporting the proper behavior of the system. It certainly does, and that role is critical. But the role is passive and cosmetic, not active or essential. There are few, if any, behavioral options that the architecture of a system can leave open.
A software system that is hard to develop is not likely to have a long and healthy lifetime. So the architecture of a system should make that system easy to develop, for the team(s) who develop it.
This is likely the reason why so many systems lack good architecture: They were begun with none, because the team was small and did not want the impediment of a superstructure.
A goal of a software architecture, then, should be to make a system that can be easily deployed with a single action.
deployment strategy is seldom considered during initial development. This leads to architectures that may make the system easy to develop, but leave it very difficult to deploy.
For example, in the early development of a system, the developers may decide to use a “mi...
This highlight has been truncated due to consecutive passage length restrictions.
the number of micro-services has become daunting; configuring the connections between them, and the timing of their initiation, may also turn out to be a huge source of errors.
Had the architects considered deployment issues early on, they might have decided on fewer services, a hybrid of services and in-process components, and a more integrated means of managing the interconnections.
The fact that hardware is cheap and people are expensive means that architectures that impede operation are not as costly as architectures that impede development, deployment, and maintenance.
good software architecture communicates the operational needs of the system.
Architecture should reveal operation. The architecture of the system should elevate the use cases, the features, and the required behaviors of the system to first-class entities that are visible landmarks for the developers. This simplifies the understanding of the system and, therefore, greatly aids in development and maintenance.
Of all the aspects of a software system, maintenance is the most costly. The never-ending parade of new features and the inevitable trail of defects and corrections consume vast amounts of human resources.
A carefully thought-through architecture vastly mitigates these costs. By separating the system into components, and isolating those components through stable interfaces, it is possible to illuminate the pathways for future features and greatly reduce the risk of inadvertent breakage.
As we described in an earlier chapter, software has two types of value: the value of its behavior and the value of its structure. The second of these is the greater of the two because it is this value that makes software soft.