The Files That Keep Changing
Code churn, defect density and hotspot scoring - reading a repository's git history to find the files most likely to break next, and the thresholds I use to decide when movement has become rework.
Ask any engineer which file in the codebase they dread opening and you will have an answer in seconds — no dashboard required. The interesting part is that the repository already agrees with them. Part 5 established whether the safety net under a file would hold; this part asks which files are most likely to fall into it, and the answer comes not from reading the code but from reading its history. Git has been quietly compiling a defect-prediction dataset since your first commit. Churn analysis is simply the discipline of opening it.
The ledger you already keep
Code churn is the rate at which a file changes: lines added plus lines deleted over a window, normalised by the size of the file.
churn = (lines added + lines deleted) / total lines
The normalisation is the whole point. Three hundred changed lines landing in a 400-line rate calculator is a very different event from three hundred lines landing in a 12,000-line import pipeline, and a raw count cannot tell them apart. Normalised, the first scores 0.75 — most of the file rewritten — and the second barely registers.
The raw material is free:
git log --since="30 days ago" --numstat
Aggregate the per-file numbers over a sprint and you have a churn table nobody had to fill in, backdated to the beginning of the project. Tools like CodeScene and GitClear do the aggregation, trending and visualisation for you, but the underlying instrument is just the log you were writing anyway — which is precisely what makes it trustworthy. Nobody performs for a metric they do not know is being collected, and nobody can retrofit a tidy history onto last quarter.
What high churn signals is some mixture of design instability, unclear ownership and requirements volatility. The code that changes constantly is where the bugs, the regressions and the operational noise come from — and that is not just intuition.
The study that made history respectable
The evidence that churn predicts defects is one of the older solid results in this series. Nagappan and Ball at Microsoft Research published the relative-code-churn study at ICSE 2005, showing that churn measures were strong predictors of post-release defect density — with the emphasis on relative: it was the normalised measures, churn set against the size of what it churned, that carried the predictive power. That is why the formula above divides by total lines, and why any churn dashboard that reports raw added-plus-deleted counts is measuring activity rather than risk.
The files that keep changing are, statistically, the files that keep breaking — and you can identify them before the breakage, because the history is already written. That is the practical promise of this whole part. Every other metric in this series measures the present state of the code; churn is the one instrument that measures its trajectory.
Movement is not the crime
Here is where the metric needs handling with care, because not all churn is bad. A module in the middle of active feature development churns legitimately — that is what development looks like. The smell is rework churn: the same code being modified again and again without ever stabilising, a design losing an argument with its requirements one sprint at a time.
My working heuristic, and I want to be explicit that it is mine: I flag any module whose normalised churn stays above 0.3 per sprint for investigation. Not for judgement — for investigation. A file that absorbs nearly a third of its own size in changes during one sprint has a story; the question is which one. A feature landing is a fine answer. The same threshold breached three sprints running, on a module whose feature work supposedly finished last quarter, is a different answer, and it is usually the design telling you it wants to be something else.
The 0.3 is not a research finding and I will not dress it as one. It is a tripwire I have tuned across estates I have worked on, and the honest advice is to treat the trend as the signal and the absolute value as a conversation starter. And note the Goodhart clause from part 1 applies here with a twist: churn is hard to game upward but easy to game downward — batch your commits, squash your history, and the number flatters. Which is one more reason it informs an investigation and never an appraisal.
The old ruler in the drawer
Churn tells you where change concentrates. Defect density tells you where failure concentrates — confirmed defects per unit of code, conventionally per thousand lines:
defect density = confirmed defects / KLOC
You will still meet the historical benchmark figures for this metric: industry numbers quoted at anywhere from 1 to 25 defects per KLOC, depending on domain and maturity — figures popularised by Steve McConnell in Code Complete. I cite them as history, not as calibration: they describe codebases from decades ago, built in different languages under different practices, and pinning your 2027 targets to them would be measuring with a ruler from another era.
The way the metric earns its keep today is comparative, inside one codebase. Map bug-fix commits to modules, normalise by size, and look for the anomaly: the small utility file with a density five times the codebase average deserves more attention than the large service that rarely troubles anyone. Prefer post-release density where you can get it — pre-release counts mostly measure how hard you tested, not how reliable the code is. And when a module tops both tables at once, high churn and high defect density together, you are no longer looking at a suspicion. You are looking at a confirmed hotspot.
Three numbers, one score
Which brings me to the composite I actually rank modules by. My hotspot risk score multiplies three normalised signals:
risk = normalised complexity × normalised churn × (1 / contributor count)
Read it as a sentence: this code is hard to reason about, it changes constantly, and almost nobody understands it. Each factor alone is survivable. Complexity that never changes is a sleeping dog; churn in simple code is cheap; a single-owner module that is stable and clear is a documentation task. It is the multiplication that hurts — a file scoring high on all three is where technical debt carries its highest interest rate, because the team pays the cost of working in that code over and over, under uncertainty, with one person as the bottleneck.
Mechanically: CodeScene computes this family of analysis natively from git history; without it, a short script combining git log --numstat, your complexity tool from part 2 and git blame gets you most of the way. I rank rather than threshold — the top ten per cent of modules by risk score are my candidates for structural improvement before any major work is scheduled in them, quarterly. The recipe and the cadence are my practice, not an industry standard; the ingredients are public metrics you already have.
Who else can touch it
The third factor in that score deserves its own paragraph, because it is the one quality metric that is not about code at all. Ownership spread — the bus factor, in its morbid nickname — asks how many engineers can confidently modify a module. Run git blame across a critical file and count the contributors with a meaningful share of it. My threshold: critical modules need at least three contributors each owning more than ten per cent of the lines. Fewer than that and you have a single point of failure for incidents, a bottleneck for delivery, and a knowledge-loss risk with a notice period.
The honest limitation: blame measures who last touched a line, not who understands it. A reformatting pass, a rename, a mass-updated import block — any of these can hand “ownership” of a thousand lines to whoever ran the tool. Read the number as a prompt for the real question — if this file breaks at 2 a.m., how many people could fix it? — rather than as the answer.
The checklist I actually run
- Normalised churn per module, per sprint, trended — collected from git, gated nowhere.
- Sustained churn above 0.3 per sprint triggers an investigation, never a verdict.
- Defect density read comparatively within the codebase, post-release where possible; historical KLOC benchmarks cited only as history.
- Hotspot risk score quarterly; the top ten per cent get structural attention before major work lands on them.
- Critical modules: three or more meaningful contributors, checked before the third one resigns.
Churn analysis finds the files where defects concentrate. One class of defect, though, arrives with a severity label attached and a clock already running — and deserves its own queues, owners and reports. Next, vulnerability metrics are an operations discipline.