|
Relational Cohesion measures how well a package p hangs together.
That is, for each type in p we measure how many types within p
it depends on, and we take the average. To cater for the case
that there is only one type in the package (and then obviously
the package is quite cohesive!) we add 1 to the resulting average.
The recommended range for this metric is between 1.5 and 4.0:
too low a cohesion indicates that the package is a "kitchen sink"
containing too many unrelated types. On the other hand, a cohesion
that is too high indicates a package that is too complex, with
too many internal dependencies.
Pre-packaged Queries
Query name = "Semmle/Metrics/Packages/Cohesion/High cohesion packages"
Reports packages that have relational cohesion greater than 4,
in decreasing order, as a bar chart.
from MetricPackage p, float c
where p.fromSource() and c = p.relationalCohesion() and c > 4
select p, c order by c desc
Query name = "Semmle/Metrics/Packages/Cohesion/Low cohesion packages"
Reports packages with relational cohesion below 1.5, in
increasing order, as a bar chart.
from MetricPackage p, float c
where p.fromSource() and c = p.relationalCohesion() and c < 1.5
select p, c order by c
.QL Source of Metric
This metric is defined in MetricPackage:
float countDependencies(RefType t) {
t.getPackage()=this and
result = count(RefType s |
s.getPackage()=this
and
depends(t,s))
}
float relationalCohesion() {
result = 1+ avg(RefType t |
t.getPackage() = this |
this.countDependencies(t))
}
Variations
Our definition above agrees with most other metrics
tools such as NDepend.
Some modelling tools, for instance those of
Objecteering,
compute this metric not by counting types, but by counting the
different ways one type depends on another. By contrast,
the above definition only counts the number of other types one
type depends on.
The above definition has been written so that it is easy to
override the way in which dependencies are counted.
A special version of the depends(s,t) predicate not
only records the existence of dependencies between types
t and s,
but also the reason why t depends on s (as a string),
and a position that identifies that reason (such as a method call).
(For a full definition of depends, please refer to
the documentation of afferent coupling, which spells it out in detail.)
Using this special version of depends, we override our
previous definition to count the number of reasons for dependencies
rather than just the dependencies themselves.
class MyMetricPackage extends MetricPackage {
float countDependencies(RefType t) {
t.getPackage()=this and
result = count(Reason r |
exists(RefType s |
s.getPackage()=this and
depends(t,s,_,r)))
}
}
References
Robert C. Martin. OO Design Quality Metrics. October 24, 1994.
Robert C. Martin.
Agile Software Development, Principles, Patterns and Practices.
Addison Wesley, 2002.
Objecteering.
Class Category Relational Cohesion (CCRC)
,
2007.
SDMetrics.
Package metrics
,
2007.
Patrick Smacchia.
Relational Cohesion
,
2007.
|