What is code complexity?
"Complexity" gets used as if it's a single measurable thing. It isn't. At least three different, only loosely correlated properties get called complexity, and confusing them leads to fixing the wrong problem.
Cyclomatic complexity — how many paths
Introduced by Thomas McCabe in 1976, this counts the number of independent paths through a function's logic: every if, loop, case, and catch adds one to a baseline of 1. It's a path count, nothing more — it treats a flat sequence of 10 independent if statements the same as 10 statements nested five levels deep, even though the second is much harder to read.
Cognitive complexity — how hard to hold in your head
A newer metric (introduced by SonarSource in 2016) built specifically to fix that blind spot. It penalizes nesting explicitly: a branch inside a branch inside a loop costs more than the same three branches laid out flat, because that's genuinely closer to how much harder the nested version is for a human to trace mentally. Two functions can have identical cyclomatic complexity and very different cognitive complexity, depending purely on how the branches are arranged.
Structural complexity — how tangled the codebase is
This one isn't about a single function at all. Fan-out (how many other files a file depends on) and fan-in (how many files depend on it) measure coupling: a file with high fan-in is risky to change because everything touches it; a file with high fan-out is fragile because it depends on a lot of moving parts elsewhere. A codebase can have simple, low-complexity individual functions and still be a nightmare to change if the coupling between files is bad.
A concrete comparison
High complexity, shallow nesting
def classify(x):
if x == 1: return "a"
if x == 2: return "b"
if x == 3: return "c"
if x == 4: return "d"
if x == 5: return "e"
return "f"
Low complexity, deep nesting
def process(items):
if items:
for i in items:
if i.valid:
if i.ready:
i.run()
The first function has higher cyclomatic complexity (six branches) but is trivial to read. The second has lower cyclomatic complexity (three branches) but is harder to trace because the reader has to track three nested conditions at once. Neither number alone tells the whole story.
Why REPO-SIGHT's health score blends more than one number
This is exactly why a single score shouldn't rely on cyclomatic complexity alone. REPO-SIGHT's health score weighs five components together — complexity density (35%), average function length (25%), comment density (20%), TODO density (10%), and max nesting depth (10%) — specifically because complexity by itself misses the nesting problem, and nesting by itself misses the sheer-size problem. See the full breakdown of how the grade is calculated.