What is the difference between cyclomatic complexity and cognitive complexity as code metrics, and why was cognitive complexity introduced?
answer
- McCabe 1976 = paths = test count
- Campbell/SonarSource 2017 = comprehension
- switch: CC high, cognitive +1
- nesting penalty only in cognitive
- both per-function, blind to coupling
basics
~20 sCyclomatic complexity counts the independent execution paths through code, which estimates how many tests you need. Cognitive complexity estimates how hard code is for a human to read: it penalises nesting and ignores structures people find easy.
solid answer
~50 sCyclomatic complexity (McCabe, 1976) counts decision points — each if, loop, case, catch and boolean operator adds a path. It is a good proxy for test effort and worst-case path count, but a poor proxy for readability: a flat 12-case switch scores 12 yet reads trivially, while three nested ifs score 3 yet is much harder to follow. Cognitive complexity (G. Ann Campbell / SonarSource, 2017) was designed to model comprehension effort instead. Three rules: ignore shorthand that condenses many lines into one (a whole switch costs +1, not +1 per case); increment for each break in linear control flow (if, loop, catch, jump, mixed boolean sequences); increment extra for nesting, so a break at depth 3 costs 3. They answer different questions, so teams track both: cyclomatic for planning test coverage, cognitive for maintainability gates.
code
pseudocode · 15 lines// cyclomatic 12, cognitive 1
switch (code) {
case 1: return "a";
// ... ten more cases ...
case 12: return "l";
}
// cyclomatic 4, cognitive 10
if (a) { // +1
for (x in xs) { // +2 (+1 nesting)
if (b) { // +3 (+2 nesting)
while (c) { ... } // +4 (+3 nesting)
}
}
}go deeper
Name both, give the one-line purpose of each, and offer the switch-versus-nested-ifs example that shows they disagree.
Add the three cognitive-complexity rules and score a small snippet out loud, including the nesting increment.
Discuss which gate to apply where, why cyclomatic still matters for test planning, and the limits of both (per-function, control-flow only).
Frame them as leading indicators inside a quality strategy — thresholds on new code, exclusions for generated/parser code, Goodhart risk, and pairing with change-failure and review-latency data.
## Cyclomatic complexity (CC) Defined by Thomas McCabe in 1976. Model the function as a *control-flow graph* — nodes are statements, edges are possible jumps — and compute `E − N + 2P` (edges minus nodes plus twice the number of connected components). For one function this reduces to the rule people actually use: > Start at 1, then +1 for every decision point: `if`, `else if`, each `case`, `for`, `while`, `do`, `catch`, `&&`, `||`, ternary `?:`. The number equals the count of **linearly independent paths** through the function, which is also the minimum number of test cases needed for *branch/path* coverage of those paths. That is its real value: test planning, and a crude risk signal (McCabe suggested keeping it under ~10). **Where it misleads.** CC is blind to *shape*. Consider: ``` // A: cyclomatic 12, trivially readable switch (code) { case 1: return "a"; case 2: return "b"; ... case 12: return "l"; } // B: cyclomatic 4, painful if (a) { for (x in xs) { if (b) { while (c) { ... } } } } ``` A scores 12 and B scores 4, yet every human finds B harder. CC also gives a `catch` block the same weight as a deeply nested loop, and treats `else` as free even though the reader must remember the negated condition. ## Cognitive complexity Published by G. Ann Campbell at SonarSource (2017 whitepaper, implemented in SonarQube/SonarLint). It deliberately abandons the mathematical grounding of CC in exchange for correlating with *how hard code is to understand*. Three principles: 1. **No increment for shorthand** — structures that let the reader collapse many lines into one concept. A whole `switch` is +1 regardless of case count; a method declaration itself is +0. 2. **+1 for every break in linear control flow** — `if`, `else`, `else if`, ternary, `switch`, every loop, every `catch` clause, jumps like labelled `break`/`continue`/`goto`, recursion, and each *sequence* of like binary boolean operators. 3. **+1 extra per level of nesting** for flow-breaking structures. An `if` at nesting depth 2 costs 1 + 2 = 3. So example B above scores 1 + 2 + 3 + 4 = 10 while example A scores 1 — matching intuition, and inverting CC's verdict. ## How to use them together - **Cyclomatic** answers "how many paths must my tests cover / how many branches exist?" - **Cognitive** answers "how expensive will this be for the next person to change safely?" Neither is a measure of *design* quality: both are computed per function, so they say nothing about coupling, naming, or whether the abstraction is right. Both are also mechanical — you can lower either without improving anything (see metric gaming). Treat them as smell detectors that start a conversation, not as scores to optimise. **Edge cases worth knowing:** boolean operator sequences count differently — CC adds 1 per `&&`/`||`, cognitive adds 1 per *run* of the same operator (`a && b && c` = +1, `a && b || c` = +2). Generated code, parsers and state machines legitimately score high on both and are usually excluded from gates.
- If cognitive complexity correlates better with readability, why not delete cyclomatic complexity from the build entirely?Because it answers a different question. Cyclomatic complexity bounds the number of independent paths, which is what you need for reasoning about branch/path test coverage and for sizing a test suite. Cognitive complexity says nothing about how many tests you need.
- Can code have low cognitive complexity and still be terrible?Easily. Both metrics are computed per function and see only control flow. A function with meaningless names, hidden side effects, five boolean parameters, or a wrong abstraction can score 1. Metrics catch tangled control flow, not bad design.
Cyclomatic complexity is the number of distinct routes through a city — useful if you must drive every one. Cognitive complexity is how confusing the map is: a wide roundabout with twelve clearly-signed exits is easy, a four-level stacked interchange is not, even though it has fewer routes.
saying these in an interview costs you the question
- Saying cognitive complexity is just 'the new name' for cyclomatic complexity
- Claiming cyclomatic complexity penalises nesting — it does not
- Treating either number as a measure of overall code or design quality
- Believing a low score guarantees readable code, ignoring naming, side effects and abstraction
- Asserting cyclomatic complexity is obsolete, forgetting its role in test-coverage reasoning