In a comment to this post,
Darrell suggested I describe where high factors of coupling are
appropriate. I’ll take it one step further and show you how to
use those factors to determine the stability of an assembly and
application, measure abstractness, and how to look at both to determine
how useful your assembly actually is.
Stability is measured by determining how easily you can change an
assembly without that change having impact on other assemblies within
An assembly with high afferent coupling (other assemblies depend on
it), which is a highly responsible assembly, is an assembly that has
lots of reuse throughout your application. These assemblies are
also, by design, typically the most stable assemblies in the
application because assemblies with a high level of responsibility to
other assemblies are difficult to change without impacting its
dependents. An example of a highly responsible assembly (high
afferent coupled assembly) would be an assembly that contains
business objects, because business objects get used throughout the
application, and if you change a business object, this has major impact
on the rest of the application.
An assembly with high efferent coupling (depends on other
assemblies), is an assembly that is highly dependent on other
assemblies in your application. These assemblies are OK with
being instable, because changing them doesn’t involved a great deal of
impact on other assemblies within the application. Highly
efferent coupled assemblies have little responsibility to the rest of
the application, but are highly dependent on the other
assemblies. GUI layer assemblies (code-behind assemblies in
Asp.Net) are a prime example of high efferent coupled, low afferent
So now that we understand where afferent and efferent coupling takes
place, how do you use that to figure out the instability of your
assemblies? Well, there is a formula for that:
I = Ce / (Ce + Ca)
- I = degree of instability of an assembly ranging from zero to one
- Zero indicates stability. One indicates instability.
- Ce = efferent coupling (outgoing dependencies)
- Ca = afferent coupling (incoming dependencies)
The closer I is to zero, the more stable and responsible the assembly is. This is an indication of more incoming dependencies (Ca) than outgoing dependencies (Ce). Again, stable packages are difficult to change without impacting the rest of the application. As I approaches one, this indicates a more instable, less responsible, more dependent, easier to change assembly.
So now, how do you make use of this? You’re going to
have assemblies that are both stable and instable in your
application. That’s the way things work. You’re goal, as a
developer, is to make an assembly as close to stable (I = 0) or instable (I
= 1) as possible, given the particular assembly’s role in your
application. You’ll goal isn’t actually to reach a value of zero
or one, but to get close to it.
In .Net, as in all OOP languages, we can use abstract classes to
increase the stability of an assembly. Abstract classes pull away
what a class is supposed to do from how its actually done, which is
handled in an inheriting class. Abstract classes are completely
stable classes themselves, and an assembly full of abstract types would
qualify as a completely stable assembly. Concrete classes do work
and do not necessarily define what work. Concrete classes
typically get the “what am I supposed to do” by inheriting from an
abstract class. The concrete class then implements the “this is
how to do that work”. Concrete classes are more instable, because
they encapsulate actual work and have less dependents/more dependencies.
So here’s the formula for determining the abstractness of an assembly:
A = Na / Nc
- A = abstractness of an assembly
- Zero is a completely concrete assembly. One is a completely abstract assembly.
- Na = number of abstract classes in the assembly
- Nc = number of concrete classes in the assembly
By taking the design metrics we have talked about, you can
determine just how useful your assembly is. If you have an
abstract assembly, but it is highly instable, you’ve really messed up
somewhere, because you have an assembly that doesn’t do any work, but
is highly dependent on other assemblies. That is a very useless
assembly. In constract, if you have a highly concrete assembly
that is also highly stable, you’re going to have a nightmare trying to
make changes to that assembly, because it is doing a lot of work, and
also is highly responsible to other assemblies in the application.
Last month I posted a few tools that analyze your assemblies and provide this information to you. Definately check these out and look at some of your code metrics to determine what kind of path you’re on and headed down.