Code metrics

This chapter explains the code metrics that are supported by Coco.

eLOC – effective lines of code

The eLoc metric measures the effective number of lines in a piece of code. An effective line is a line which contains statements that produce executable code.

When computing effective lines of code, Coco ignores:

  • empty lines
  • comment lines
  • declarations

This metric is more precise than simply counting the number of lines in a source code project since it skips non-functional code.

McCabe metric – cyclomatic complexity

The cyclomatic complexity is a code complexity measure proposed by Thomas J. McCabe, Sr. It is a strictly positive number that expresses the complexity of a program. A function with a cyclomatic complexity higher than 10 is usually considered to be difficult to maintain because it contains too many branches, switch or case statements or loops.

Definition

In structured programming languages like C++ and C#, the McCabe complexity of a piece of code is:

McCabe = Branchings + Functions

In this equation, Branchings is the number of binary branch statements , and Functions is the number of functions in the code.

The binary branching statements in the code are counted in the following way:

  • An if (...) ... else ... statement counts as one binary branch, and also a single if (...) ... statement: Both contain a choice between two different execution paths.
  • A loop construct, like while (...) ... or for (...) ..., also counts a one binary branch statement, since it contains a condition that offers the choice to stay in the loop or exit it.
  • A switch (...) { case ...: ... } construct with case labels counts as as binary branches because it can be simulated by if (...) ... else ... statements.

Properties

The McCabe complexity has several properties which distinguish it from eLOC:

  • McCabe is independent of the number of source lines of a function: It does not matter how many statements are present in the code, only how many branches are in it.
  • The metric is completely independent of the coding style. Reformatting the code does not affect it. This is a big difference to eLoc and other metrics that measure the number of lines of code.
  • The metric has a linear growth with the function complexity. For example, adding an if (...) ... else ... statement somewhere in a function increments the metric by one. It does not matter if the selection statement is nested or at the beginning of the function and it does not grow exponentially.
  • The McCabe metric is easy to interpret for a single function, but its value for a source file, a class, or an application is difficult to interpret. The reasons for this is that function calls are not represented in the flow diagram. The McCabe metric is computed independently for each function and it is as if there were no interactions between the functions present in the source code.
  • The McCabe metric is not adapted to measure the complexity of the software architecture. Or, to say it differently, it does not work on complex C++/C# design patterns which split the complexity over several classes.
  • And, like all metrics, the McCabe metric measures only the code complexity and not the complexity of the data structures.

eLOC vs McCabe – which metric to choose?

In general, for measuring the complexity of a function, the McCabe approach is more useful because the measurement is only dependent on the structure of the code. The code style and comments have no impact on it.

But, as soon as a complete file or a class is analyzed, even it is difficult to interpret. The reason is that the McCabe value grows with the number of functions in a piece of code regardless of function complexity. In this case, the number of effective lines of code is certainly easier to interpret.

Variants of McCabe metrics

Coco generates alternate variants of McCabe metrics to handle the complexity of the switch/case statement.

McCabe with cases grouped

McCabe is a metric which relies on a statement graph, but this graph is in general not unique. Specially for switch/case, the way to handle consecutive cases is undefined.

For example:

switch( a )
{
    case 0:
    case 1:
    case 2:
        return true;
    default:
        return false;
}

The McCabe complexity of this statement is 4 if we consider each case as a separate branch. But it is also possible to consider case 0:, case 1: and case 2: as one branch of the statement graph. In this case, the complexity of the whole code would only be 2.

Coco supports this interpretation of McCabe and calls this metric McCabe grouped cases.

McCabe with condensed switches

Often a switch/case statement is used to do a very simple computation, but the usage of this statement increases the McCabe complexity, as well as the complexity in the feeling of the developers.

For example:

switch( day )
{
    case 0: return "Monday";
    case 1: return "Tuesday";
    case 2: return "Wednesday";
    case 3: return "Thursday";
    case 4: return "Friday";
    case 5: return "Saturday";
    case 6: return "Sunday";
}

The McCabe complexity is 7 but this code is not really more complex than a single if...then...else... statement.

To handle this use case, Coco provides a metric called McCabe condensed switches which considers that a switch/case has a complexity of 1 regardless of the number of cases. So in this case, the complexity of this sample is 1.

Note: McCabe condensed switches does not conform to the definition of McCabe and should for this reason not be used if analysis the McCabe metric is required for a project.