Copious Cyclomatic Complexity Creates Confusing Code
The amount of cyclomatic complexity that a block of code has is a neat metric to measure. In short, it measures the number of linearly-independent paths in a program or method. Thus, a program containing a single entry and exit point and no loops, conditional statements, try-catch blocks, etc. will have a cyclomatic complexity of 1. The name itself threw me at first; I did not understand why cycle was in the name. It made more sense, however, after reading the Wikipedia article and looking at the graphical representation of the metric. Cyclomatic complexity basically counts the number of different cycles in a control flow graph of a given program. A quick and easy way to calculate a program’s cyclomatic complexity is to count the number of decision points in the program and then add one. This calculation is accurate only if the program has only one entry and exit point.
Let’s have a look at a simple method:
void DoSimpleStuff()
{
a();
b();
}
This method has no decisions to make so it has a cyclomatic complexity of 1. You can see in the associated graph that there is only one linearly independent path. In the following graphs, the blue node represents the entry point and the red node the exit point.
A more complex method yields higher cyclomatic complexity. Let’s have a look at a method that contains a couple decision points. Its corresponding graph immediately follows.
void DoStuff()
{
for (int i = 0; i < 1000; i++)
{
a();
}
if (condition())
{
b();
}
else
{
c();
}
}
Note that a loop only generates one extra branch whether it loops once, twice, or 100 times. Also note the difference in the directed edges between the for loop and the if statement. DoStuff() has a cyclomatic complexity of 3. While this measurement starts off small, it can grow rapidly. For example, if a conditional statement has multiple conditions then each of those conditions adds to the complexity:
void DoMoreStuff()
{
if(c1() && c2())
{
a();
}
else
{
b();
}
}
DoMoreStuff() also has a cyclomatic complexity of 3. If c1() returns false, execution goes to b(). If c1() is true, execution goes to c2(). c2() then goes either to a() or b() depending on its truth value. As you can see, even a little extra decision making can rapidly increase the complexity of a seemingly-simple method. A high cyclomatic complexity is usually a good code smell indicator: if the code has a lot of decisions to make, is it adhering to the Single Responsibility Principle? How easy or difficult would it be to mock or fake its behavior in a testing environment? Speaking of tests, a good guideline to follow when creating tests is that a method has good testing coverage if the number of tests equals the method’s cyclomatic complexity. The above examples would be relatively easy to test: a couple tests are written and the job is done. What if the complexity measurement was 10? 15? 37? Getting such a messy method under test would certainly be more difficult! Such methods can lead to difficult maintenance as well. In addition to all the tests that have to be written and maintained, all of the paths of the code open a new door for bugs to crawl into.
So how does one find smelly code that reeks of cyclomatic complexity? While it is simple to calculate this measurement for methods that only have single entry and exit points, throwing multiple entry/exit points into the equation complicates matters significantly. Furthermore, it is tough to sort through a large code base to find these complicated code clusters. This is where an analysis tool comes into play. The company I work for has recently released a cool new tool called Nitriq that makes analyzing .NET code really easy. With it, you can locate these complex bits of code in your project in a snap. For the remainder of my post, I’m going to show you how easy it is to find portions of your code containing high cyclomatic complexity.
After selecting the assemblies and executables you want to analyze, you can overview your entire codebase at a glance:
You can see the methods with the largest cyclomatic complexity in your code base by selecting the “Method – Cyclomatic Complexity” metric within the Treemap window. As exemplified in the above screenshot, hovering over a particular region with the mouse gives you the pertinent information. In addition to the Treemap, queries that come with Nitriq also take advantage of this metric to give you a detailed listing of methods that have a high cyclomatic complexity:
The Treemap window highlights the methods returned in the executed query (the assembly I analyzed in this example is far larger than the one in the previous example, so its Treemap window contains quite a bit more depth). The red portion of the Treemap indicates the class I had double-clicked within the CodeTree window. This functionality also exists when double-clicking icons in the Grid view. The cyclomatic complexity is given in addition to other useful information such as physical line count and out types (i.e. all of the types that the method depends on). The columns can be easily sorted by clicking on the column titles, so finding the methods with the highest cyclomatic complexity is a cinch.
Maintaining a reasonable amount of cyclomatic complexity in your code is essential. It is too easy to let a simple block of code get complicated very quickly. Letting that measurement grow too large can lead to maintenance nightmares, difficult testing, and a potential for splitting headaches. Refactoring out conditionals into their own methods or classes, removing loops where possible, and adhering to good software design principles are all steps that can be taken to help lower the complexity. It can be quite time-consuming to find these code smells in a manual fashion, so the usage of a solid code analysis tool is a great approach to take when setting out to lower the cyclomatic complexity of your code.
This post is part of a series exemplifying how Nitriq can assist in the identification of code smells.


