Code complexity is an important and valid metric. Its most common unit of measure is derived via cyclomatic complexity and is frequently referred to as the cyclomatic complexity number, or CCN. To be historically complete, the same measure was once known as "McCabe," because it was originally proposed by Tom McCabe in 1976. The CCN basically measures the number of possible execution paths through a piece of code, generally a function. So code with a single path (that is, no
if statements or loops) has a CCN of 1, the minimum possible value. The CCN rises with
if statements, looping constructs, and other code features that involve a test before deciding what code to execute.
Typically, it's desirable for routines to have a CCN below 10. Most tools that measure code quality get fairly noisy if they find CCNs above 20. The idea behind these guidelines is that the more complex code is, the harder it is to test and maintain. Code that is hard to test and maintain tends to be a honey pot for bugs.
Organizations that pay attention to quality metrics will often put in a place a system that refuses to allow check-ins of code in which the CCN surpasses a preset limit. This would work except for one imperfection in the CCN as it is measured today, namely that every
case statement in a
switch represents a different path and so raises the CCN. So, a routine with a
case statement containing more than 30 cases will have a CCN greater than 30 and be blocked at check in. There are ways around this, of course, but the
switch statement is designed precisely to reduce the complexity of large-scale multiway value-based decisions. There is no doubt that a 20-case
switch is less complex than code whose logic is 20 levels deep. This is a small defect in CCN computation, which otherwise is a good measure: It is simple to calculate, easy to evaluate, and universally deployed in QA tools.
However, for CCN to be useful, it needs to be applied correctly. Many people apply the CCN measure to a whole program or to an entire source file. This approach generates a meaningless number. The resulting number is the sum of the CCNs of the individual routines. This means that the more routines in the file, the higher the CCN. It says nothing about whether the code is complex or not. This misunderstanding is rife in our industry, which is why the CCN is far too often ignored. A recent example of this very thing, to my surprise, appears in VS 2012, as I noted in our recent review of the product. The VS 2012 code review option generates the data in the following box (see column 3):
Cyclomatic Complexity in Column 3 is the sum of CCNs of constituent functions.
As can be seen, the CCN is meaningless when computed this way. If taken at face value, all those entries are off-the-charts complex. A CCN of 137 for example (the highlighted item) is unimaginably complex code. But, in fact, the CCN in this dialog is the sum of the CCNs of the various methods in the class, which has 222 lines of code. Had Microsoft at least shown the average CCN per method, developers would have some sense of where to look for problems. But the right path would be to omit CCNs entirely from code at the class level, and to present a separate dialog listing the methods and functions with the highest CCNs. Then, developers could go in and fix the code if necessary.
The typical fixes for high-complexity code include refactoring the code, frequently into smaller functions or classes that break up the complexity. Highly complex code is often indicative of violations of the single responsibility principle (SRP) although not always. For example, parser code is frequently tagged with high CCNs and yet respects the SRP and is devilishly difficult to simplify. In such cases, adding comments is often a good path. This at least helps maintainers work their way through the code. Finally, occasional Dr. Dobb's author Andrew Glover points out that if you're committed to thorough testing, a good rule of thumb is that you should have, at minimum, one unit test for every increment in CCN. So a function with a CCN of 17 should have at least 17 unit tests one for each possible execution path.
Either way, if you rely on CCN as a useful code metric, and I believe you should, apply it correctly so that it delivers true value.