Cyclomatic Complexity

The criticality and risk of software is defined by its complexity. Forty years ago, McCabe introduced his famous cyclomatic complexity (CC) metric. Today, it is still one of the most popular and meaningful measurements for analyzing code.

It is of even more value having an indicator which can provide constructive guidance on how to improve the quality of code.It is of great benefit for projects to be able to predict software components likely to have a high defect rate or which might be difficult to test and maintain. This is what the cyclomatic complexity (CC) metric gives us. 

The CC metric is simple to calculate and intuitive to understand. It can be taught quickly. Control flows in code are analyzed by counting the decisions, i.e., the number of linear independent paths through the code under scrutiny. Too many nested decisions make the code more difficult to understand due to the many potential flows and possibilities of passing through it . In addition, the CC value of a module correlates directly with the number of test cases necessary for path coverage, so even a rough indication given by the CC metric is of high value to a developer or project manager.

These relationships are intuitive for students as well as experts and managers and this is another appealing feature of the CC metric.A high CC thus implies high criticality and the code will have a higher defect density (vis-à-vis code with a relatively lower CC); test effort is higher and maintainability severely reduced. It is small wonder therefore that CC, unlike many other metrics which have been proposed over the past decades is still going strong and is used in almost all tools for criticality prediction and static code analysis.

CC, together with change history, past defects and a selection of design metrics (e.g., level of uninitialized data, method overriding and God classes) can be used to build a prediction model. Based on a ranked list of module criticality used in a build, different mechanisms namely refactoring, re-design, thorough static analysis and unit testing with different coverage schemes can then be applied. The CC metric therefore gives us a starting point for remedial maintenance effort. 

Instead of predicting the number of defects or changes (i.e., algorithmic relationships) we consider assignments to classes (e.g., “defect-prone”). While the first goal can be achieved more or less successfully with regression models or neural networks mainly in finished projects, the latter goal seems to be adequate for predicting potential outliers in running projects, where precision is too expensive and not really necessary for decision support. Christof – I am not sure I follow the point being made in these last two sentences – can you possibly clarify/elaborate please?

While the benefits of CC are clear, it does need clear counting rules. These days for instance, we do not count simple “switch” or “case” statements as multiplicities of “if, then, else” decisions. Moreover, the initial proposal to limit CC to seven plus/minus two per entity is no longer taken as a hard rule, because boundaries for defect-prone components are rather fuzzy and multi-factorial.

Having identified such overly critical modules, risk management must be applied. The most critical and most complex of the analyzed modules, for instance, the top 5, are candidates for redesign. For cost reasons mitigation is not only achieved with redesign. The top 20% should have a thorough static code analysis, and the top 80% should be at least unit tested with C0 coverage of 100%. By concentrating on these critical components the productivity of quality assurance is increased.

Critical modules should at least undergo a flash review and subsequent refactoring, redesign or rewriting – depending on their complexity, age and reuse in other projects. Refactoring includes reducing size, improving modularity, balancing cohesion and coupling, and so on. For instance, apply thorough unit testing with 100 percent C0 coverage (statement coverage) to those modules ranked most critical. Investigate the details of the selected modules’ complexity measurements to determine the redesign approach. Typically, the different complexity measurements will indicate the approach to follow. Static control flow analysis tools incorporating CC can also find security vulnerabilities such as dead code, often used as backdoors for hijacking software.

Our own data but also many published empirical studies demonstrate that a high decision-to-decision path coverage or C1 coverage will find over 50% of defects, thus yielding a strong business case in favor of using CC.  On the basis of the results from many of our client projects and taking a conservative ratio of only 40 percent defects in critical components, criticality prediction can yield at least a 20 percent cost reduction for defect correction.

The additional costs for the criticality analysis and corrections are in the range of few person days per module. The necessary tools such as Coverity, Klocwork, Lattix, Structure 101, SonarX, SourceMeter, are off the shelf and account for even less per project. These criticality analyses provide numerous other benefits, such as the removal of specific code-related risks and defects that otherwise are hard to identify (for example, security flaws).

CC clearly has its value for critically predictions and thus improving code quality and reducing technical debt. Four decades of validity and usage is a tremendous time in software, and I congratulate McCabe for such a ground-breaking contributio