rkcole.com
Cyclomatic complexity is a static software metric pioneered in the 1970s by Thomas McCabe. The cyclomatic complexity number (CCN) is a measure of how many paths there are through a method. It serves as a rough measure of code complexity and as a count of the minimum number of test cases that are required to achieve full code-coverage of the method.
The equation for calculating the cyclomatic complexity number comes from the the theory of graphs where it refers to the number of paths from any point in a topological space to any other point. It is expressed as:
CCN = E - N + P
where E represents the number of edges on the graph, N the number of nodes on the graph, and P the number of connected components. In programming terms, E represents the code executed as a result of a decision, N is the number of decision points (conditional statements) and P is the number of ways to exit the program. As a software metric it can be expressed as
CCN = "The number of decision points" + 1
Cyclomatic complexity measures the number of execution paths through a method; therefore, every method has, at a minimum, a cyclomatic complexity of 1 since there is at least one path through the method. This means that even the simplest getter/setter method has CCN = 1:
public String getName()
{
return this.name;
}
In the following method there are two decision points. Remembering that every method has at least a CCN value of 1, the final value for the cyclomatic complexity of the getResult(...) method is 3.
public int getResult(int p1, int p2)
{
int result = 0;
if (p1 == 0)
{
result += 1;
} else
{
result += 2;
}
if (p2 == 0)
{
result += 3;
} else
{
result += 4;
}
return result;
}
Conditionals and loops add to the complexity of a method. Each additional if, case, while, etc, adds 1 to your CCN score because you're adding another potential path through the method.
In general,
if statement.for statement.while loopdo-while loop.&& (an implied if statement).|| (an implied if statement).? (an implied if statement).. (an implied if statement).case statement.default statement.catch statement.finaly statement.continue statement. You'll notice that I keep referring to the CCN value of methods. Measuring the complexity of an entire class is somewhat meaningless. If a class has a dozen public attributes with the standard accessor methods it will have a CCN value of at least 24! Does that mean the class is complex? Of course not. A CCN value of 24 for a class doesn't mean much; a value of 24 for a method may mean you've got a plate of spaghetti to unravel (of course it could also indicate a large but trivial case statement).
There are several good tools available for calculating complexity. On various projects I've used:
The number of execution paths through a method is directly related to the understandability, maintainability, and testability of the method. A general rule of thumb states that in order to ensure a high level of test coverage, the number of test cases for a method should be at least equal to the method's cyclomatic complexity value. When the number of test cases is equal to the CCN value, you can feel confident that your tests have followed every path through your code.
The getResult(...) method above would require at least four test cases to achieve complete code coverage. The following table illustrates the argument values required to test each path through the method.
| Test # | p1 | p2 |
|---|---|---|
| 1 | 0 | 0 |
| 2 | 0 | not 0 |
| 3 | not 0 | 0 |
| 4 | not 0 | not 0 |
Another rule of thumb when considering the CCN value is the relationship between CCN and risk:
| Cyclomatic Complexity | Risk Summary |
|---|---|
| 1-10 | Simple, low risk |
| 11-20 | Moderate complexity, medium risk |
| 21-50 | Complex, high risk |
| 51+ | Very high risk |
Studies have shown that bug counts spike in methods with CCN > 13. A method with a CCN value greater than 10 is considered complex. By determining the cyclomatic complexity of various class methods and paying attention to outlier values, one can uncover code that may be a candidate for a testing and/or refactoring effort. The higher the value of CCN for a given method, the harder it is to test.
There is a strong correlation between CCN value and defect density. When the determination has been made that a class is complex there are two steps available to mitigate the associated risk:
Software systems that have gone through a refactoring process with the goal of reducing complexity have higher quality and are more maintainable.
CCN is a useful aide in flagging possible problems in the code base but the number does suffer some potential drawbacks: