Analysis of Code Cyclomatic Complexity and Cognitive Complexity

write at the beginning

        Cyclomatic complexity is used to describe the "testability" of a piece of code very well ( measurability here refers to how much it takes to build a well-covered and comprehensive unit test ), but its design model is difficult to get a good "readability & maintainability" measurement result

        The new version of soanrqube introduces the concept of cognitive complexity . This complexity index makes up for some shortcomings of cyclomatic complexity, and can more accurately reflect the cost of understanding a piece of code and the difficulty of maintaining this piece of code.

        The following is a brief description of why cognitive complexity is more suitable for evaluating the readability and maintainability of a piece of code.

What is Cyclomatic Complexity?

        Cyclomatic complexity (Cyclomatic complexity) is a measure of code complexity. It was proposed by Thomas J. McCabe, Sr. in 1976. The goal is to guide programmers to write more testable and maintainable code.

        It can be used to measure the complexity of a module's judgment structure. It is expressed as the number of independent paths in quantity, and it can also be understood as the minimum number of test cases required to cover all possible situations. 

Calculation method of code cyclomatic complexity

The calculation method usually used is the point-edge calculation method (of course, there is also the node determination method), and the calculation formula is:

V(G) = e – n + 2 

e represents the number of edges in the control flow graph (corresponding to the part of the sequence structure in the code), n represents the number of nodes in the control flow graph, including the start point and the end point (note: all end points are only calculated once, even if there are multiple returns or throws; nodes correspond to branch statements in the code )

Suppose you have a piece of code like this:

public String case2(int index, String string) {

       String returnString = null;

       if (index < 0) {

           throw new IndexOutOfBoundsException("exception <0 ");

       }

       if (index == 1) {

           if (string.length() < 2) {

              return string;

           }

           returnString = "returnString1";

       } else if (index == 2) {

           if (string.length() < 5) {

              return string;

           }

           returnString = "returnString2";

       } else {

           throw new IndexOutOfBoundsException("exception >2 ");

       }

       return returnString;

    }

Cyclomatic Complexity Calculation Method

According to the formula V(G) = e – n + 2 = 12 – 8 + 2 = 6, the cyclomatic complex segment in the figure above is 6.

Note: Explain why n = 8. Although there are 12 real nodes on the graph, 5 of them are throw and return. Such nodes are end nodes and can only be recorded as one

Why introduce cognitive complexity?

        The original purpose of cyclomatic complexity is to identify "software modules that are difficult to test and maintain". It can calculate the least amount of fully covered test cases, but it cannot measure a satisfactory "difficulty of understanding".

        This is because codes with the same cyclomatic complexity do not necessarily have the same maintainability. Let's take a look at the following two examples:

The above two pieces of code have the same cyclomatic complexity, but obviously not the same readability and maintainability, which is where the cyclomatic complexity falls short.

Because cyclomatic complexity theory was proposed in 1976, it does not contain some modern language constructs, such as try-catch, lambda.

Moreover, each method has a minimum cyclomatic complexity of 1 by default, which makes it impossible for us to know whether a given class has a high cyclomatic complexity, whether it is a large and easy-to-maintain class, or a small and complex class.

In order to solve the above problems, "cognitive complexity" is introduced, which estimates the complexity of a piece of code when it is read and understood as a specific number

How is cognitive complexity judged?

Basic Principles of Cognitive Complexity Assessment

  • For linear code logic, if there is something that interrupts the logic, the complexity +1;
  • When the interrupt logic is a nest, the complexity +1;
  • Ignore abbreviations: abbreviate multiple sentences of code into one readable code without additional complexity;

The above description may be a bit abstract. Specifically, the following control flow structure will lead to increased cognitive complexity:

for, while, do while, ternary operator, if/elif/else, catch statement, jump statement (goto/break/continue), and nested control flow (the complexity of each layer of nesting increases)

Let's continue with the two examples mentioned above:

The cyclomatic complexity for the getWord method itself will have a complexity of 1 by default, and the complexity of each additional case will be +1, so the final cyclomatic complexity is 4

As for the cognitive complexity, the complexity of the entire switch structure is only increased by 1, because in terms of comprehensibility and maintainability, a few more cases will not lead to an increase (of course, a large number of cases should also be avoided as much as possible)

Let's look at another example:

As you can see, cognitive complexity takes into account factors that make this method more difficult to understand than the aforementioned getWords() method - nesting and jump statements

Therefore, although the cyclomatic complexity of the two methods is the same, their cognitive complexity data is a good reflection of the difference in understandability/maintainability between them.

In addition, compared to cyclomatic complexity, which defaults to a complexity of at least 1 for all methods, cognitive complexity does not have such an evaluation rule, which will be more friendly and objective for the complexity evaluation of simple classes such as entities:

To sum up, cognitive complexity will be more appropriate as the "readability/maintainability" evaluation index of code.


Attachment, the relationship between code complexity and software quality

The above complexity values ​​can be understood as method granularity, that is, if the complexity of a certain method is >30, then the readability and maintainability of this method are very low

Guess you like

Origin blog.csdn.net/liuqinhou/article/details/131724347
Recommended