Hello everyone, I am han Cao 😈, a grass code ape 🐒 who has been working for more than a year. If you like my article, you can follow ➕ to like it and grow up with me. Add my wechat: Hancao97, invite you to join the group, learn and communicate together, and become a better engineer

“This is the 17th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

background

This is the 15th article in my Architectural Cleanliness series on the Principle of stable abstraction.

This article relies heavily on the previous article in this series, and SAP in this article is also the stable dependency principle of the previous article.

Clean Architecture Series:

  • Hancao’s column on the Way to Neat architecture

Principle of stable abstraction

The abstraction of a component should be consistent with its stability.

Where do higher-order strategies go

In a software system, there are always parts that shouldn’t change very often. These sections are usually used to represent the high-level architectural design of the system and some high-level policy-related decisions.

We don’t want these business decisions and architectural designs to change frequently, so the components that represent the higher-order policies of the system should be placed in stable components (I=0), and unstable components (I=1) should only include those that we want to change quickly and easily.

So there’s a question:

If we put high-level policies into stable components, the source code used to describe those policies would be difficult to modify. This can make the architectural design of the entire system difficult to change. How can an infinitely stable component (I=0) accept changes?

Here we can review the open and close principle before: design principle (3) : OCP open and close principle. With this principle as a guide, it is possible to create a class that is flexible enough to be extended without modification.

This is where we can use abstract classes.

Introduction to stable abstraction principles

The Stable Abstraction principle (SAP) establishes a relationship between the stability of a component and its degree of abstraction. On the one hand, the principle requires that a stable component should also be abstract, so that its stability does not affect extensibility. On the other hand, this principle also requires that an unstable component should contain concrete implementation code so that its instability can be easily modified with concrete code.

Combining the two principles of SAP and SDP equals DIP at the component level. Because SDP requires that dependencies point in a more stable direction, SAP tells us that stability implicitly requires abstraction, that dependencies should point in a more abstract direction.

DIP, after all, is a principle associated with the class hierarchy, and a class is either abstract or not. The SDP/SAP principle applies at the component level, allowing a component to be partially abstract and partially stable.

Classes can only be abstract or not, and components are not “black and white”, so there are the following metrics:

Measure abstraction

Suppose the A metric is A measure of the abstraction of A component, and its value is the proportion of abstract classes and interfaces in the component. So:

  • Nc: the number of classes in the component.
  • Na: The number of abstract classes and interfaces in a component.
  • A: Degree of abstraction, A=Na/Nc

The value of indicator A ranges from [0, 1]. A value of 0 means that there are no abstract classes in the component, and A value of 1 means that there are only abstract classes in the component.

The main sequence

We now have the component’s stability, I, and its abstraction, A, to define the relationship between them.

The most stable component in the figure above, which contains an infinite number of abstract classes, should be in the upper left corner (0,1), and the most unstable, concrete component should be in the lower right corner (1,0). We cannot force all components to be in positions (0,1) and (1,0), so we must assume that there is a reasonable component range in the figure above. This interval should be able to be derived by elimination, which means that we can first figure out where the components should not be.

Let’s learn about the pain zone and the useless zone

Pain area

Given that a component is in position (0,0), it should be a very stable but very specific component.

Such a component is poorly designed because it is difficult to modify, which means that the component cannot be extended. As a result, because the component is not abstract and is particularly difficult to modify for stability reasons, we do not want a well-designed component to be near this region, so the region around (0,0) is called the pain region.

It is harmless for immutable components “such as utility libraries” to fall into the (0,0) zone because they are unlikely to change. Because of this, it is the ever-changing software components that fall into the pain zone that cause trouble.

Useless area

Let’s look at components near the point (1,1). These components are usually infinitely abstract, but are not dependent on other components. Such components are often unavailable, so we call this area the useless area.

For example, some abstract class in a corner of the system that no one has implemented just sits there, unused.

Components that fall into the garbage zone are also bound to contain a lot of garbage code, which is not what we want.

Avoid these two areas

Main sequence line: connects from (1,0) to (0,1).

Components that sit on a main sequence line are not designed to be “too abstract” for stability, nor are they designed to be “too unstable” to avoid abstraction. Such a component would not be particularly difficult to modify, but would be sufficiently functional.

For these components, there are usually enough components that depend on them to give them a degree of abstraction, and enough other components that it must contain many concrete implementations.

On the entire main sequence line, the optimal position for a component is at either end of the line. However, components in large systems cannot be completely abstract, nor can they be completely stable. So we just want to have these components on, or close to, the main sequence line.

Distance from the main sequence line

D index: distance D = A + | | I – 1, the scope of the index is [O, 1). A value of 0 means that the component is directly on the main sequence line, and a value of 1 means that the component is farthest from the main sequence.

By calculating the D indicator for each component, you can quantify how well a system design fits into the master sequence. The diagram below:

We can also track the D value of a component from version to version. Assuming that D=O.1 is the red line for the component, the 2.1 version of R has a D value outside the red line, which tells us that it is now worth some effort to find out why this component deviates from the main sequence line.

conclusion

This brings to an end the three principles, which are essentially indicators of dependency management that can be used to quantify how well a system design fits into a “good” design pattern.

✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨

Youth never knows heaven and earth

Conceit and talent are everywhere you look

Pretentious as it is

I was honest

I love such a boy

Humble and arrogant

Proud and calm ☀️

✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨

Your likes and attention are my constant motivation, you can add my wechat: HancAO97, invite you to join the group, learn and communicate together, become a better front-end engineer ~