Lack of Cohesion of Methods of a Type (Henderson-Sellers)

The aim of this metric is to try and determine whether a class represents one abstraction (good) or multiple abstractions (bad). If a class represents multiple abstractions, it should be split up into multiple classes. The correct way to measure this property is a matter of hot debate among software metrics experts, so SemmleCode provides two ways of doing it: one due to Henderson-Sellers (described below), and another one due to Chidamber and Kemerer.

The intuition underlying the Henderson-Sellers method of calculating Lack of Cohesion of Methods (LCOM) is that in a cohesive class C, many methods access the same fields of C. Formally, let

  • M = set of methods in class
  • F = set of fields in class
  • r(f) = number of methods that access field f
  • ar = mean of r(f) over f in F

We then define LCOM of the class under consideration to be

LCOM = (ar - |M|) / (1 - |M|)

We follow Lance Walton (author of the State of Flow Eclipse Metrics Plugin) in restricting M to methods that read some field in the same class, and F to fields that are read by some method in the same class.

A value greater than 0.9 indicates a class that may deserve some further scrutiny.

Pre-packaged Query

Query name = "Semmle/Metrics/Types/Cohesion/Reftypes that lack cohesion of methods (LCOM) in the Henderson-Sellers sense"

Reports reftypes that have lack of cohesion greater than 0.9, in decreasing order.

from MetricRefType t, float loc
where loc = t.getLackOfCohesionHS() and loc > 0.9
select t, loc order by loc desc

.QL Source of Metric

This metric is defined in class MetricRefType.

  // does m access field f defined in the same type?
  predicate accessesLocalField(Method m,Field f) {
    m.accesses(f) and 
    m.getDeclaringType() = this and
    f.getDeclaringType() = this
  }
     
  // returns any method that accesses some local field
  Method getAccessingMethod() {
     exists(Field f | this.accessesLocalField(result,f))
  }

  // returns any field that is accessed by a local method
  Field getAccessedField() {
     exists(Method m | this.accessesLocalField(m,result))
  }

  // compute Henderson-Sellers lack of cohesion metric
  float getLackOfCohesionHS()  {
     exists(int m, float r |
        // m = number of methods that access some field
        m = count(this.getAccessingMethod())
        and
        // r = average (over f) of number of methods that access field f
        r = avg(Field f |
                  f = this.getAccessedField() |
                  count(Method x | this.accessesLocalField(x,f)))
        and
        // avoid division by zero
        m != 1
        and
        // compute LCOM
        result = ((r-m)/(1-m))
     )
  }

Criticisms and Variations

The definition of the metric does not distinguish between static methods and instance methods, or between static fields and instance fields. Indeed, the Metrics 1.3.6 Eclipse Plugin provides an option for disregarding static fields and static methods.

To program that option in .QL, we define a new class of our own that overrides the accessLocalField predicate.

class MyMetricRefType extends MetricRefType {
   predicate accessesLocalField(Method m,Field f) {
     super.accessesLocalField(m,f) and
     not(m.hasModifier("static")) and
     not(f.hasModifier("static"))
  }
}

Another criticism is that the metric discourages the use of getter and setter methods: surely these should could as field accesses just the same. Again that variation is easily coded by overriding the accessesLocalField predicate. In fact, arguably any direct call to a method that accesses a local field should count as an access. Hence we define:

class MyMetricRefType2 extends MetricRefType {
   predicate accessesLocalField(Method m,Field f) {
     super.accessesLocalField(m,f)
     or
     exists(Method n | 
         m.getACall() = n and
         n.getDeclaringType() = this and
         super.accessesLocalField(n,f)) 
  }
}

from MyMetricRefType2 t, float loc
where t.fromSource() and 
      loc = t.getLackOfCohesionHS() and 
      loc > 0.9
select t, loc order by loc desc

References

Brian Henderson-Sellers. Object-Oriented Metrics: Measures of Complexity. Prentice-Hall 1996.

Frank Sauer. Metrics 1.3.6 - Getting Started. 2005.

Renaat Verbruggen. Object-oriented patterns and metrics (Lecture Notes). (updated regularly)

Lance Walton. Eclipse Metrics Plugin. State of Flow, 2005.

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

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