VBDepend Metrics

Metrics Definition


To learn metrics, you can print this Placemat Visualization Expert by Stuart Celarier MVP (Corillian) or you can print this Metrics Cheat Sheet by Frank-Leonardo Quednau'


Metrics on Application

NbLinesOfCode

Notice that the LOC for a type is the sum of its methods’ LOC, the LOC for a namespace is the sum of its types’ LOC, the LOC for an project is the sum of its types’ LOC and the LOC for an application is the sum of its projects LOC. Here are some observations:

  • Abstract methods and enumerations have a LOC equals to 0. Only concrete code that is effectively executed is considered when computing LOC.
  • Types, fields and methods declarations are not considered as line of code because they don’t have corresponding sequence points.

Recommendations:
Methods where NbLinesOfCode is higher than 20 are hard to understand and maintain.

Related Links:
Why is it useful to count the number of Lines Of Code (LOC) ?
How do you count your number of Lines Of Code (LOC) ?

NbLinesOfComments

Defined for application, projects, types, methods

Recommendations:
This metric is not helpful to asses the quality of source code. We prefer to use the metric PercentageComment.

PercentageComment

Defined for application, projects, types, methods

PercentageComment = 100*NbLinesOfComment / ( NbLinesOfComment + NbLinesOfCode)

Recommendations:
Code where the percentage of comment is lower than 20% should be more commented. However overly commented code (>40%) is not necessarily a blessing as it can be considered as an insult to the intelligence of the reader. Guidelines about code commenting can be found here.

NbProjects

Defined for application - The number of projects.

NbTypes

Defined for application, projects. The number of types. A type can be an abstract or a concrete class, a structure, an enumeration.

NbMethods

Defined for application, projects, types. The number of methods. A method can be an abstract, virtual or non-virtual method, a method declared in an interface, a constructor, a class constructor, a finalizer, a property/indexer getter or setter, an event adder or remover.

Recommendations:
Types where NbMethods > 20 might be hard to understand and maintain but there might be cases where it is relevant to have a high value for NbMethods.

NbFields

Defined for application, projects, types. The number of fields.

Recommendations:
Types where NbFields is higher 20 might be hard to understand and maintain but there might be cases where it is relevant to have a high value for NbFields.

Go to top


Metrics on Projects

By measuring coupling between types of your application, VBDepend assesses the stability of each project. A project is considered stable if its types are used by a lot of types of tier projects (i.e stable = painful to modify). If a project contains many abstract types and few concrete types, it is considered as abstract. Thus, VBDepend helps you detect which projects are potentially painful to maintain (i.e concrete and stable) and which projects are potentially useless (i.e abstract and instable).

Note:
This theory and metrics have been first introduced by the excellent book Agile Software Development: Principles, Patterns, and Practices in C# Robert C. Martin (Prentice Hall PTR, 2006)

Afferent coupling (Ca)

The number of types outside this project that depend on types within this project. High afferent coupling indicates that the concerned projects have many responsibilities.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Efferent coupling (Ce)

The number of types inside this project that depends on types outside this project. High efferent coupling indicates that the concerned project is dependant.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Relational Cohesion (H)

Average number of internal relationships per type. Let R be the number of type relationships that are internal to this project (i.e that do not connect to types outside the project). Let N be the number of types within the project. H = (R + 1)/ N. The extra 1 in the formula prevents H=0 when N=1. The relational cohesion represents the relationship that this project has to all its types.

Recommendations:
As classes inside an project should be strongly related, the cohesion should be high. On the other hand, too high values may indicate over-coupling. A good range for RelationalCohesion is 1.5 to 4.0. Projects where RelationalCohesion < 1.5 or RelationalCohesion > 4.0 might be problematic.

Instability (I)

The ratio of efferent coupling (Ce) to total coupling. I = Ce / (Ce + Ca). This metric is an indicator of the package's resilience to change. The range for this metric is 0 to 1, with I=0 indicating a completely stable package and I=1 indicating a completely instable package.

Abstractness (A)

