The Pipeline Job Everyone Rolls Their Eyes At (And Why It Still Catches Real Rot)

Part five of the pipeline series. Lint checks individual lines, type checking verifies consistency across the whole program, tests verify behavior. This job — static analysis, often via something like SonarQube — is the one that gets the most eye-rolls, and it's worth being honest about why, and where that reaction is and isn't fair.
Before the argument, play with the one number in this job that's real. Add rules to a small function and watch its complexity score and its paths grow, then move the threshold to see when the gate would fail:
Score 3 is within 8, so the job stays green. Whether that number is right depends on the system and the team.
It's not lint, even though it feels adjacent
Lint operates one file at a time, matching known-bad patterns. Static analysis of this kind looks across the whole codebase and tracks things that only exist as cross-file, structural properties: duplicated logic living in two places, functions whose branching complexity has quietly crept past anything a person can hold in their head, a file that's grown to a size where nobody wants to touch it anymore. None of that is visible from inside a single file, which is exactly why it needs its own job instead of being another lint rule.
The metric that's real: cyclomatic complexity
Cyclomatic complexity, roughly, counts the number of independent paths through a function — every if, every case, every loop condition adds one. It's not a subjective "this feels messy" score; it's a countable property of the control flow. A function with a complexity score in the 30s isn't hard to work in because someone's being precious about code style — it's hard to work in because there are, provably, dozens of distinct paths through it, and a change to any one of them risks breaking a path you weren't thinking about. That's not vibes. That's a real, measurable source of bugs. I still remember my Delta Engine days. We had a very old piece of legacy code with a complexity of about 120. When we switched this check on with a threshold of 32, it flagged code that had sat there for 10 years without anyone noticing. The right score and threshold always depend on the system and the team you work with, so there is no hard rule here.
The one that bit me directly: duplication
I've seen the same validation logic copied into two places instead of shared, because sharing it felt like premature abstraction for two call sites at the time. A requirement changed. One copy got updated. The other didn't, quietly, for months, until a bug report made the divergence obvious in production. Static-analysis duplication detection exists specifically to catch that class of drift before it ships — not because copy-pasted code is inherently wrong, but because copy-pasted code that's supposed to stay identical and silently doesn't is a real, recurring failure mode. I'll cover how to solve cases like this in the clean code series I'm starting next.
Where the eye-rolls are fair
Not everything this job flags deserves equal weight. A composite "maintainability index" or an arbitrary threshold like "no file over 300 lines" is a much softer, more debatable signal than complexity or duplication — it's a real proxy for something, but a much noisier one, and teams that treat every flagged item as equally must-fix tend to burn goodwill on the whole job. The useful version of this pipeline stage is configured deliberately — hard-gate on the metrics that are provably correlated with bugs, and treat the softer style-adjacent ones as advisory. The lazy version just turns on every default rule and wonders why nobody trusts the report anymore.
Next: the build job — where "it works on my machine" stops being an excuse, because the pipeline builds it somewhere else entirely.
Enjoyed this one? Get the next post by email — no spam, unsubscribe anytime.
Subscribe →