skip to content

What is the difference between cyclomatic complexity and cognitive complexity as code metrics, and why was cognitive complexity introduced?

level: juniorimportance: must knowfreq 62%

answer

  1. McCabe 1976 = paths = test count
  2. Campbell/SonarSource 2017 = comprehension
  3. switch: CC high, cognitive +1
  4. nesting penalty only in cognitive
  5. both per-function, blind to coupling

basics

~20 s

Cyclomatic 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 s

Cyclomatic 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
pseudocode
// 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

for a junior

Name both, give the one-line purpose of each, and offer the switch-versus-nested-ifs example that shows they disagree.

for a middle

Add the three cognitive-complexity rules and score a small snippet out loud, including the nesting increment.

for a senior

Discuss which gate to apply where, why cyclomatic still matters for test planning, and the limits of both (per-function, control-flow only).

for a principal

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

context