The ratio of the number of internal abstract types to the number of types. The range for this metric is 0 to 1, with A=0 indicating a completely concrete project and A=1 indicating a completely abstract project.

Distance from main sequence (D)

The perpendicular normalized distance of an project from the idealized line A + I = 1 (called main sequence). This metric is an indicator of the project's balance between abstractness and stability. An project squarely on the main sequence is optimally balanced with respect to its abstractness and stability. Ideal projects are either completely abstract and stable (I=0, A=1) or completely concrete and instable (I=1, A=0). The range for this metric is 0 to 1, with D=0 indicating an project that is coincident with the main sequence and D=1 indicating an project that is as far from the main sequence as possible. The picture in the report reveals if an project is in the zone of pain (I and A both close to 0) or in the zone of uselessness (I and A both close to 1).

Recommendations:
Projects where NormDistFromMainSeq is higher than 0.7 might be problematic. However, in the real world it is very hard to avoid such projects. Therefore, you should allow a small percentage of your projects to violate this CQLinq constraint: WARN IF Percentage > 15 IN SELECT PROJECTS WHERE NormDistFromMainSeq > 0.7

Go to top


Metrics on Types

Type rank

TypeRank values are computed by applying the Google PageRank algorithm on the graph of types' dependencies. A homothety of center 0.15 is applied to make it so that the average of TypeRank is 1.

Recommendations:
Types with high TypeRank should be more carefully tested because bugs in such types will likely be more catastrophic.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Afferent Coupling at type level (Ca)

The Afferent Coupling for a particular type is the number of types that depends directly on it.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Efferent Coupling at type level (Ce)

The Efferent Coupling for a particular type is the number of types it directly depends on. Notice that types declared in framework projects are taken into account.

Recommendations:
Types where TypeCe > 50 are types that depends on too many other types. They are complex and have more than one responsability. They are good candidate for refactoring.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Lack of Cohesion Of Methods (LCOM)

The single responsibility principle states that a class should not have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class. There are several LCOM metrics. The LCOM takes its values in the range [0-1]. The LCOM HS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. A LCOM HS value highest than 1 should be considered alarming. Here are algorithms used by VBDepend to compute LCOM metrics:

  • LCOM = 1 – (sum(MF)/M*F)
  • LCOM HS = (M – sum(MF)/F)(M-1)
  • Where:
  • M is the number of methods in class (both static and instance methods are counted, it includes also constructors, properties getters/setters, events add/remove methods).
  • F is the number of instance fields in the class.
  • MF is the number of methods of the class accessing a particular instance field.
  • Sum(MF) is the sum of MF over all instance fields of the class.
The underlying idea behind these formulas can be stated as follow: a class is utterly cohesive if all its methods use all its instance fields, which means that sum(MF)=M*F and then LCOM = 0 and LCOMHS = 0.

Recommendations:
Types where LCOM > 0.8 and NbFields > 10 and NbMethods >10 might be problematic. However, it is very hard to avoid such non-cohesive types. Types where LCOMHS > 1.0 and NbFields > 10 and NbMethods >10 should be avoided. Note that this constraint is stronger (and thus easier to satisfy) than the constraint types where LCOM > 0.8 and NbFields > 10 and NbMethods >10.

Cyclomatic Complexity (CC)

Defined for types, methods. Cyclomatic complexity is a popular procedural software metric equal to the number of decisions that can be taken in a procedure. Concretely, in C++ the CC of a method is 1 + {the number of following expressions found in the body of the method}:

if | while | for | case | default | continue | goto | && | || | catch | ternary operator ?: | ??

Following expressions are not counted for CC computation:

else | do | switch | try | using | throw | finally | return | object creation | method call | field access

Adapted to the OO world, this metric is defined both on methods and classes/structures (as the sum of its methods CC). Notice that the CC of an anonymous method is not counted when computing the CC of its outer method.

Recommendations:
Methods where CC is higher than 15 are hard to understand and maintain. Methods where CC is higher than 30 are extremely complex and should be split in smaller methods (except if they are automatically generated by a tool.)

