Photo by Markus Spiske on Unsplash

Clean Architecture -> PART IV: Component Principles

Muhammed Ali Aydın

--

Considering that SOLID principles tell us how to arrange bricks in a room or wall, component principles tell us how the rooms inside the building will be arranged.

Chapter 12: Components

Components are deployment units. In other words, they are the smallest assets of the system that can be deployed. These are jars in Java and gem files in Ruby.

Compiled languages are combinations of binary files, while interpreted languages are combinations of source files. So for each language, they are part of deployment.

Chapter 13: Component Cohesion

It is an important decision to determine which classes belong to which component. When deciding, guidance from a good software engineering principle is needed. Three component coupling principles are available:

REP: The Reuse/Relase Equivalance Principle

CCP: The Common Closure Principle

CRP: The Common Reuse Principle

1. The Reuse/Relase Equivalance Principle (REP)

REP is a principle that allows us to see the obvious, though a little late. People want to reuse a component that they cannot or will not use unless they are followed by a process release or a given release number.

However, this is not easy, because when one component does not have a release number, there is no way to know whether the reused componenting is compatible with the others. More precisely, this means that the developer needs to know when a release will arrive and what innovations will come with this release.

From a software design and architectural perspective, this principle says that classes and modules within the component must be in a cohesive group. According to this principle, the component cannot consist of randomly assembled classes and modules. Instead, they should serve a theme that encompasses them, or a common goal that they all share. The classes and modules that make up the component must also be released together. In this way, they can all share the same version number and the same release tracking.

The weakness of this principle is that what it provides by the strengths of the other two principles is more than affordable. More precisely, CCP and CRP define this principle more strongly, but with a negative perception.

2. The Common Closure Principle (CCP)

SRP is adapted for components. Unlike SRP, it considers that a component should not have multiple reasons to change. That is, SRP says that if different functions need to change for different reasons, they should be divided into different classes, whereas CCP says that if different classes need to change for different reasons, they must be divided into different components.

When the code in an application has to change, instead of changing all components, the problem must be solved by changing the content of only one component. Thus, if the change is limited to only one component, only that component will need to be deployed. This will ensure that other components are not affected by this event.

At the same time, it tends to gather the classes that conform to the Open Closed (OCP) principle to the same component, which is closed to modification, but open to extensions, with the same type of changes. Thus, it aims to replace the minimum number of components in case of any requirement change.

3. The Common Reuse Principle (CRP)

CRP is another principle used to determine a class or component will belong to which component. It argues that classes that are reusable and which will cooperate with each other in the reuse phase must be in the same component.

CRP also tells us which classes should not be in the same component, as well as telling us which classes to put in the same component. When a component uses another component, a dependency occurs between them. It does not weaken the dependency between them, even if the component is only a class. Because of this connection between them, when a change is made to the component used, it is reflected in the component that uses it. Even if no changes have been made to the component being used, or even if the change does not affect the component at all, it must be recompiled, validated, and deployed.

So if we’re going to make a component-dependent development, we need to make sure that the process is dependent on every class in that component. For this reason, CRP is more of a guideline than to tell us which class will be in a component, but which one will not. CRP is also defined as the generic version of the ISP. ISP says that we shouldn’t depend on a class that we don’t use, while CRP says we shouldn’t depend on a component that we won’t use.

4. The Tension Diagram For Component Cohesion

In fact, it can be said that these three principles are at war with each other. While REP and CCP are more prone to increasing the size of the component, CRP is trying to reduce the size of the component.

“Cohesion Principles Tension” diagram is given below.

Cohesion principles tension diagram

A designer who focuses exclusively on REP and CRP will cause a large number of components to be affected by the smallest changes. On the contrary, a designer who focuses strongly on CCP and REP will result in a large number of unnecessary releases.

A good designer should try to find a middle way in this tension triangle according to the concerns of the development team, but should be aware that these concerns will develop over time.

Generally, projects are initially more prone to the right side of the triangle, and as the project matures, this trend shifts to the left. This indicates that the component structure may vary depending on the maturity and timing of the project.

Chapter 14: Component Coupling

There are three principles regarding the relationships between components:

ADP: Acyclic Dependencies Principle

SDP: Stable Dependencies Principle

SAP: Stable Abstractions Principle

1. The Acyclic Dependencies Principle

Sometimes we see that the things that we’ve been working on all day, after a day, don’t work. When we investigate this, we realize that someone else changes something that we have developed as dependent and makes all the things we deal with inoperable. The author calls this the morning after syndrome.

“the morning after syndrome” occurs in development environments with some programmers changing source code. While this problem does not cause very big problems in relatively small teams, it is not possible to say the same for large teams.

