There are different definitions of coupling types in software development, and each of these has a different perspective. There is one shared concept among the definitions though; Coupling in software is about the dependency relationship of modules. This leads us to the generic definition of coupling; “Coupling is the degree of interdependence between software modules …“1). Granted that, anyone who has dealt with coupling must have heard the widely known statement that it’s crucial to seek low coupling, and high cohesion between software modules to get a well structured, reliable, easy-to-change software. However, how can we know that our software design has the correct level of coupling? In order to answer this, first, we are going to revisit afferent coupling, efferent coupling concepts in this article. Secondly, we are going to explain the instability index concept, which relates these metrics to each other.
How to help your code base to stand the test of time using fan-in and fan-out metrics? A short revisit of afferent and efferent coupling metrics.
Afferent and Efferent Coupling as the Metrics of Coupling
A software quanta, -a module, a class, a component- is considered to be more stable if they have loose coupling to the other quanta in the system because it will remain undisturbed by the changes introduced to the others. The metrics afferent and efferent coupling, which were initially defined by Robert C. Martin in his books Agile Software Development, and Clean Architecture, help us understand the probability that a change in a software module will force a change in others. Similarly, they guide us to see the tendency of a module to be affected if an error in other modules of the system occurs.
Afferent Coupling – Fan-in
Afferent Coupling metric defines the number of modules that depend on a specific module. A module with a high fan-in value is likely to induce changes on the components which are dependent on it. On the other hand, the changes to the dependants are unlikely to induce changes to this component.
For instance, the PageUrlGenerator class in the above diagram has three first-level dependants, and four dependants in total so it’s said to have a high afferent coupling.
As we mentioned before, components with high afferent coupling have smaller chances of being affected by the changes introduced to its dependants, therefore; these components are also called “stable components“. When we see a module (component etc.) with high fan-in coupling, we can also assume that the code reuse is high from the perspective of that module.
Relying on these statements, one might instinctively think that high fan-in value is always a good thing. While this may be true in most of the cases, consider a “stable“ component which depends on a highly flexible component, what happens in this case? Alternatively, assume that we have another so-called “stable” component with a high fan-in value that tries to handle many responsibilities; in fact, it acts as a swiss army knife. Can we confidently say that we did a good job in either of these cases? Absolutely, no! We will elaborate on this after we define the Efferent Coupling metric and the Instability Index.
Efferent Coupling – Fan-out
Efferent coupling, on the other hand, defines the number of components on which a certain component depends. Components with high efferent coupling value are sensitive to the changes that are introduced to their dependencies. In addition, the deficiencies of their dependencies naturally manifest themselves in these components.
As an illustration, let’s focus on the LiveUrlGenerator class in the above; this class extends the GenericViewUrlGenerator class and has “has-a” relation to the classes MarketingAgentUrlGenerator__ and LoginRedirectUrlGenerator. If any of its dependencies undergoes a change, this class needs to adapt to it as well. Similarly, if a bug manifests itself in one of these dependencies, LiveUrlGenerator suffers from it, too. Therefore, we call such kind of components “unstable“.
This leads to another question:
-Should we try to avoid high fan-out value all the time? -No!
In fact, some components need to be “unstable” (or flexible) by nature. For instance, consider a microservices service of the form “Backend for Frontend” which uses some other downstream services to collect and orchestrate the information that the frontend application will need. If we try to reduce the fan-out metric of such a component, we might end up either with a completely irresponsible component that does nothing or overly responsible component that tries to do everything (see also: coincidental cohesion, death star antipattern). That is to say, whether it’s fan-in or fan-out coupling is inevitable, -actually mandatory-, however; what is the correct level or style of coupling? We will try to explain this after touching on the concept “instability index”.
The instability index relates fan-out coupling to the total incoming/outgoing coupling of the system with the formula:
The instability index ranges between [0,1]. If the value is tending towards 0 then the component is heading to maximal stability. The value 1, on the other hand, indicates maximum instability.
What is the correct level of instability?
We can answer this question with the famous software consultant reply: “it depends!”. It depends because the role of the component within the architectural constellation might require that component to be flexible, or as stable as possible. The goal, in general, is not to have individually stable components all over the system, but rather to have a stable system that is capable of responding to change in a seamless, adaptive manner. This leads us to the “Stable Dependencies Principle“.
The “Stable Dependencies Principle” states that:
The instability metric of a component should be larger than the instability metrics of the component that it depends on. That is, the instability metrics should decrease in the direction of dependency. (See 3), Chapter 14)
How to check the stability of a system?
Luckily, there are libraries that ease implementation of such kind of architectural wellness checks; JDepend for java, NDepend for -. Net, PDepend for PHP are a few examples. In addition, there many static code analysis tools like Checkstyle, that make use of such libraries to provide configurable utilities to handle such concerns effortlessly.
Who writes here?
"Offering a supportive and liberal environment combined with 20+ years grown business, at Mercateo I can reflect on my experience on different levels of software development.” Hasan Çomak is an IT-professional and software engineer who contributed to many software projects in diverse industries. He is interested in evolutionary software architectures and enjoys transforming software systems into a highly resilient, flexible state.