Cyclomatic Complexity, Perceived Complexity, and ABC Metric
The story has three parts:
In Part Two: Calculations, we have seen a couple of examples to understand the metrics calculations. In this part, we will analyze the interdependence of the metrics and figuring out the maximum values for the RuboCop analysis.
Cyclomatic Complexity and Perceived Complexity
The cyclomatic and perceived complexity values are determined by if, and, or, case, when, for, while, until, and, rescue nodes:
- The if…elsif…else construct with n elsif branches, then, the contribution to cyclomatic complexity is n + 1, and perceived complexity is n + 2 because an else branch contributes to perceived complexity score.
- Each of the and, or, for, while, until, and, rescue nodes, the contributions to cyclomatic and perceived complexity values are the same.
- The case…when…else construct has n when branches, then, the contribution to cyclomatic complexity is n, and perceived complexity is 0.8 + 0.2 * n.
It is not possible to predict perceived complexity value given the cyclomatic complexity value, but we can derive an equation.
- Let E be the total number of else branches for if only.
- Let W be the total number of when branches.
- Let C be the total number of case nodes.
- Let CC be cyclomatic complexity.
- Let PC be perceived complexity.
Then, PC = CC + E − 0.8 * (W − C)
- Let a be the total number of if constructs without any elsif and else branch.
- Let b be the total number of if…elsif constructs without any else branch, and each such construct have f1, f2, …, fb elsif branches respectively.
- Let c be the total number of if…elsif…else constructs with else branch and each such construct have g1, g2, …, gc elsif branches respectively.
- Let d be the total number of case…when…else constructs and each such construct have h1, h2, …., hd when branches.
- Let e the total number of and, or, for, when, until, and, rescue nodes collectively.
CC = a + b + f1 + f2 + ... + fb + c + g1 + g2 + ... + gc + h1 + h2 + ... + hd + ePC = a + b + f1 + f2 + ... + fb + c + g1 + g2 + ... + gc + c + 0.8 * d + 0.2 * (h1 + h2 + ... + hd) + e=> PC - CC = c + 0.8 * d - 0.8 * (h1 + h2 + ... + hd)
=> PC = CC + c + 0.8 * d - 0.8 * (h1 + h2 + ... + hd)
Note that, c is the total number of else branches, d is the total number of case nodes, and, h1 + h2 + … + hd is the total number of when branches. So using E, C, and, W per the assumption:
PC = CC + E + 0.8 * C - 0.8 * W
=> PC = CC + E - 0.8 * (W - C)
It is easy to count the values of E, C, and, W from the code itself, so, we need not calculate the perceived complexity using the pseudocode from part two.
def hoge -- CC = 1
return :foobar if foo && bar -- CC = 3 baz =
case msg -- C = 1
when :qux -- W = 1, CC = 4
when :quux -- W = 2, CC = 5
end plugh =
if corge -- CC = 6
elsif grault && garply -- CC = 8
elsif grault -- CC = 9
elsif garply -- CC = 10
else -- E = 1
end quuz =
case xyzzy -- C = 2
when :foo -- W = 3, CC = 11
when :bar -- W = 4, CC = 12
when :thud -- W = 5, CC = 13
end if baz && (plugh || quuz) -- CC = 16
else -- E = 2
endPC = CC + E - 0.8 * (W - C)
= 16 + 2 - 0.8 * (5 - 2)
= 16 + 2 - 2.4
= 16 - 0.4
Cyclomatic Complexity and ABC Metric
The conditions component of the vector <A, B, C> is the sum of the total number of comparison operations except for the spaceship operator and cyclomatic complexity. No direct relation between cyclomatic complexity and ABC metric is possible.
Let a — the largest component, be the total number of assignments, b be the total number of branches, and, c be the total number of conditions. For 0 ≤ x, y ≤ a, b = a − x and c = a − y. So, a² + b² + c² = a² + (x − a)² + (y − b)². Consider a square of length a, and quarter-circles on the bottom-right and top-right vertices with a radius of (a − x) and (a − y) respectively, then the area of these shapes describes the behavior of a² + b² + c².