|
Strictly speaking not a metric, this set of definitions and
queries provides a means for identifying cycles in dependencies
between packages, and for exploring them in depth.
One package p depends on another package q
if p contains a type s that depends on a type t in q.
For a detailed discussion of the notion of dependencies between
types, please consult the discussion of
afferent coupling.
Pre-packaged Queries
Name of query = "Semmle/Metrics/Packages/Coupling/Determine packages that cyclically depend on one another"
This reports strongly connected components in the dependency graph of packages. For each such component, it reports a representative element (the package with the lexicographically minimal name) and the size of the component. Underneath this initial description in the tree view, you will find a list of all the elements of a component.
from MetricPackage p
where p.getCycleSize() > 1 and p.isRepresentative()
select "SCC of size " + p.getCycleSize().toString() + " for " + p.getName() as s,
p.getACycleMember()
order by s desc
Query name = "Semmle/Metrics/Packages/Coupling/Cyclic packages with exploration"
While the above query is useful in identifying the existence of
cycles between packages, it is sometimes hard to get at the
cause of such cycles. The query below helps to drill down into
such cases: it reports the cycles, but then for each cycle member, it lists the dependencies on other packages. Furthermore, for each such
pair, it gives an explanation of the reasons why the first package depends on the second, both in words (as a string), and as a location you can click on to take you to the relevant source location.
from MetricPackage p, // representative of cycle
MetricPackage q1, // cycle member
MetricPackage q2, // another cycle member
RefType s, // a type in q1
RefType t, // a type in q2
string reason, // why s depends on t
Reason click // locatable for inspecting the reason
where p.fromSource() and q1.fromSource() and q2.fromSource() and
p.isRepresentative() and
q1 = p.getACycleMember() and
q2 = p.getACycleMember() and
q1 != q2 and
s = q1.getARefType() and
t = q2.getARefType() and
depends(s,t,reason,click)
select "SCC of size " + p.getCycleSize().toString() +
" for " + p.getName() as name,
q1,q2,
"explanation", // show why q1 depends on q2
q1,s, // q1 contains a type s
q2,t, // that depends on t in q2
reason,click // report reason
order by name desc
.QL Source
The auxiliary methods for finding cycles and for exploring them
are defined in MetricPackage:
MetricPackage getACycleMember() {
result.getADependency*() = this
and
this.getADependency*() = result
}
int getCycleSize() {
result = count(this.getACycleMember())
}
predicate isRepresentative() {
this.getName() = min(MetricPackage p |
p = this.getACycleMember() |
p.getName())
}
References
Chris Chedgey.
Emergent Package Design: cyclic package dependencies
.
About: Focus on Java, 2007.
Robert C. Martin. OO Design Quality Metrics. October 24, 1994.
Robert C. Martin.
Agile Software Development, Principles, Patterns and Practices.
Addison Wesley, 2002.
Glen Wilcox.
Managing your dependencies with JDepend
.
O'Reilly OnJava.com, 2004.
|