قالب وردپرس درنا توس
Home / Tips and Tricks / What is Cyclomatic Complexity? Measuring code quality – CloudSavvy IT

What is Cyclomatic Complexity? Measuring code quality – CloudSavvy IT



Shutterstock / fran_kie

Cyclomatic complexity is a code statistic that you can view in many IDEs such as Visual Studio. While not an exact science, it gives you a general idea of ​​the complexity of functions, classes, and namespaces, which can be useful when looking for code to refactor.

What is Cyclomatic Complexity?

Cyclomatic complexity basically measures how much your code branches. Every time there is one if statement or other control block such as a loop, cyclomatic complexity increases as the graph will increasingly resemble a tree.

If you imagine your code as a series of actions (functions, method calls, variable assignments) connected through a control flow, you get an abstract graph that you can use to better understand the complexity. For common control flows such as if statements and for loops, the graphs look like this:

The formula for it is simple; take the number of edges in the graph (the arrows connecting everything) and subtract the number of nodes in the graph (the actions themselves).

Complexity = Edges -- Nodes + 2

For example, this code has a cyclomatic complexity of one, as there are no branches, and it just calls WriteLine over and over. Since it is just perfectly linear code, the number of nodes will cancel out the number of edges, giving a cyclomatic complexity of one.

public void TestFunction()
{
    Console.WriteLine("Test");
    Console.WriteLine("Test");
    Console.WriteLine("Test");
    Console.WriteLine("Test");
    Console.WriteLine("Test");
}

For more complicated code with branches, the complexity will be higher. This code, which one switch statement, has a complexity of 6, because there are many different paths the code can take. Each case in the switch statement adds complexity as it can lead to different outputs with different inputs.

public void TestFunction(string arg)
{
    switch(arg)
    {
        case "one":
            Console.WriteLine("Test");
            break;
        case "two":
            Console.WriteLine("Test");
            break;
        case "three":
            Console.WriteLine("Test");
            break;
        case "four":
            Console.WriteLine("Test");
            break;
        case "five":
            Console.WriteLine("Test");
            break;
    }
 
    Console.WriteLine("Test");
}

Cyclomatic complexity is calculated only within the scope of the function. If a function calls another function with high cyclomatic complexity, it is counted as only a single node and adds nothing to the caller, despite technically adding complexity to the program in a general sense.

Is cyclomatic complexity useful?

Cyclomatic complexity is not a perfect measure. It’s a very simple statistic and looks at the nuance of the code itself. Of course, you can still have terrible code with low complexity, or decent code with high complexity. But in general, it is still very useful to get an idea of ​​how complex a program is.

For the most part, complexity below 6 to 8 is probably fine, as long as the code itself is properly formatted. Anything from 8-15 is questionable, and anything over 15 probably isn’t great. Anything older than 25 is almost certainly a problem unless proven otherwise.

While having high cyclomatic complexity in a particular position isn’t the end of the world, it could point to a bigger problem. High complexity features are more difficult to maintain and more bug prone because more things can go wrong. And functions of higher complexity directly lead to unit tests of higher complexity, which can make the code difficult to maintain in the long run due to the difficulty of testing.

Visual Studio and other IDEs calculate the total complexity of entire classes and namespaces, which can be useful for tracing your most complex classes. You can sort by the highest complexity and zoom in on individual functions.

Often, code review can take into account cyclomatic complexity, and even highlight problematic features that may need to be manually revised. This can make it a very useful tool for maintaining a clean and organized codebase.

Looking for bad code

Many IDEs, such as Visual Studio, have built-in tools for calculating cyclomatic complexity and other code metrics for your entire codebase.

To do this from Visual Studio, click Analyze> Calculate Code Statistics> For Solution.

This will open the “Code Metrics” panel with a breakdown of your solution. You can sort by complexity in descending order to see the most problematic namespaces.

In addition to complexity, Visual Studio also presents a “Maintainability Index” that easily rates the method from 0-100 and can be maintained high, as well as “Class Coupling”, which indicates how many classes are referenced from that function or class.

Here, Visual Studio pointed out a 400-line method of mine that scored a whopping 72 on the complexity scale and a 14/100 on the maintainability index (shown as a yellow triangular hazard sign), referring to 65 different classes.

You can be sent directly into the five phases of grief with the result. “But this is a very long coroutine that has a lot of tasks to do!” I say to myself, trying to deny that the code I have written is mathematically bad, to the point where Visual Studio gives a warning. A complexity of 72 should definitely be cleaned up.

In this case, the solution was simple: the coroutine has a lot of tasks to do, so I divide those tasks into smaller coroutines and replace the main method with calls to subroutines. The overall code didn’t change, nor did the overall complexity of the class itself, but now the main function is not a 400-line sample.


Source link