|
This page last changed on Jul 18, 2005 by jflowers.
-
-
- Object Oriented Metrics
The metrics detailed here proviode guidence on knowing what actions could be taken when thresholds are broken. Each subject being measured has its own curcumstances that effect what actions should or should not be taken. Thresholds being broken on metrics measured never warrent atomated action. Every incedence should be reviewed and understood before action is taken.
Assemblies
Afferent coupling
The number of types outside this assembly that depend on types within this assembly. High afferent coupling indicates that the concerned assemblies have many responsibilities.
Action
No threshold.
Efferent coupling
The number of types inside this assembly that depends on types outside this assembly. High efferent coupling indicates that the concerned assembly is dependant.
Action
No threshold.
Relational Cohesion
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 assembly). 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 assembly has to all its types.
Action
Threshold: > .5
This metric is more important when there are more than 10.
Instability
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.
Action
No threshold.
Abstractness
The ratio of the number of internal abstract types (i.e abstract classes and interfaces) to the number of internal types. The range for this metric is 0 to 1, with A=0 indicating a completely concrete assembly and A=1 indicating a completely abstract assembly.
Action
No threshold.
Distance
The perpendicular normalized distance of an assembly from the idealized line A + I = 1 (called main sequence). This metric is an indicator of the assembly's balance between abstractness and stability. An assembly squarely on the main sequence is optimally balanced with respect to its abstractness and stability. Ideal assemblies 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 assembly that is coincident with the main sequence and D=1 indicating an assembly that is as far from the main sequence as possible. The picture in the report reveals if an assembly 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).
Action
Threshold: > .75
Hold a review.
Suggest that the assembly be reorganized.
Types
Response For a Type
The Response For a Type is the number of methods that can be potentially executed when calling a method of the concerned type. The IL instruction version of the RFC metric is the sum of IL instructions over this set of methods. Thus, the percentage of IL instructions that can be potentially reached from a class assesses precisely its location in the calling tree of your application (high percentage implies that your type is close to the roots while low percentage pinpoints a type near the leaves).
It has been deemed that types with high RFT are fault-prone. Indeed, such types are harder to test and debug since they potentially involve bulks of code. However, bear in mind that types with high RFT are unavoidable and central because they implement the overall semantic of your application.
Details on NDepend RFT implementation:
à When a polymorphic method is called, NDepend includes all its versions in computation.
à A given method will be counted once even if it is met several times while building the calls tree.
à RFT computation has some limitations. Following methods can't be reached by a static introspection: class constructors, methods only called through delegates or events, constructor of classes that has no instances (i.e that has only static members). For instance, this is the reason why the response for the class Prog of NDepend is not exactly 100% as it should be.
Action
I think > 10%. This is because of our plugin architecture. There are so many abstract types that 10% is a high number for EF.
Lack of Cohesion Of Methods + Henderson-Sellers
The single responsibility principle states that a class should 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) ids the sum of MF over all instance fields of the class.
Action
LCOM(HS) Threshold: > 1
Hold a review.
Recomend using agregation, suppect that inheritance is the cause, responsiblities are being added through derivation.
Cyclomatic Complexity
Cyclomatic complexity is a popular procedural software metric equals to the number of decision that can be taken in a procedure (i.e number of if/else, switch/case, ternary operator, loop...). Adapted to the OO world, this metric is defined both on methods and classes/structures (as the sum of its methods CC).
This metric is language dependent, and NDepend only cops with the IL language. Thus, CC in NDepend is defined on a method as the number of different offsets targeted by a jump/branch IL instruction. Experience shows that NDepend CC is between two and three times larger than the CC computed in C# or VB.NET. Indeed, a C# for loop yields two different offsets targeted by a branch IL instruction while a foreach C# loop yields three ones.
Cyclomatic Complexity
Risk Evaluation
1-30 a simple program, without much risk
22-60 more complex, moderate risk
42-150 complex, high risk program
greater than 150 untestable program (very high risk)
Action
Threshold: > 60
Hold review.
Recomend agregation, I bet the LCOM(HS) is high as well.
Afferent Coupling
The Afferent Coupling for a particular type is the number of types that depends directly on it.
Action
No threshold.
Efferent Coupling
The Efferent Coupling for a particular type is the number of types it directly depends on.
Action
No threshold.
Association Between Class
The Association Between Classes metric for a particular class or structure is the number of members of others types it directly uses in the bodies of its methods.
Action
No threshold.
Number of Children
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.
Action
No threshold.
Depth of Inheritance Tree
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).
Action
Threshold: > 2
There will clearly be exceptions to this threshold, e.g. thigs that inherit from Form. But this will also catch inheritance hierarchies before they start.
|