Size of instance

Defined for instance fields and types. The size of instances of an instance field is defined as the size, in bytes, of instances of its type. The size of instance of a static field is equal to 0.

The size of instances of a class or a structure is defined as the sum of size of instances of its fields plus the size of instances of its base class.

Fields of reference types (class, interface, delegate…) always count for 4 bytes while the footprint of fields of value types (structure, int, byte, double…) might vary.

Size of instances of an enumeration is equal to the size of instances of the underlying numeric primitive type. It is computed from the value__ instance field (all enumerations have such a field when compiled in IL).

Size of instances of generic types might be erroneous because we can’t statically know the footprint of parameter types (except when they have the class constraint).

Recommendations:
Types where SizeOfInst is higher than 64 might degrade performance (depending on the number of instances created at runtime) and might be hard to maintain. However it is not a rule since sometime there is no alternative (the size of instances of the System.Net.NetworkInformation.SystemIcmpV6Statistics framework class is 2064 bytes).

Non-static and non-generic types where SizeOfInst is higher than 0 indicate stateless types that might eventually be turned into static classes.

Association Between Class (ABC)

The Association Between Classes metric for a particular class or structure is the number of members of others types it directly uses in the body of its methods.

Number of Children (NOC)

The number of children for a class is the number of sub-classes (whatever their positions in the sub branch of the inheritance tree). The number of children for an interface is the number of types that implement it. In both cases the computation of this metric only count types declared in the application code and thus, doesn't take account of types declared in tiers projects.

Depth of Inheritance Tree (DIT)

The Depth of Inheritance Tree for a class or a structure is its number of base classes (including the System.Object class thus DIT >= 1).

Recommendations:
Types where DepthOfInheritance is higher than 6 might be hard to maintain. However it is not a rule since sometime your classes might inherit from tier classes which have a high value for depth of inheritance. For example, the average depth of inheritance for framework classes which derive from System.Windows.Forms.Control is 5.3.

Go to top


Metrics on Methods

Method rank

MethodRank values are computed by applying the Google PageRank algorithm on the graph of methods' dependencies. A homothety of center 0.15 is applied to make it so that the average of MethodRank is 1.

Recommendations:
Methods with high MethodRank should be more carefully tested because bugs in such methods will likely be more catastrophic.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Afferent coupling at method level (MethodCa)

The Afferent Coupling for a particular method is the number of methods that depends directly on it.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Efferent coupling at method level (MethodCe)

The Efferent Coupling for a particular method is the number of methods it directly depends on. Notice that methods declared in framework projects are taken into account.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

NbParameters

The number of parameters of a method. Ref and Out are also counted. The this reference passed to instance methods in IL is not counted as a parameter.

Recommendations:
Methods where NbParameters is higher than 5 might be painful to call and might degrade performance. You should prefer using additional properties/fields to the declaring type to handle numerous states. Another alternative is to provide a class or structure dedicated to handle arguments passing (for example see the class System.Diagnostics.ProcessStartInfo and the method System.Diagnostics.Process.Start(ProcessStartInfo)).

NbVariables

The number of variables declared in the body of a method.

Recommendations:
Methods where NbVariables is higher than 8 are hard to understand and maintain. Methods where NbVariables is higher than 15 are extremely complex and should be split in smaller methods (except if they are automatically generated by a tool).

NbOverloads

The number of overloads of a method. . If a method is not overloaded, its NbOverloads value is equals to 1. This metric is also applicable to constructors.

Recommendations:
Methods where NbOverloads is higher than 6 might be a problem to maintain and provoke higher coupling than necessary. This might also reveal a potential misused of the C# and VB.NET language that since C#3 and VB9 support object initialization. This feature helps reducing the number of constructors of a class.

Go to top


Metrics on fields

Afferent coupling at field level (FieldCa)

The Afferent Coupling for a particular field is the number of methods that directly use it.

Related Link:
Code metrics on Coupling, Dead Code, Design flaws and Re-engineering.

Go to top