Lakos Level of a Type

The Lakos level of a type gives an indication of how "high" it is in the design of a system. For example, the Main classes usually are high up in this sense, whereas utility classes are lower. The metric is named after John Lakos, who introduced it in his book "Large-scale C++ software design".

One type depends t depends on another (different) type dep if t != dep and t makes use of dep in some way. For a further discussion of the precise definition of dependencies between types, please refer to the description of afferent coupling.

The level of a type is defined as follows. An element has no level defined if it is cyclically dependent on itself. Otherwise, it has level 0 of it does not depend on any other elements. It has level 1 if it does not directly depend on another element that occurs in the source. Finally, if it depends on another element at level n then it has level n+1.

This definition possibly assigns multiple levels to the same type. The Lakos level of a type is the maximum over all such levels.

There is no recommended value for the Lakos level; it is simply a means of exploration, typically when we wish to understand a design in a top-down manner. We then first explore the highest Lakos levels, and work our way down.

Pre-packaged Query

Query name = "Semmle/Metrics/Types/Coupling/Reftypes with high Lakos level"

Reports types with a Lakos level greater than 10, in descending order, as a bar chart.

from MetricRefType t, int n
where t.fromSource() and
      n = t.getLevel() and
      n > 10
select t,n order by n desc

.QL Source of Metric

The Lakos level is in fact defined for multiple kinds of program element, so there is a generic definition in MetricLevel, and the relevant notion of dependency is overridden in MetricRefType. First, that overriding is simply:

MetricElement getADependency() {
   depends(this,result) and this != result
}

That instantiates the generic definition in MetricElement, which itself reads as shown below. Note a small subtlety: we restrict ourselves to dependency cycles that occur in the source, rather than via some library.

  /* a dependency in the source */
  MetricElement getADependencySrc() {
      result = this.getADependency() and result.fromSource()
  }

  /* get some level value */
  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.

Digg!Reddit!Del.icio.us!Facebook!Slashdot!Technorati!StumbleUpon!Ma.gnolia!

Comments
Only registered users can write comments!
 
< Prev   Next >