codeintelligently
Back to posts
Code Intelligence & Analysis

Code Churn: What It Tells You About Team Health

Vaibhav Verma
7 min read
code churnmetricsteam healthcode intelligencetechnical debt

Code Churn: What It Tells You About Team Health

I once inherited a codebase where the payments module had a churn rate 4x the rest of the system. The code looked fine. Tests passed. SonarQube gave it a passing grade. But every sprint, 3-4 files in that module were being rewritten. Not extended. Not refactored. Rewritten.

Turns out, the original architect had left the company, the documentation was nonexistent, and every developer who touched the module was essentially re-solving the same problems from scratch because they couldn't understand the existing solutions.

No static analysis tool would have caught that. Code churn did.

What Is Code Churn?

Code churn measures how frequently code is being rewritten or modified. The simplest definition: the number of lines added, modified, or deleted in a file over a given period. But raw line counts aren't particularly useful. What matters is the ratio and the pattern.

There are several ways to measure churn:

  • Absolute churn: Total lines changed in a time period
  • Relative churn: Lines changed divided by total lines in the file
  • Rework ratio: Lines changed within 2-3 weeks of being written (this is the one that predicts bugs)
  • Author churn: How many different developers have modified a file

The rework ratio is the most telling. Code that's written and then immediately rewritten signals one of several problems: unclear requirements, missing tests, knowledge gaps, or poor design.

Healthy vs Unhealthy Churn

Not all churn is bad. This is the mistake I see most teams make when they first start measuring it. They see high churn and panic. But churn has context.

Healthy churn looks like:

  • A new feature being actively developed (churn is high, then drops off after release)
  • A planned refactoring effort (churn spikes during the refactor, then stabilizes at a lower baseline)
  • Test files changing alongside source files (tests should churn when code churns)

Unhealthy churn looks like:

  • The same files churning sprint after sprint with no planned refactoring
  • Churn concentrated in a small number of "usual suspect" files
  • High rework ratio: code being rewritten within days of being committed
  • Churn that doesn't correlate with feature delivery (lots of changes, no new capabilities)

Here's a quick diagnostic I run on every codebase I work with:

bash
# Top 20 most frequently changed files in the last 90 days
git log --since="90 days ago" --pretty=format: --name-only | \
  sort | uniq -c | sort -rn | head -20

# Files with the most authors in the last 90 days
git log --since="90 days ago" --format='%an' --name-only | \
  awk '/^$/{next} !author{author=$0;next} {print author, $0; author=""}' | \
  sort -k2 | awk '{print $2}' | uniq -c | sort -rn | head -20

If the same files show up on both lists, you've found a hotspot that's also a knowledge bottleneck.

The Churn-to-Complexity Matrix

The real power of churn data comes when you cross-reference it with complexity. I use a 2x2 matrix:

Low Complexity High Complexity
Low Churn Leave it alone Worth watching
High Churn Normal development Refactor NOW

That top-right quadrant (high complexity + high churn) is where bugs breed. These are the files that are hard to understand AND constantly being modified. Every modification is a gamble because the developer might not fully understand the implications of their change.

I call these files "complexity traps," and I've found that addressing just the top 5 complexity traps in a codebase can reduce bug rates by 30-40%.

The Framework: CHURN Diagnosis

When churn signals a problem, here's how I investigate:

C - Count: Measure the churn. Get the numbers. Which files? How often? How many authors?

H - History: Read the git log for your high-churn files. What kinds of changes are being made? Are they bug fixes? Feature additions? Reformatting? The commit messages tell the story.

U - Understand: Talk to the developers. Why does this file keep changing? Is it because requirements keep shifting? Because the abstraction is wrong? Because there's a missing test that lets regressions through?

R - Root cause: Identify the underlying issue. In my experience, it's one of five things: unclear requirements (product problem), wrong abstraction (design problem), missing tests (quality problem), knowledge gap (people problem), or external dependency changes (integration problem).

N - Neutralize: Address the root cause, not the symptom. Adding tests to a file won't help if the real problem is that requirements change every sprint. Refactoring won't help if the team doesn't understand the domain.

The Contrarian Take: Stable Code Isn't Always Good Code

Teams tend to celebrate stability. "This module hasn't been touched in 18 months!" That's not necessarily good. If the module is mature and feature-complete, stability is great. But if the module hasn't been touched because everyone's afraid of it? That's a different story.

I call this "fear-frozen code." It's code that should be changing (because the business requirements around it have changed) but isn't (because the last three people who touched it caused production incidents).

Fear-frozen code doesn't show up in churn analysis. It shows up in the negative space. Look for modules where feature requests and bug reports pile up but code changes don't. That gap between demand and delivery is a signal.

Tracking Churn Over Time

The most useful view of churn is the trend line. A single snapshot tells you very little. But churn tracked over 6-12 months tells you whether your codebase is getting healthier or sicker.

Set up a weekly job that runs your churn analysis and logs the results. Plot the top 10 churning files each month. If the same files keep appearing, you've got a systemic problem. If different files appear each month, your churn is healthy, driven by active development, not rework.

Tools like CodeScene automate this entirely and give you trend visualizations out of the box. But you can get 80% of the value with a cron job and a spreadsheet.

What Churn Tells You That Nothing Else Can

Code churn is a proxy for organizational health. When churn patterns are healthy (focused, intentional, tapering off after feature completion), your team is communicating well, requirements are clear, and designs are solid.

When churn patterns are unhealthy (scattered, persistent, concentrated in the same files), something is broken in the system around the code. Maybe it's requirements. Maybe it's team structure. Maybe it's missing domain knowledge.

The code is just the symptom. Churn helps you find the disease.

$ ls ./related

Explore by topic