Metrics Definitions
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'
-
7 metrics on application:
NbLinesOfCode,
NbLinesOfComment,
PercentageComment,
NbProjects,
NbTypes,
NbMethods,
NbFields
-
10 metrics on projects:
NbLinesOfCode,
NbLinesOfComment,
PercentageComment,
NbTypes,
NbMethods,
NbFields,
Project level,
Afferent coupling (Ca),
Efferent coupling (Ce),
Relational Cohesion(H),
-
16 metrics on types:
NbLinesOfCode,
NbLinesOfComment,
PercentageComment,
NbMethods,
NbFields,
Type level,
Type rank,
Afferent coupling at type level (TypeCa),
Efferent coupling at type level (TypeCe),
Lack of Cohesion Of Methods (LCOM),
Lack of Cohesion Of Methods Henderson-Sellers (LCOM HS),
Code Source Cyclomatic Complexity,
Size of instance,
Association Between Class (ABC)
Number of Children (NOC),
Depth of Inheritance Tree (DIT)
-
11 metrics on methods:
NbLinesOfCode,
NbLinesOfComment,
PercentageComment,
Method level,
Method rank,
Afferent coupling at method level (MethodCa),
Efferent coupling at method level (MethodCe),
Code Source Cyclomatic Complexity,
NbParameters,
NbVariables,
NbOverloads
-
2 metrics on fields:
Size of instance,
Afferent coupling at field level (FieldCa)
Metrics on application
-
NbLinesOfCode: (defined for application, projects, namespaces, types, methods)
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 assembly is the sum of its namespaces’ 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.
-
Namespaces, 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) ?
-
NbLinesOfComment: (defined for application, projects, namespaces, 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, namespaces, types, methods)
This metric is computed with the following formula:
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, namespaces)
The number of types. A type can be an abstract or a concrete class, a structure, an enumeration.
-
NbMethods: (defined for application, projects, namespaces, 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, namespaces, 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.
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 assemblies (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 assemblies 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 assembly 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 assembly (i.e that do not connect to types outside the project). Let N be the number of types within the assembly. 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 assembly 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. Assemblies where RelationalCohesion < 1.5 or RelationalCohesion > 4.0 might be problematic.
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 assemblies 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 NDepend 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 assemblies.
-
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.
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 assemblies 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.
Metrics on fields
| |
|
For VB.NET Code Base use:
Our Partners:
|
|