Component principles

In this part we'll briefly introduce principles applied on component level. Components are units of deployment, for example .jar
files in Java.
Well designed components should have an ability to independently deploy and develop.
Component cohesion
These principles decides which classes should be grouped into components.
There are three of them:
- The Reuse/Release Equivalence Principle
- The Common Closure Principle
- The Common Reuse Principle
The Reuse/Release Equivalence Principle
This principle tells us that software components cannot be reused unless these components are tracked through a release process and given release numbers accordingly.
The Common Closure Principle
This is same principle as SRP applied on component level. The SRP says that there should be only one reason to change for a class. CCP tells us, that there should be only one reason for a component to change.
Purpose of this principle is to group together all classes that are likely to change for the same reasons. This should minimize the impact of particular changes on more than one component.
The Common Reuse Principle
CRP tells us that classes and modules that tend to be reused together belong in the same component. This also means that classes that have lots of dependencies on each other should be grouped into a component as a reusable abstraction.
It also tells us that if we depend on a component, we should depend on every class of the component. In a well designed component it should be impossible to depend on some classes of component, but not others. This is because changes in these independent parts of component would force unnecessary redeployments.
You may have noticed some similarities to ISP principle - it tells us to not depend on classes that have methods we don't use. The CRP insists that we don't depend on components that have classes we don't use.
Generically speaking:
Don't depend on things you don't need.
Tension Diagram for Component Cohesion
All three principles together form a relationship in which they fight each other. Result of this fight is a natural balance between them which depends on a lot of variables as we can see on picture below.

Component coupling
Component coupling principles propose how should we manage component relations.
There are also three principles:
- The Acyclic Dependencies Principle
- The Stable Dependencies Principle
- The Stable Abstractions Principle
The Acyclic Dependencies Principle
Allow no cycles in the component dependency graph
This principle solves the problem that occurs when our dependencies are frequently changing which can deal to problems trying to achieve a stable build, because our code can break anytime.
These components must work as a standalone units that can be a responsibility of particular developers or teams. Every standalone unit must be releasable without an impact on its dependencies. Therefore every release must be given a release number.
If one dependency is not yet prepared to use new release, it just keeps using the old one and integrate new releases when the team is ready, without breaking anything.
There is one condition that must be met if this can be achievable. If we picture the dependencies as a directed graph, there can be no cycles. Directed graph without cycles is called directed acyclic graph.
But what if we can't do it without a dependency cycle? There are two different approaches for breaking this cycle.
First one is to apply the Dependency Inversion Principle. That means to invert the edge that caused cycle in the first place by introducing an interface contract.
Another solution would be to introduce a whole new components that would depend on the components that caused the cycle.
This leads us to the conclusion that we simply can't design component structure upfront, but instead let it evolve with changing requirements.
Component dependency diagrams do not describe the intents of a system, but they map the buildability and maintainability of it.
Stable Dependencies Principle
Depend in the direction of stability.
Design cannot be completely static. There are cases when components are designed to be volatile, since it is expected to change.
Components like this should not have dependents that are difficult to change. This would make them difficult to change as well.
What does it mean for a component to be stable? It has nothing to do with its frequency of change, but instead how hard it is to make a change in it.
Components with a lot of dependents are very stable because all changes affect these dependents as well.


Luckily, we can measure stability of a component by counting classes from other components that depends on it and count of those that it depends on.
Instability of a component is: I = Fan-out / (Fan-in + Fan out).
I = 0 indicates maximally stable component and I = 1 maximally unstable.
The lesson there is that I should decrease in the direction of the dependencies. That means that stable components should not depend on unstable ones.
If a situation like that occurs, we can extract a stable interface contract and put it into new component, which would be maximally stable.
Stable Abstractions Principle
A component should be as abstract as it is stable.
Unstable components should contain only volatile software, because it is easy to change.
But there are cases, when we have very stable component that should be flexible for changes. A solution for this can be to apply the OCP which means to create stable abstract classes and adapt to changing requirements by extending its behavior by creating derivatives rather than modifying the class.
This principle tells us about a relation between stability and abstractness of a component.
It says that stable components should tent to be abstract, so we can extend behavior easily. On the other hand it is already easy to change unstable components, so its best suited for concrete components.
Abstraction of a class is a matter whether the class is abstract or not, but component can by partially abstract. We can measure this abstractness as a ratio of abstract classes to all classes in a component.

Main sequence is a line where stability is same as abstraction. We want our components to group around it.
There are also zones of exclusion, that has inadequate ratio between instability and abstractness.
The zone of pain contains components that are highly stable, but very concrete. It is called zone of pain because it is painful and hard to change and the concretion expects it to be flexible.
On the other hand non-volatile components can comfortably sit in the zone of pain. This graph only shows highly volatile components, so for example the String library can sit comfortably in the zone of pain.
On the other side there is the zone of uselessness. This is pretty straightforward because it contains abstract classes that has no dependents, which means it is not used, and therefore useless.