Refactoring activity across millions of code changes has collapsed from 21% to under 4% since 2022. Duplicated code blocks are up 81%. We are writing more code than ever and maintaining less of it than ever — and most teams haven’t noticed yet, because the bill arrives late.

I want to be careful here, because there’s a lazy version of this argument and it isn’t the one I’m making. The lazy version says AI produces bad code and real developers don’t use it. That’s not true, it’s not interesting, and the 84% of developers using these tools daily would rightly ignore it.

The argument worth making is harder: AI coding tools are genuinely useful and they are doing measurable structural damage to codebases, and both of those things are true simultaneously because of how the incentives work. The speed is immediate and visible. The cost is deferred and diffuse. That’s the most dangerous shape a trade-off can have.

What the code itself says

The most useful evidence doesn’t come from surveys about how people feel. It comes from looking at what actually landed in repositories.

GitClear analysed 623 million code changes across 2023 to 2026. The findings are consistent, and none of them are good:

  • Duplicated code blocks rose 81% — from 40.3 to 73.0 per million changed lines.
  • Copy-pasted code grew from 9.4% to 15.7% of all changes.
  • Refactoring collapsed from 21% of changes in 2022 to 3.8% in 2026. Developers are now roughly five times more likely to duplicate code than to consolidate it.
  • Cross-file function calls fell 35% — new code is increasingly isolated rather than integrated with what already exists.
  • Updates to older code dropped 74%. Legacy sections are being frozen rather than modernised.
  • Error-masking constructs rose 47%, and two-week code churn — code written and then rewritten almost immediately — is up 15%.

Read those together and a picture forms. We’re producing a great deal of new code that doesn’t call into existing code, doesn’t get consolidated, gets abandoned faster, and swallows its own errors more often.

This isn’t a story about AI writing syntactically incorrect code. It writes syntactically fine code. It’s a story about what happens to a codebase when the cost of adding code drops to near zero while the cost of understanding code stays exactly where it was.

Why AI structurally prefers duplication

There’s a mechanical reason for the refactoring collapse, and it’s worth understanding because it explains why this won’t fix itself.

When you ask an AI to add a feature, it generates code for that feature. It doesn’t know that a nearly identical function exists three directories over, because that function isn’t in its context window. Even when it is, writing fresh code is a lower-risk action than modifying shared code that other things depend on.

Then there’s you. Reviewing a self-contained 80-line addition is easy. Reviewing a refactor that touches nine files and changes a shared abstraction is hard — and you didn’t write any of it, so you have no mental model of it. Faced with two AI-generated options, the reviewer approves the duplicate. Every time.

Multiply that by every feature, every sprint, across a whole team. Nobody made a decision to stop refactoring. It simply became the path of least resistance at every individual step.

The plausibility problem

Human-written bugs usually look like mistakes. You read the code and something feels off — an odd variable name, a weird indentation, an obviously rushed section.

AI-written bugs look like correct code. Idiomatic naming, consistent formatting, sensible structure, sometimes a helpful comment explaining the thing it’s doing wrong. Your reviewing instincts are tuned to spot carelessness, and there is no carelessness to spot.

Here’s a real category of example — code that will pass review from most developers most of the time:

javascript
// Deactivate every expired subscription, then send one summary email.
async function processExpiredSubscriptions(userIds) {
  const deactivated = [];

  userIds.forEach(async (id) => {
    const sub = await db.subscriptions.findByUser(id);
    if (sub && sub.expiresAt < Date.now()) {
      await db.subscriptions.deactivate(sub.id);
      deactivated.push(sub);
    }
  });

  await sendSummaryEmail(deactivated);
  return deactivated;
}

It reads fine. It has a clear comment. The naming is good. It is also completely broken: forEach does not await its async callback, so sendSummaryEmail fires against an empty array while the deactivations are still in flight, and the function returns []. In production it deactivates the subscriptions correctly and silently emails nobody about it — the kind of bug that surfaces three weeks later during a billing dispute.

Every experienced JavaScript developer knows this trap. The point isn’t that it’s subtle in isolation — it’s that it’s invisible at review speed when it arrives inside a 400-line diff alongside eleven other things that are all correct.

Now consider that AI has made 400-line diffs cheap to produce and no cheaper to review.

The productivity result nobody wants to talk about

In 2025, METR ran a randomised controlled trial with experienced open-source developers working on real tasks in repositories they knew well. Half the tasks allowed AI tools, half didn’t.

The developers using AI were 19% slower.

Afterwards, those same developers estimated that AI had made them about 20% faster. They were wrong by roughly forty percentage points about their own performance, on tasks they had just completed.

Two caveats matter and I’ll state them plainly. The sample was small, and it tested experienced developers on codebases they already knew deeply — the scenario where AI has least to offer, since the expert already holds the context the AI has to rediscover. It doesn’t generalise to a junior on an unfamiliar codebase, where the gains are probably real and large. METR themselves have since revised their experiment design.

But the perception gap is the finding that should worry you, and it’s the part that generalises. DORA found over 80% of technology professionals believe AI has increased their productivity. That belief is not measurement. It’s the same self-report that was off by forty points in a controlled setting.

The felt experience of AI-assisted work is smooth. Less typing, less looking things up, fewer moments of being stuck. Smoothness is what we’re actually measuring when we say “faster” — and smoothness and speed are not the same variable.

The verification burden

Around 30% of developers report little to no confidence in AI-generated code. The reasonable response to low confidence is careful review. But careful review of code you didn’t write is slower than writing it yourself, for anything non-trivial.

This is the trap. Generation is nearly free; verification is not, and verification cost scales with how much you don’t trust the output. The time doesn’t disappear — it moves from a phase that feels like work (writing) to a phase that feels like overhead (reviewing), and overhead is precisely what humans skimp on under deadline pressure.

