Example

        [TestMethod]
        public void NestingDepthIsAtMost6()
        {
            Verifier.VerifyThat<MemberDescriptor>((x, state) =>
            {
                var c = Metrics.NestingDepth(x);
                if (c > 6)
                {
                    state.Message = string.Format("'nesting depth={0} > 6'", c);
                    return false;
                }
                return true;
            }, Filters.MyMethods);
        }

Abstractness (Module)

The portion of interfaces plus abstract types in relation to the total number of types in a module.

Abstractness (Submodule)

The portion of interfaces plus abstract types in relation to the total number of types in a submodule.

Afferent Coupling (Module)

Return the number of types in other modules than the target that refer to the target module.

Afferent Coupling (Submodule)

Return the number of types in other submodules than the target that refer to the target submodule.

Afferent Coupling (Type)

Return the number of types that refer to the examined type. Self references are excluded.

Afferent Coupling (Member)

Return the number of members that refer to the examined member. Self references are excluded.

Association Between Classes (Type)

The number of members from other types that are directly accessed by the specified type.

Cyclomatic Complexity (Type)

The cyclomatic complexity of each member for a type are summed up. This way you have a hint to identify types that are hard to maintain.

Cyclomatic Complexity (Member)

The cyclomatic complexity is a measurement for the number of linear independent paths through a members source code. Fields always return 0.

Depth of Inheritance (Type)

Return the depth of the inheritance tree from this type to System.Object inclusive. Interfaces do not count. Only Abstract and concrete types.

The deeper a class in the hierarchy, the greater the number of methods it will probably inherit which makes it harder to predict its behavior. Deeper trees involve greater design complexity since more classes and methods are involved. Deeper classes in the tree have a greater potential for reusing inherited methods.

Efferent Coupling (Module)

Return the number of types the examined module depends on. The type inside the module are excluded.

Efferent Coupling (Submodule)

Return the number of types the examined submodule depends on. The type inside the submodule are excluded.

Efferent Coupling (Type)

Return the number of types the examined type depends on. Self references are excluded.

Efferent Coupling (Member)

Return the number of members the examined member depends on. The declaring type is excluded.

Halstead: Delivered Bugs (Project)

Halstead's delivered bugs is an estimate for the number of errors in the implementation. Delivered bugs is calculated for all modules in the current dependency model that are marked with IsPartOfProject.

Bugs = ( Effort ^ (2/3) ) / 3000

Halstead: Difficulty (Member, Type, Submodule, Module, Project)

The difficulty level or error proneness of the program is proportional to the number of unique operators in the program. Difficulty is also proportional to the ration between the total number of operands and the number of unique operands (i.e. if the same operands are used many times in the program, it is more prone to errors).

Difficulty = ( ||operators|| / 2 ) * ( operands / ||operands|| )

Halstead: Effort (Member, Type, Submodule, Module, Project)

The effort to implement or understand a program is proportional to the volume and to the difficulty level of the program.

Effort = Volume * Difficulty

Halstead: Program Length (Member, Type, Submodule, Module, Project)

Sum of the total number of operators and operands in the part of the program.

Length = operators + operands

Halstead: Program Vocabulary (Member, Type, Submodule, Module, Project)

Count of the distinct number of operators and operands in the part of the program.

Vocabulary = ||operators|| + ||operands||

Halstead: Time to program (Project)

The time to implement or understand a program (T) is proportional to the effort. Halstead has found that dividing the effort by 18 give an approximation for the time in seconds. 

Time = Effort / 18

Halstead: Volume (Member, Type, Submodule, Module, Project)

According to Halstead, Program Volume V corresponds to the minimum number of bits required for program coding.

Volume = Length * Log2(Vocabulary)

Instability (Module)

Modules that contain multiple outgoing but few incoming dependencies are less stable because of the consequences of changes in these modules. Modules containing more incoming dependencies are more stable because they are more difficult to change.
Instability = EfferentCoupling / (EfferentCoupling + AfferentCoupling)

Instability (Submodule)

Submodules that contain multiple outgoing but few incoming dependencies are less stable because of the consequences of changes in these submodules. Submodules containing more incoming dependencies are more stable because they are more difficult to change.
Instability = EfferentCoupling / (EfferentCoupling AfferentCoupling)

Lack of Cohesion (Type) Henderson-Sellers

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.  The LCOM HS (HS stands for Henderson-Sellers) takes its values in the range [0-2].
A LCOM HS value higher than 1 should be considered alarming.

Nesting Depth (Member)

Return the deepest nesting of a members IL instructions. An implemented method at least has a nesting depth of 1 as entering the method counts as scope. Fields return 0. Anything above 5 should be considered for refactoring.

Normed Distance from Main Sequence (Module)

Describes the balance between abstractness and stability of a module. A module becomes stable when there are a lot of referrers to it. If so, then it should be abstract at the same time. A module that is instable should be concrete, as there are no referrers relying on contracts. Values are in range [-1, +1]. Close to -1 means the module is concrete but has many dependent modules, changes to the module will imply lots of changes to referrers. This is called the zone of pain. On the other side, a value of one means the module is almost completely abstract, but noone uses it. Which is the zone of uselessness.
NormalizedDistance = Abstractness + Instability - 1

Normed Distance from Main Sequence (Submodule)

Describes the balance between abstractness and stability of a submodule. A submodule becomes stable when there are a lot of referrers to it. If so, then it should be abstract at the same time. A submodule that is instable should be concrete, as there are no referrers relying on contracts. Values are in range [-1, +1]. Close to -1 means the submodule is concrete but has many dependent submodules, changes to the submodule will imply lots of changes to referrers. This is called the zone of pain. On the other side, a value of one means the submodule is almost completely abstract, but noone uses it. Which is the zone of uselessness.
NormalizedDistance = Abstractness + Instability - 1

Number of Children (Type)

Count the number of types that inherit from the current type.

Number of Fields (Type)

Count the number of fields in a type including inherited ones.

Number of Interfaces (Type)

Count all interface the current type implements, which equals the number of different contracts a type has to fulfill. Interfaces on inherited types and interfaces that are base types for other interfaces also count. Low values are desired.

Number of Methods (Type)

Count the total number of methods in a type including inherited ones.

Number of Overridden Methods (Type)

Count the number of methods in a type that are overriding a member of a base class.

Number of Parameters (Member)

Count the number of parameters of a method. For more than 2 parameters you must have good reasons. More than 3 parameters might be caused by implementing framework interfaces. Otherwise having more than 3 parameters is a hint for breaking the single responsibility principle.

Number of Variables (Member)

Count the number of local variables in a member. Fields return 0.

Relational Cohesion (Module)

The average number of relations between types of the module per type. Optimal values lie between 1.5 and 4.0.
RelationalCohesion = (RelationShips + 1) / Types

Relational Cohesion (Submodule)

The average number of relations between types of the submodule per type. Optimal values lie between 1.5 and 4.0.
RelationalCohesion = (RelationShips + 1) / Types

Specialization Index (Type)

The deeper the inheritance graph and the more members are overridden methods, the more complex a system gets. A high value of specialization is an indicator for lack of maintainability for a type and its callers.
SIX = NumberOfOverriddenMethods * DepthOfInheritance / Max(NumberOfMethods, 1)
A value above 1.2 should be considered alarming.

Egg and Gherkin is a development tool written in C# to qualify the evolvement of your software architecture within predefined limits. Controlled by the unit test framework of your choice, it gives immediate feedback when breaking architectural constraints.

Last edited Nov 2, 2013 at 11:24 AM by The_eg, version 10

Comments

No comments yet.