Miscellaneous object-oriented metrics

See also Object-oriented metrics

Simple class-level OO metrics

IMPL Number of interfaces implemented by class Counts the number of Implements statements. A class may implement either another class (VB Classic) or an interface definition.
WMCnp Non-private methods defined by class This is the same as WMC but Private methods are ignored.
WMCi Methods defined and inherited by class This is the same as WMC but all inherited methods are also counted.
VARS Variables defined by class Number of variables and arrays defined at the class-level. Inherited and procedure-level variables are not counted.
VARSnp Non-private variables defined by class The same as VARS, but Private variables are excluded.
VARSi Variables defined and inherited by class The same as VARS, but inherited variables are included.
EVENTS Events defined by class Number of Event statements (event definitions) in a class. Inherited events and event handlers are not counted.
CTORS Constructors defined by class Number of constructors (Sub New) in a class. Class_Initialize in VB Classic is an event handler, and not counted in CTORS.
CSZ Class size Number of methods + variables defined by class. CSZ = WMC + VARS. Measures the size of the class in terms of operations and data.
CIS Class interface size Number of non-private methods + variables defined by class. CIS = WMCnp + VARSnp. Measures the size of the interface from other parts of the system to the class.

Class hierarchy metrics

The following metrics provide key figures for the entire class hierarchy. These metrics are counted from source classes and interfaces, thus any binary classes or interfaces are not included. They are available if the analysis found at least one class or interface.

CLS Number of classes If zero, no OO metrics are meaningful.
CLSa Number of abstract classes Number of abstract classes defined in project. See below for definition.
CLSc Number of concrete classes Number of concrete classes defined in project. A concrete class is one that is not abstract. CLSc = CLS − CLSa
ROOTS Number of root classes Number of distinct class hierarchies. See below for definition and discussion.
LEAFS Number of leaf classes A leaf class is one that other classes don't inherit from.
INTERFS Number of interfaces Number of .NET Interfaces. Abstract classes are not counted as interfaces even though they can be thought of as interfaces.
maxDIT Maximum depth of inheritance tree See DIT. maxDIT should not exceed 6.

CLSa Number of abstract classes

An abstract class is a class that is not designed for instantiation at run-time. A concrete class is the opposite of an abstract class.

In VB.NET, an abstract class is declared with the MustInherit keyword.

In VB Classic, we have to approximate. There is no specific syntax to define an abstract class. However, abstract classes do exist: they are skeleton base classes used with the Implements statement. The following conditions need to be true for a .cls file to be counted in CLSa.

  1. Other class(es) implement this class via Implements.
  2. Class has no Private variables, no Private Declare statements, and no Private/Friend methods (Sub/Function) or properties.
  3. Class has some Public methods, properties or variables.
  4. A majority of the Public methods/properties are empty, indicating a skeleton class.
  5. As a special case, empty implemented classes are abstract. This happens when #1 and #2 are True but #3 is False.

Because this definition is mechanical, CLSa may look too high or too low. It cannot take the intended future use into account. For example, a defined base class that is not yet used via Implements is not counted in CLSa. A class used both in an abstract and a concrete way (both Implemented and instantiated) may or may not be counted in CLSa, depending on whether the above rules apply or not.

ROOTS Number of root classes

ROOTS is the number of root classes defined in source code. It equals the number of class hierarchies defined entirely in source code.

VB Classic doesn't offer implementation inheritance. Thus, each class is a root class and ROOTS=CLS.

For .NET systems, a root class is one that inherits directly from System.Object (or has no Inherits statement). A class that derives from any other class is not counted as a root. ROOTS can well be zero. This happens when all available classes derive from the .NET framework classes. 0 <= ROOTS <= CLS

Ideally, all classes belong to a single hierarchy, they derive from a single root and ROOTS=1. Theoretically speaking, all classes and structures in .NET derive from System.Object and there is always just one class hierarchy. We have defined ROOTS in a more practical way: it equals the number of class hierarchies that are fully defined in source code.

Class Reuse and Specialization

Class Reuse and Specialization ratios are metrics for the class inheritance tree.

Reuse ratio U = superclasses / classes
U = (CLS − LEAFS) / CLS

Specialization ratio S = subclasses / superclasses
S = (CLS − ROOTS) / (CLS − LEAFS)

A superclass is a class that is not a leaf class.
A subclass is a class that is not a root class.

U measures reuse via inheritance. A high U indicates a deep class hierarchy with high reuse. In other words, U is the percentage of classes that are derived from. Reuse ratio varies in the range 0 <= U < 1. When U=0, there is no inheritance. As U approaches 1, the inheritance tree deepens in a chain form with exactly one root and one leaf.

S measures the width of the inheritance tree. The higher S, the wider the class hierarchy. In other words, S is the average number of derived classes for each base class. When inheritance is used, S >= 1. The deepest and narrowest inheritance tree happens when S=1 (chain form tree with exactly one root and one leaf). A higher value indicates a wider tree. There is no absolute maximum value.

If there are no classes, no inheritance or no root class, U=0. In this case, S is undefined and displayed as zero.

A deep hierarchy (high U and low S) is usually preferred over a wide hierarcy.

Readings

MPC Message-Passing Coupling

MPC measures how dependent a class implementation is on methods of other classes. It is related to the complexity of message passing among classes. MPC equals the number of messages sent out from a class, that is, the number of procedure calls.

MPC = number of send statements defined in a class

MPC was proposed separately by Li & Henry and Lorenz & Kidd. MPC equals the number of procedure calls originating from a method in the class and going to other classes. Every call is counted as many times as it exists in the code. A polymorphic call is counted as one call regardless of how many procedures it may go to at run-time.

Implementation details

MPC is calculated for classes. It includes calls to all subs, functions and properties, whether in classes or other modules. Calls to property Set, Let and Get are all counted separately. Calls to VB library functions, such as print, are not counted. Calls to declared external API procedures are counted. Dead methods and their callees are included in the measure. Although these calls are not executed at the moment, they could become live by a change in the code. In VB, a polymorphic call can result from an Overrides, Overloads or Implements statement, or from late binding. In these cases, MPC is increased by one regardless of the number of possible targets. Only such calls are counted for which at least one target is detected. Unresolved calls are not counted. If the analysis of late binding is turned off, late-bound calls are not detected nor included in MPC.

Readings

Other class-level metrics

Lines of code and statement count metrics are also reported for classes. A VB.NET class starts at the class header line and ends in End Class.

TCC Total cyclomatic complexity is provided for each class.

See also Object-oriented metrics

© Project Analyzer Help