Recently someone asked me why SDMetrics features hardly any cohesion measures “out of the box”, and only for packages, not for classes. In this post, we’ll look at the reasons for this apparent deficiency.
The first reason is a practical one: many proposed class cohesion measures can’t be applied to UML models. Class cohesion measures often look at how the methods of a class call each other, or access attributes of the class. This information pertains to the method implementation, and is rarely available in UML models.
The second reason is that overall cohesion measures tend not to be good quality indicators (cf. this survey of empirical studies). Possible causes are the construct validity of the measures, and the actual impact of cohesion on external software quality.
Construct validity
Construct validity asks the question: do we measure the concept we purport to measure? Cohesion is a semantic concept: the degree to which elements in a module are logically related, or belong together. Cohesion measures attempt to approximate this semantic concept using static criteria: how closely connected are the elements with each other?
Many cohesion measures are defined as a ratio of the actual number of connections between elements to the maximum possible number of such connections. Maximum cohesion is attained when every element is connected to every other element. But this situation is hardly desirable because then we also have maximum complexity. More advanced approaches take the transitive closure of connections into account, or look at connected components, edge connectivity, etc. But even then it is still not clear that this is a good approximation of “logical relatedness”.
Impact on external software quality
For size measures, it is fairly straightforward to deduce the impact on external software quality attributes. Each statement added to a method, or declaration added to a class, is an opportunity to get it wrong, and needs to be maintained in the future. So reliability and maintainability decrease with size. Same story for complexity or coupling measures. Each loop or condition added to a method is an invitation to introduce errors, and warrants one or more test cases. Each additional external resource used must be used correctly, and the program can’t run without the resource. Every time we add an artifact that contributes to size, complexity, or coupling, we pay a price.
For cohesion, the impact on system quality is not so immediate. We modified a class, and now three more pairs of methods have something in common – so what? I’m not saying that cohesion isn’t an important structural property. Far from it. Extracting a piece of functionality from some class X into a separate, new class Y to increase cohesion clearly has its benefits. For example, it is easier to reuse the functionality of class Y elsewhere, or plug in alternative implementations of class Y into class X. However, as long as there is no need to reuse class Y somewhere else, or plug in alternative implementations, the low cohesion of class X before the refactoring does not really hurt.
To summarize, cohesion measures are scarce in SDMetrics because
- UML models rarely contain the information needed to calculate the measures,
- cohesion measure may not be good approximations of the concept the purport to measure,
- low cohesion does not hurt as much as high coupling or complexity.