|
The Lakos Level of a package is an indication of how high up it is
when the system is explored in a top-down manner: the topmost
packages are those specific to the application (often containing
the Main class, whereas low packages typically contain
utility classes.
Formally, the level of a package is defined as follows:
- A package that participates in a dependency cycle does not have
a level.
- A package that depends only on itself has level 0.
- A package has level 1 if it does not depend on another package that occurs
in the source.
- A package has level n+1 if it depends on a package that has
level n.
The above definition can assign multiple level values to the same
package; the Lakos level is the maximum of all those
values.
There is no recommended range for this metric; it gives guidance
on how to view the system in a top-down manner, and in what order
to explore packages.
This metric is named after John Lakos, as he first proposed it in
his book on large-scale design in C++.
Pre-packaged Query
Query name = "Semmle/Metrics/Packages/Coupling/Packages with high Lakos level"
Reports packages in the source that have a Lakos level higher than 3,
in descending order, as a bar chart.
from MetricPackage p, float c
where p.fromSource() and c = p.getLevel() and c > 3
select p, c order by c desc
.QL Source of Metric
This metric is generic, in the sense that it is defined in a separate class that is a super class both of MetricRefType and of
MetricPackage. Each of these subclasses override the
notion of dependency, in particular in MetricPackage
that specialized definition is:
MetricElement getADependency() {
exists(RefType t |
depends(this.getARefType(),t)
and
result = (MetricPackage) t.getPackage())
and
result != this
}
The generic definition of the level metric is as follows:
MetricElement getADependencySrc() {
result = this.getADependency() and result.fromSource()
}
/* get some level */
int getALevel() {
this.fromSource()
and
not(this.getADependencySrc+()=this)
and
( (not(exists(MetricElement t | t=this.getADependency()))
and
result=0)
or
(not(this.getADependency().fromSource())
and
result=1)
or
(result = this.getADependency().getALevel() + 1) )
}
/* getLevel returns John Lakos's level metric */
int getLevel() {
result = max(int d | d = this.getALevel())
}
Further Remarks
In other metrics tools, it is sometimes suggested that you use the
absence of a Lakos level to test for the existence of dependency
cycles. In .QL, it is much nicer to write a special query for that,
and some hints on how to do that can be found in the description
of Cyclic Package Dependencies.
References
John Lakos.
Large-scale C++ Software Design
Addison-Wesley, 1996.
Antranig Basman.
Levelization
Wiki Page, 2006.
Patrick Smacchia.
NDepend - Level metric
,
2006.
|