DORA’s data reflects the outcome: higher AI adoption correlates with higher delivery throughput and higher delivery instability. More shipped, more broken. That’s what it looks like when verification is the step that quietly gets skipped.

The junior developer problem

This is the cost I’d weight most heavily over a ten-year horizon, and it’s the least measurable.

Expertise comes from struggle. You become good at debugging by sitting with a bug for two hours, forming five wrong hypotheses, and eventually finding the truth. That process builds the intuition that lets you glance at code later and sense that something’s wrong. It’s miserable and it’s how the skill is built. There is no other route.

A junior developer with an AI assistant can now skip that entirely. Paste the error, get a fix, move on. The ticket closes. The learning doesn’t happen.

Here’s the sharp edge of it: the skill most needed to use AI safely — the ability to look at plausible-seeming code and sense that it’s wrong — is exactly the skill that AI use prevents you from developing. Senior developers can use these tools well because they spent years without them. It’s not obvious how the next cohort acquires that judgement.

I don’t have a clean answer. The best I’ve seen in practice is deliberately protected struggle time: juniors attempt work unaided first, then compare against AI output, with the comparison itself being the lesson. That requires a team culture that values learning over ticket velocity, which is rarer than it should be.

What honest mitigation looks like

None of this argues for banning the tools. It argues for treating the costs as real and budgeting for them explicitly, the way you’d budget for any other form of debt.

  1. Cap diff size, seriously. If a pull request exceeds a few hundred lines, it isn’t being reviewed — it’s being skimmed. Make this a hard rule, not a guideline.
  2. Measure duplication, not just coverage. Add a clone-detection check to CI and fail the build when duplication crosses a threshold. If you don’t measure it, the GitClear numbers are your future.
  3. Schedule refactoring as work, not as slack. Refactoring has stopped happening organically because AI removed the friction that used to force it. It now needs to be a ticket with an owner and an estimate.
  4. Enforce “explain it or don’t merge.” The single most effective cultural intervention. If you can’t answer why a line is there, it doesn’t go in.
  5. Ban AI-generated error handling from review-by-default. Error-masking constructs are up 47%. A generated try/catch that swallows an exception is worse than no error handling at all, because it hides the failure.
  6. Track your own delivery metrics. Change failure rate and time to restore will tell you whether your throughput gain is real or whether you’ve just moved the work downstream to incidents.
  7. Stop trusting the productivity feeling. If you want to know whether AI is making your team faster, measure cycle time and failure rate before and after. Self-report has a documented forty-point error bar.

The fair conclusion

AI coding tools are useful. I use them, most working developers use them, and the previous two posts in this series make a serious case for what they’re good at. This isn’t a call to go back.

It’s a call to be honest that we’ve taken on a loan. The interest is paid in duplicated logic nobody consolidates, legacy code nobody touches, subtle bugs that pass review because they look tidy, and a generation of developers who may never build the instinct to catch them.

DORA’s word for AI was amplifier. Amplifiers work in both directions. If your team has strong review culture, good tests, and time budgeted for maintenance, AI will make you meaningfully better. If it doesn’t, AI will help you accumulate technical debt faster than any tool in the history of the profession — and it will feel great while you do it.

That feeling is the problem. Measure something instead.

Key takeaways

  • Across 623 million code changes, refactoring fell from 21% to 3.8% while duplicated blocks rose 81% and copy-pasted code grew from 9.4% to 15.7%.
  • AI structurally prefers duplication: it can’t see code outside its context, and reviewers find self-contained additions far easier to approve than shared refactors.
  • AI bugs are dangerous because they’re plausible — idiomatic, well-named, well-commented code that happens to be wrong slips past instincts tuned to spot carelessness.
  • A METR randomised trial found experienced developers were 19% slower with AI while estimating they were 20% faster — a forty-point perception gap.
  • Verification cost is the hidden expense. Generation is free; careful review of code you didn’t write is slower than writing it, and it’s the step teams skip under pressure.
  • The skill needed to use AI safely is the skill that AI use prevents juniors from developing.
  • Mitigate with hard diff-size caps, duplication checks in CI, scheduled refactoring, “explain it or don’t merge,” and measured delivery metrics rather than self-reported productivity.

Frequently asked questions

Is AI-generated code actually worse than human-written code?

Not line by line — it’s often cleaner. The problem is structural rather than local: it duplicates instead of reusing, doesn’t integrate with existing abstractions, and is produced faster than anyone can meaningfully review. The damage shows up at the codebase level, not in any individual function.

Does the METR study mean I should stop using AI tools?

No. It tested experienced developers on codebases they knew intimately, which is the scenario where AI helps least, and the sample was small. The durable lesson isn’t “AI is slower” — it’s that developers are unreliable judges of their own productivity, so decisions should rest on measurement rather than on how the work feels.

How do I measure whether AI is helping my team?

Track cycle time from first commit to production, change failure rate, and time to restore service. Add a duplication metric from a clone-detection tool. Compare a period before heavy AI adoption with one after. If throughput rose and failure rate rose with it, you’ve shifted work into incidents rather than eliminating it.

What’s the single most effective safeguard?

A hard cap on pull request size. Almost every problem described here — unreviewed duplication, plausible bugs slipping through, swallowed errors — is downstream of diffs being too large to review properly. Small diffs restore the one control that actually works.

How should teams train juniors in this environment?

Protect struggle time deliberately. Have juniors attempt problems unaided, then compare their solution with an AI’s and discuss the differences — making the comparison itself the lesson. Pair programming and code review with senior developers matter more now, not less, because they’re the remaining places where reasoning gets transferred rather than just output.

Add a response

Your email address will not be published. Required fields are marked *