Improving architectural maintainability
Ever noticed that objects that have a lot of dependencies on other objects become somewhat brittle? If one of their dependencies changes, does the object itself break, man? Ever noticed the opposite? Have you over observed objects that every other object in a system depends on have the tendency to create issues elsewhere when they’ve changed? (Interestingly, this tendency to create issues elsewhere is commonly referred to as the “Collateral Damage†effect.)
There are a series of hip coupling metrics that are known as Afferent Coupling and Efferent Coupling (or sometimes referred to as Fan Out and Fan In). These integer based metrics represent a count of objects that correspond to coupling to another object. Both Afferent Coupling and Efferent Coupling signify an architectural maintenance issue: either an object has too much responsibility (high Afferent Coupling) or the object isn’t independent enough (high Efferent Coupling).
Interestingly, these types of dependency metrics can be extremely helpful in determining the risk in maintaining a code base. Objects or namespaces/packages with too much responsibly present dangerous situations when those objects need to be changed. If, some how, their behavior changes, other objects within a software system may stop functioning as indented. Objects that are highly dependent on other objects present brittleness in the face of change- they too may stop functioning as indented if one of their imported objects changes, even in subtle ways.
What’s more, both Afferent and Efferent Coupling can be combined to form an “instability†ratio. For example, the following smokin’ equation can represent an object’s (or namespace/package’s) level of instability in the face of change: a value of one is completely instable, while a value of zero is stable.
![]()
This Instability metric can apply to objects or packages/namespaces as well.
NDepend for the .NET platform is a trippin’ open source project, which reports Efferent Coupling, Afferent Coupling, Instability and a number of other interesting architectural metrics. These metrics are reported by Assembly and by class. The tool is easily executed via NAnt and produces reports in both XML and HTML formats.
For example, the following HTML report displays metrics for a .NET assembly, which in this case is the NUnit framework.
Note how the nunit.framework assembly has an Afferent Coupling of 140 and an Efferent Coupling of 0. This means that this is the core code of the NUnit framework (if you couldn’t figure that out by its name); however, this also means this code can’t change easily. Hence, the Instability value for this assembly is zero- because so many other objects depend on this core code there is a natural tendency for this code not to change without something breaking quickly.
On the other hand, note the nunit.tests assembly. NDepend reported a Efferent Coupling value of 76 and an Afferent Coupling value of 0; therefore, the Instability is 1 or unstable- this makes sense- anytime code changes, tests usually break (if they don’t, by the way, there could be issues with those tests).
Understanding these metrics for one’s code base can have dramatic effects on maintainability. For instance, assemblies with high Afferent Coupling should have a high degree of associated tests to ensure proper functionality. If a lot of code is dependent on that assembly, wouldn’t you want to guarantee it is reliable? Also too, evaluating the long term implications of Afferent Coupling could drive teams to decide to break assemblies into smaller more malleable chunks of code.
On the other hand, assemblies with a high Efferent Coupling are subject to breakage easily. Again, having a copasetic amount of code coverage regarding these assemblies will help teams spot troubles quickly.
In a Continuous Integration environment, monitoring these values over time can enable development teams to make corresponding changes rapidly before things get out of control. If during a series of builds the Afferent Coupling of an assembly grows rapidly, the following measures can be taken:
- Teams could ensure an equal velocity of tests are being constructed to combat any associated risks
- Teams could evaluate the long term implications of any associated brittleness that may occur from a high coupling value
- Perhaps assemblies could be further broken up to enable change in future iterations
In addition to NDepend for .NET, JDepend is a similar open source project for the Java platform, which reports coupling metrics by package. JDepend can be run via Ant or Maven and also produces reports in XML and HTML formats.
Architectural coupling metrics can effectively spot long term maintenance issues for a code base by reporting assembly/package or object couplings. These metrics can provide insights into any associated risks in the face of change. What’s more, monitoring these metrics on a regular basis in a Continuous Integration environment effectively brings these risks to light before they become maintenance nightmares. Dig it?
| Related odds and ends | ||
|---|---|---|
Tuesday 14 Mar 2006 | Code Metrics, Continuous Integration, Developer Testing
Side by side metrics?
Greetings,
Great post about these tools. These tools are really good, but the practice is left unfished if there is no mechanism for side-by-side comparison between revisions. Do you know of any tools that can accomplish this?
For example, we are using Subversion for source control and I cannot find any good tool that can give me so much as a simple Lines Changed / Lines Added / Lines Deleted report for two given revisions.
That would be a great start, but being able to use something like NDepend or one of these other tools to line up the stats between one version of a project and another and show the measure of improvement or worse, regression, between the two would be nothing short of amazing.
Yes, there is a tool which will allow side by side comparisons of these metrics. Check out Convergence and watch this (dated) demo (features the Java edition, however, the .NET edition has the similar features).
[...] I tend to categorize Afferent and Efferent coupling as Maintenance metrics, meaning that these two copasetic metrics, in collaboration with Instability, Abstractness and coverage facilitate understanding how change will affect aspects of an architecture. One thing about metrics, though, is that they are only marginally useful as one time measurements. Real value comes from watching metrics over time and noticing trends. Once a baseline has been established (say for code coverage), then you can set goals and work to achieve them (like ensuring coverage doesn’t precipitously drop). [...]