Complexity metrics

The following metrics measure the complexity of executable code within procedures. This includes both the internal complexity of a single procedure and the complexity of the data flow in and out of a procedure.

High complexity may result in bad understandability and more errors. Complex procedures also need more time to develop and test. Therefore, excessive complexity should be avoided. Too complex procedures should be simplified by rewriting or splitting into several procedures.

Complexity is often positively correlated to code size. A big program or function is likely to be complex as well. These are not equal, however. A procedure with relatively few lines of code might be far more complex than a long one. We recommend the combined use of LOC and complexity metrics to detect complex code.

CC Cyclomatic complexity

Cyclomatic complexity, also known as V(G) or the graph theoretic number, is probably the most widely used complexity metric in software engineering. Defined by Thomas McCabe, it's easy to understand and calculate, and it gives useful results. This metric considers the control logic in a procedure. It's a measure of structural complexity. Low complexity is desirable.

How to calculate cyclomatic complexity?

CC = Number of decisions + 1

The cyclomatic complexity of a procedure equals the number of decisions plus one. What are decisions? Decisions are caused by conditional statements. In Visual Basic they are If..ElseIf..Else, Case, For..Next, Until, While, Catch [..When], On..GoTo and On..GoSub. In order to get CC, one simply counts the conditional statements. A multiway decision, the Select Case block, typical counts as several conditional statements. The decisions counted for each statement or construct are listed below.

ConstructDecisionsReasoning
If..Then+1An If statement is a single decision.
ElseIf..Then+1ElseIf adds a new decision.
Else0Else does not cause a new decision. The decision is at the If.
#If..#ElseIf..#Else0Conditional compilation adds no run-time decisions.
Select Case0Select Case initiates the following Case branches, but does not add a decision alone.
Case+1Each Case branch adds a new decision.
Case Else0Case Else does not cause a new decision. The decisions were made at the other Cases.
For [Each] .. Next+1There is a decision at the For statement.
Do While|Until+1There is a decision at the start of the Do..Loop.
Loop While|Until+1There is a decision at the end of the Do..Loop.
Do..Loop alone0There is no decision in an unconditional Do..Loop without While or Until. *
While+1There is a decision at the start of the While..Wend or While..End While loop.
Catch+1Each Catch branch adds a new conditional path of execution. Even though a Catch can be either conditional (catches specific exceptions) or unconditional (catches all exceptions), we treat all of them the same way. *
Catch..When+2The When condition adds a second decision. *
On..GoTo, On..GoSub+nThe statement is a multi-branch decision. Each target line adds a branch. **

* Rule added to Project Analyzer v8.0.
** Rule added to Project Analyzer v10.3.
Previous versions did not take these rules into account.

The minimum limit for cyclomatic complexity is 1. This happens with a procedure having no decisions at all. There is no maximum value since a procedure can have any number of decisions.

Notes:

Variations: CC, CC2 and CC3

Cyclomatic complexity comes in a couple of variations as to what exactly counts as a decision. Project Analyzer supports three alternative cyclomatic complexity metrics. CC is the basic version. CC2 and CC3 use slightly different rules.

CC does not count Boolean operators such as And and Or. Boolean operators add internal complexity to the decisions, but they are not counted in CC. CC and CC3 are similar what comes to Booleans, but CC2 is different.

CC2 Cyclomatic complexity with Booleans ("extended cyclomatic complexity")

CC2 = CC + Boolean operators

CC2 extends cyclomatic complexity by including Boolean operators in the decision count. Whenever a Boolean operator (And, Or, Xor, Eqv, AndAlso, OrElse) is found within a conditional statement, CC2 increases by one. The statements considered are: If, ElseIf, Select, Case, Until, While, When.

The reasoning behind CC2 is that a Boolean operator increases the internal complexity of a decision. CC2 counts the "real" number of decisions, regardless of whether they appear as a single conditional statement or split into several statements. Instead of using Boolean operators to combine decisions into one (x=1 And y=2), you could as well split the decisions into several sub-conditions (If x=1 Then If y=2 Then). CC2 is immune to this kind of restructuring, which might be well justified to make the code more readable. On the other hand, one can decrease CC simply by combining decisions with Boolean operators, which may not make sense.

Including Boolean operators in cyclomatic complexity was originally suggested by Thomas McCabe. In this sense, both CC and CC2 are "original" cyclomatic complexity measures.

Alternative names: CC2 is also known as ECC extended cyclomatic complexity or strict cyclomatic complexity.

Note: A Case branch can cover several alternative values or ranges, such as Case 1, 2, 5 To 10. These are not counted in CC2, even if they add internal complexity to the decision, quite the same way as the Or operator does in an If statement. A Case with several alternatives (Case 1, 2, 3) is usually simpler than the same decision as an If statement (If x=1 Or x=2 Or x=3 Then). A Case like this will also yield a lower CC2 than the respective If. Splitting the If statement into successive If..ElseIf branches will keep CC2 unmodified, but rewriting it as a single Case will decrease CC2.

CC3 Cyclomatic complexity without Cases ("modified cyclomatic complexity")

CC3 = CC where each Select block counts as one

CC3 equals the regular CC metric, but each Select Case block is counted as one branch, not as multiple branches. In this variation, a Select Case is treated as if it were a single big decision. This leads to considerably lower complexity values for procedures with large Select Case statements. In many cases, Select Case blocks are simple enough to consider as one decision, which justifies the use of CC3. Cyclomatic complexity and Select Case

