Modularity Metrics And Microservices, Part 1
Modularity is "the degree to which a system's components are made up of relatively independent parts that can be combined." It is closely related to encapsulation, as it is a way of organizing encapsulated abstractions into physical modules.
Grady Booch says,” Make a module cohesive with an interface for minimal inter-module coupling. Teamwork, security, and documentation are Other considerations.” These modules can be called components that are deployment units, the smallest entity as part of software that can be deployed as Jar files or DLL files. These components must be cohesive and have a controlled coupling level to perform the final task. The cohesion and coupling roles described in the “Clean Architecture” book can be a practical guideline for applying healthy modularity in software.
Components' Cohesion
As modularity and encapsulation are tied closely together, the central question for drawing module borders is “Which classes belong in which components or modules?” the answer to this question should be based on the cohesion principles of the components, which are:
REP: The Reuse/Release Equivalence Principle
CCP: The Common Closure Principle
CRP: The Common Reuse Principle
REP: The Reuse/Release Equivalence Principle
A component cannot merely consist of a bunch of randomly selected classes with no rational relation among them; it means these classes should belong to a cohesive group that is releasable together. In other words, these classes share the same version number and release documentation. As a result, this collection of items in a component makes sense to the author and the users. It may seem a bit hard to measure the cohesion degree between component elements until a situation where breaking REP results in pain during the development or deployment process.
CCP: The Common Closure Principle
This principle emphasizes the components’ single responsibility, which means each component should not have multiple reasons for change, and there should be only one axis of change in a component. Most of the time, maintainability is more critical than reusability. A maintainability measure is the amount of work per deployment and release, so it is worth sacrificing some reusability to gather related classes with close relation into a single component at the cost of losing some reusability and gaining more maintainability. This principle tries to keep a family of related classes in a component to increase cohesion. As Robert C. Martin says, “Gather together those things that change at the same times and for the same reasons. Separate those things that change at different times or for different reasons."
CRP: The Common Reuse Principle
This principle states, “Don’t depend on things you don’t need, and don’t force users of a component to depend on things they don’t need.”
Classes part of the reusable abstraction are seldom reused in isolation; these highly dependent classes belong together in the same component. Besides, CRP tells us which classes should not be kept together in a component to avoid unnecessary dependencies between components and avoid wasting significant effort deploying a mesh of components without any reasonable relationship. CRP is more about which classes shouldn’t be together than which classes should be together; this principle says that classes not tightly bound to each other should not be in the same component.
Components' Coupling
Coupling and cohesion have been a twin since the early days of software development; these two evaluator principles help determine whether relations between software elements are safe. There are three coupling indices for the relationships between components. These principles are:
ADP: The Acyclic Dependencies Principle
SDP: The Stable Dependencies Principle
SAP: The Stable Abstractions Principle
ADP: The Acyclic Dependencies Principle
The dependency graph of components should have no cycles because these cycles result in a mess not only in build and compile time but also in deployment and runtime due to a cyclic relationship between packages. Some strategies for breaking down a cyclic path in a component graph include the Dependency inversion principle, Creating a new package, and moving the common dependencies there. The following images depict a cyclic dependency and the solution for eliminating it by creating a new component.
SDP: The Stable Dependencies Principle
Before exploring this principle, the meaning of “Stable” as a keyword should be clarified. A stable thing requires a more significant amount of work than usual to change or move. The more stable an element is, the more work and energy is needed to change it. So, when a component is stable, applying change requires much work, including changing other software parts. For instance, look at this diagram.
What if the “Component D” public services or interfaces get changed? How many other components may need to change subsequently? In the worst case, all other components may also be required to be changed. This means a change in “Component D” requires much work in compression with other components because it has many dependent components. Based on the definition of stability, “Component D” is the most stable component in this diagram.
According to "SDP", if a component is a place of change and changes frequently, it should not be a stable component. Each change results in a cascading change in other components. These components are unsafe to depend on and are located at the heart of the component dependency graph. The stability measure for an element can be quantized using the following formula:
In this formula, the number “Fout” shows the number of output edges from a component. This edge could be any connection between classes and interfaces, including Association, Generalization, Realization, and Dependency. Also, “Fin” shows input connections for a component. If I = 0, it indicates a maximally stable component, while I = 1 means a maximally unstable component. The following table shows the Instability and stability factors for the previous component diagram in this article.
SAP: The Stable Abstractions Principle
All parts of the software do not have the same level of impact on the whole system; some pieces contain the most important, either business or technical, critical elements, which we do not want to change frequently; their stability has competitive advantages for our product. The agility in changing these elements helps us cheaply align the business and technical decisions with changes in the business. As a result, the more stable a component is, the more abstract it should be. The abstraction means there is no concrete decision about a specific process or technology in the stable components; they are independent stem cells for your business. Only changes with business advantages should result in a change in these components. On the other hand, some components are subject to change, depending on the first category of components; they can be replaced and changed with no significant pain and rework. The abstraction level of a component can be measured using the following formula:
Na: The number of abstract classes and interfaces in the component.
Nc: The number of classes in the component.
A: Abstractness, this value would be a number between 0 and 1.
Adding SAP and SDP metrics results in a combined measure, which shows that the more stable a component is, the more abstract it should be. Such a component has a reasonable level of decoupling from other components that resist change propagation.
Modularity and Microservices
In the era of microservices, modularity and its metrics are still critical inside a microservice, but what about the entire system and the relationship between microservices? Could we apply the same metrics for the microservices and find the hot spots?
In the next part of this post, I will deep dive into this topic.