Two solutions have been proposed for this problem: weekly build and Acyclic Dependencies Principle (ADP).

a. The Weekly Build

Usually used in medium-sized projects. Developers work the first four days of the week, ignoring the others. Without any integration concerns, they develop the code as if the code will run independently. After four days, on Friday, all changes and the system are integrated.

Although this approach provides a great advantage for the first four days, the fifth day causes a serious problem. As the project grows, the cost of integration increases and the burden on other days begins. As integration decreases, so does the efficiency of the development team. Therefore, this situation causes crisis in time.

b. Eliminating Dependency Cycles

This problem can be resolved by dividing the development environment into releasable components. These components become the work of a developer or a team and can be made available to other developers.

When a new release of a component is released, other teams also need to adapt their work to the new release. However, each change made to a component may not be critical to other teams. It is a decision of the team to decide whether the work will be adjusted according to the new release.

Typical component diagram

Above is a specific component structure of an application. There is no cycle in this graph structure which is a directional graph. Therefore, it is called directed acyclic graph.

Let’s assume that the team that developed Presenter has released a new release. Using the graph, we can say that the Main and View components will be affected when we follow the arrows in the opposite direction. The team working on these components needs to decide whether to adapt their own components with this new change.

When the release time of the whole system arrives, the process goes from bottom to top. First, the Entities component is compiled, tested and released. This is followed by Database and Interactors. Then the same operations are applied to Presenter, View and Controller. Lastly after applying to Authorizer and Main, it ends.

Suppose a developer works in the Database component. He knows that this component is dependent on Entities. However, because of the cycle here, it is also dependent on Authorizer and Interactors components. This makes the Database component a difficult component for release. This level of dependence leads to serious problems, if not compulsory.

c. Breaking the Cycle

In such cases, it is possible to reconstruct the graph by breaking the cycle. There are 2 different ways to do this:

By applying DIP, an interface between Entities and Authorizer can be placed and the connection can be reversed.

Inverting the dependency between Entities and Authorizer

A component to which Entites and Authorizer components are dependent can be created. This is usually applied when a temporary solution is required. Creating new components means that the dependency structure will also grow.

The new component that both Entities and Authorizer depend on

2. Top-Down Design

The conclusion that can be drawn from the problems described so far is that the component structure cannot be designed from top to bottom. Component structure is not one of the first things to be done when designing the system, it should develop according to the growth and change of the system.

The fact is that component dependency diagrams do not have much to do with defining the functions of the application, but rather are important in the planning of the application’s buildability and maintability features. Therefore, they are not designed from the very beginning of the project. When there is no software for executing build or maintain functions, there is not much need for planning.

The changes are localized as much as possible in a specific region, and can be achieved by having the class distributions of the components where regional changes can be made by giving importance to SRP and CCP.

As application begins to grow, reusable element formation becomes a concern. At this point, components are started to be combined using CRP. The loops resulting from this process are also broken using ADP and component dependency is eliminated, but the graph is growing.

If the component dependency structure is attempted before any class is designed, it will lead to serious consequences. It is very difficult to recognize the dependencies and reusable elements when there is no design. Therefore, the component dependency structure grows and develops with the logical design of the system.

3. The Stable Dependencies Principle

The design cannot be completely static. To be a sustainable design, it needs to be a little volatility. By applying CCP, components that are sensitive to changes and independent of others are created. Some of these components are designed to be volatile. These are expected to be changeable as the project matures.

At the same time, it is necessary to make sure that these temporary components are not dependent on the components that are difficult to change. Failure to meet this requirement makes it very difficult to change the component, which is designed to be susceptible to change. Therefore, it can be ensured that such dependence does not occur by using the Stable Dependencies Principle (SDP).

a. Stability

It becomes difficult to change a software component when many other components depend on it. In order to change any property of this component, it is necessary to do so in accordance with all dependent components. Therefore, components that have a large number of dependent components are considered very stable.

4. The Stable Abstraction Principle

Some software in the system is not required to change very often. This type of software includes high-level architecture and policy decisions. That is, it is not preferred that such business and architectural decisions be temporary. Therefore, these softwares that contain the high-level policy decisions of the system should be included in the stable components.

However, this makes architecture inflexible. In such cases, by applying OCP, it is possible to create flexible and non-modification classes with the help of Abstract classes.

Stable Abstraction Principle (SAP) provides a relationship between stability and abstractness. On the one hand, it says that the stable component should be abstact, so it doesn’t prevent it from being extended, on the other hand, it says that the unstable component must be concrete and unstable, and also that concrete code should be easily modified.

--

--