Alternative name: CC3 is sometimes called modified cyclomatic complexity.

Summary of cyclomatic complexity metrics

Metric Boolean operators Select Case Alt name
CC Cyclomatic complexity Not counted +1 for each Case branch Regular cyclomatic complexity
CC2 Cyclomatic complexity with Booleans +1 for each Boolean +1 for each Case branch Extended or strict cyclomatic complexity
CC3 Cyclomatic complexity without Cases Not counted +1 for an entire Select Case Modified cyclomatic complexity

CC, CC2 or CC3 — which one to use? This is your decision. Pick up the one that suits your use best. CC and CC2 are "original" metrics and probably more widely used than CC3. The numeric values are, in increasing order: CC3 (lowest), CC (middle) and CC2 (highest). In a sense, CC2 is the most pessimistic metric. All of them are heavily correlated, so you can achieve good results with any of them.

Values of cyclomatic complexity

A high cyclomatic complexity denotes a complex procedure that's hard to understand, test and maintain. There's a relationship between cyclomatic complexity and the "risk" in a procedure.

CCType of procedureRisk
1–4A simple procedureLow
5–10A well structured and stable procedureLow
11–20A more complex procedureModerate
21–50A complex procedure, alarmingHigh
>50An error-prone, extremely troublesome, untestable procedureVery high

The original, usual limit for a maximum acceptable value for cyclomatic complexity is 10. Other values, such as 15 or 20, have also been suggested. Regardless of the exact limit, if cyclomatic complexity exceeds 20, you should consider it alarming. Procedures with a high cyclomatic complexity should be simplified or split into several smaller procedures.

Cyclomatic complexity equals the minimum number of test cases you must execute to cover every possible execution path through your procedure. This is important information for testing. Carefully test procedures with the highest cyclomatic complexity values.

Bad fix probability

There is a frequently quoted table of "bad fix probability" values by cyclomatic complexity. This is the probability of an error accidentally inserted into a program while trying to fix a previous error.

CCBad fix probability
1–105%
20–3020%
>5040%
approaching 10060%

As the complexity reaches high values, changes in the program are likely to produce new errors.

Cyclomatic complexity and Select Case

The use of multi-branch statements (Select Case) often leads to high cyclomatic complexity values. This is a potential source of confusion. Should a long multiway selection be split into several procedures?

McCabe originally recommended exempting modules consisting of single multiway decision statements from the complexity limit.

Although a procedure consisting of a single multiway decision may require many tests, each test should be easy to construct and execute. Each decision branch can be understood and maintained in isolation, so the procedure is likely to be reliable and maintainable. Therefore, it is reasonable to exempt procedures consisting of a single multiway decision statement from a complexity limit. Note that if the branches of the decision statement contain complexity themselves, the rationale and thus the exemption does not automatically apply. However, if all the branches have very low complexity code in them, it may well apply.

Resolution: For each procedure, either limit cyclomatic complexity to 10 (or another sensible limit) or provide a written explanation of why the limit was exceeded.

Cyclomatic complexity readings

TCC Total Cyclomatic Complexity

The total cyclomatic complexity for a project or a class is calculated as follows.

TCC = Sum(CC) - Count(CC) + 1

TCC equals the number of decisions + 1 in a project or a class. It's similar to CC but for several procedures.

Sum(CC) is simply the total sum of CC of all procedures. Count(CC) equals the number of procedures. It's deducted because we already added +1 in the formula of CC for each procedure.

TCC is immune to modularization, or the lack of modularization. TCC always equals the number of decisions + 1. It is not affected by how many procedures the decisions are distributed in.

TCC can be decreased by reducing the complexity of individual procedures. An alternative is to eliminate duplicated or unused procedures.

DECDENS Decision Density

Cyclomatic complexity is usually higher in longer procedures. How much decision is there actually, compared to lines of code? This is where you need decision density, which also known as cyclomatic density.

DECDENS = Sum(CC) / LLOC

This metric shows the average cyclomatic density in your project. The numerator is sum of CC over all your procedures. The denominator is the logical lines of code metric. DECDENS ignores single-line procedure declarations since cyclomatic complexity isn't defined for them.

DECDENS is relatively constant across projects. A high or low DECDENS does not necessarily means anything is wrong. A low DECDENS might indicate lack of logic, such as in generated code, or code that primarily loads some data instead of performing actions.


Depth of nesting metrics

The following metrics measure nesting levels. It is assumed that the deeper the nesting, the more complex the code.

DCOND Depth of Conditional Nesting

Depth of conditional nesting, or nested conditionals, is related to cyclomatic complexity. Whereas cyclomatic complexity deals with the absolute number of branches, nested conditionals counts how deeply nested these branches are.

The recommended maximum for DCOND is 5. More nesting levels make the code difficult to understand and can lead to errors in program logic. If you have too many levels, consider splitting the procedure. You may also find a way to rewrite the logic with a Select Case statement, or an easier-to-read If..Then..ElseIf..Else structure.

Although it might seem to give a lower DCOND, it's not recommended to join multiple conditions into a single, big condition involving lots of And, Or and Not logic.

Readings

DLOOP Depth of Looping

Depth of looping equals the maximum level of loop nesting in a procedure. Target at a maximum of 2 loops in a procedure.


Advanced complexity readings

If you are really interested in structural complexity measures, there is a book that makes a thorough mathematical examination of 98 proposed measures for structural intra-modular complexity. This is for the very advanced reader.

© Project Analyzer Help