Published June 7, 2020
by Doug Klugh
Design your software in such a way that any given component depends on other components that are more stable than it is. In other words, the dependencies within a component architecture should be pointing in the direction of increasing stability. This will ensure that components that need to change frequently will be easy to change and that the stable components that others depend on will not change nearly as often.
This Principle of Component Coupling will enhance the flexibility of your software by making frequent changes much easier. It also helps to isolate functionality that other part of the system depend upon — helping to minimize the impact of changes. This promotes a loosely coupled architecture and is achieved through effective dependency management.
When building components, would you rather depend on a component that is stable or on one that is unstable? In other words, would you rather depend on something that is hard to change (i.e. stable) or something that is easy to change (i.e. unstable)?
If you give it enough thought, you will probably come to the conclusion that you want to depend on a component that is hard to change. Because every time it changes, that means more work for you. By following the economy of change, you want to depend on a component that is so hard to change that it causes them more pain to change it than it does you. You want all those components you depend on to change as infrequently as possible.
So what makes a component stable? A component could be hard to change for a number of reasons, such as being highly complex, poorly written, or just really big. But in reality, the stability of a component comes down to its dependency structure.
In figure 1 below, component S has several incoming dependencies from components that depend upon it. This is referred to as Afferent Coupling, which is easily remembered as Fan In. If you have to modify component S, you will need to make sure you're not breaking any of the other components that depend on it — and that is hard to do, which makes this component hard to change. Therefore, component S is stable.
In figure 2 below, component I has several outgoing dependencies on other components. This is referred to as Efferent Coupling, which is easily remembered as Fan Out. There are no incoming dependencies to keep component I from changing and there are several outgoing dependencies that are likely to make it change. This component is easy to change and is likely to change. Therefore, component I is instable.
In figure 3 below, S is a stable component with a lot of incoming dependencies that is hard to change, while EZ starts off as an instable component that is easy to change. But if component S references component EZ, EZ will suddenly have five components that depend upon it, making it stable and hence hard to change. A change to component EZ will cause all of those five other components to be recompiled and redeployed.
This is where care is often needed. By simply referencing component EZ, any developer can ruin the maintenance characteristics of that component, while introducing rigidity into the system.
We want certain components to be instable because that is where we want to put the code that changes frequently. Stable components are hard to change, so that is not where we want to put code that changes often.