Blog

AI didn't make engineering discipline obsolete. It made it the whole job.

Tests, small PRs, readable code, documentation: every engineering best practice just got more valuable, because every one of them is about managing change, and change is what AI multiplied. But one practice has no guardian at all, and it's the one that decides whether your codebase survives the next two years.

There’s a story making the rounds in engineering circles, and I understand why it’s comforting: AI writes cleaner code than most humans, so the old disciplines matter less now. Fewer reviews. Lighter process. Let the tools carry it.

I think that story has it exactly backwards, and I want to walk through why, starting not with architecture but with the humble stuff: tests, naming, small pull requests. The things every senior engineer preaches and every deadline erodes.

Best practices were never about writing code

Here’s the thing about engineering best practices that gets forgotten: almost none of them exist to help you write code. They exist to help you change code later, safely, without holding the whole system in your head.

Think about what each one actually buys:

What each practice is really for

1

Tests

Not proof of correctness. Confidence to change something six months from now without fear.

2

Readable code & naming

Cheap onboarding for the next person, who is usually you, later, with no memory of why.

3

Small PRs

Units of change a human can actually hold in their head and meaningfully judge.

4

Docs & ADRs

Shared memory. The decisions that outlive the people and conversations that made them.

The common denominator: every practice manages the cost and risk of future change. None of them is about typing speed.

Now ask: what did AI coding tools actually change? Not correctness per line, not fundamentally. What they changed is volume of change. Teams that shipped five PRs a day ship fifteen. Refactors that would have been postponed forever now happen in an afternoon, because generating the code is no longer the expensive part.

If best practices are the machinery for managing change, and AI just multiplied change, then every one of those practices became more load-bearing, not less. Tests matter more because more code lands between human readings. Naming matters more because more code is read by people who didn’t write it, including the models generating the next change on top of it. Docs matter more because they’re now consumed by agents as well as people.

The data backs this up, and it’s not subtle:

What the industry data shows

8x
increase in duplicated code blocks in 2024 vs. two years prior (GitClear, 211M changed lines)
-7.2%
delivery stability per 25% increase in AI adoption (Google DORA 2024)
46%
of code in Copilot-enabled files is AI-written (GitHub research)
1 in 3
merged refactor PRs carried unreviewed structural risk (our own analysis)

Sources: GitClear AI Code Quality research, Google's 2024 DORA report, GitHub Copilot research, and our analysis of merged refactor PRs.

GitClear’s number is the one I keep coming back to. Across 211 million changed lines, 2024 was the first year that copy-pasted code exceeded refactored code. Duplication rising in lockstep with AI assistance. That isn’t a story about bad code. It’s a story about system-level properties degrading while everyone’s attention stays at the line level.

The practices that scale themselves, and the one that doesn’t

Here’s where it gets interesting. Not all best practices are equally at risk, because not all of them depend on a human paying attention.

Most of the classics have a guardian that scales automatically. Style has linters. Correctness has tests and CI. Even readability has help now, since coding assistants are genuinely good at naming and idiom. Crank the volume to 10x, and these hold the line, because the enforcement is mechanical and per-file.

But look at what’s left unguarded:

Every practice has a guardian. Except one.

PracticeWho enforces itHolds at 10x volume?
Consistent style & formattingLinters, formatters✓ Automatic
CorrectnessTests, CI, type systems✓ Automatic
Readable code, good namesReview norms + coding assistants✓ Mostly
Small, focused diffsTeam norms✓ If you insist
Dependency direction & boundariesNobody✗ Erodes silently
Coupling staying in checkNobody✗ Erodes silently
No dependency cyclesNobody✗ Erodes silently

The unguarded rows share a property: they're global. You cannot check them by looking at one file, one diff, or one PR. They exist only in the relationships between components, which is exactly what per-file tooling can't see.

This is the transition the comforting story misses. The practices that survived the volume increase are the local ones. The practice with no guardian is architecture: which component depends on which, whether boundaries hold, whether the system’s shape is drifting. And architecture is the practice where damage compounds hardest, because you can’t refactor your way out of a shape problem one file at a time.

Why architecture decays at exactly AI speed

Before AI tools, there was an accidental safety mechanism nobody designed: the speed of human typing. Code changed about as fast as a senior engineer could keep a mental model of it. Reading diffs was a workable proxy for “is the system still healthy?” because the system changed slowly enough for a head to track.

Output scaled. Oversight didn't.

Code written, before AI
1x
Code written, with AI
3-10x
Architectural review capacity, before
1x
Architectural review capacity, now
1x

The bottleneck on writing disappeared. The bottleneck on noticing what the writing did to the system is still one human head, reading diffs.

That proxy is now broken, and here’s the mechanism. A diff shows you lines. It does not show you that those lines created the first-ever edge from your core into a plugin, or closed a cycle across five packages, or modified a contract with 35 dependents. That information lives in the relationship between this change and every change before it. It is structurally absent from the thing your reviewers are reading:

The same PR, two representations

What review sees refactor: extract schema utils · +3 -0 + import ImageHeapUtils + layout = ImageHeapUtils.pack(obj) + return layout ✓ Tests passing ✓ Lint clean ✓ Review approved Three clean lines. Nothing to flag. What the graph sees core.graph core.heap core.meta ⚠ New package-level dependency cycle heap → meta → graph → heap · new with this PR

The red edge exists only in the relationship between this change and the edges that were already there. No amount of careful diff-reading surfaces it, because it isn't in the diff.

And this is exactly the pattern our own data shows in the wild: when we analyzed merged refactor PRs from popular open-source repos, a third of them moved the dependency graph in ways that deserved attention. Contracts with dozens of dependents rewritten. First-ever boundary crossings. A package cycle, born in a PR whose diff looked immaculate. All reviewed. All merged.

The bill comes due quietly

The failure mode of high-volume AI development isn’t dramatic. Nothing crashes. The failure mode is a codebase that accumulates coupling, cycles, and misplaced responsibilities one clean-looking PR at a time, until one day the symptoms surface as things nobody connects back to architecture: builds got slow. Onboarding takes months. Every estimate has a fudge factor because every change touches more than it should.

Teams that ship 10x faster while their structural oversight stays flat aren't being efficient. They're borrowing. The loan comes due as a system that technically passes every check while becoming harder to change every week, and by the time it's obvious, the cheap moment to fix it is hundreds of merges in the past.

So what do you actually do?

Keep every practice you already have. They matter more now, not less; that’s the whole first half of this post. But be honest about the gap: nothing in your current setup is watching the graph.

Closing that gap doesn’t mean hiring architects to trace dependencies by hand, and it certainly doesn’t mean slowing your team down to pre-AI speed. It means giving the one unguarded practice the same thing every other practice already has: an automatic, per-PR guardian.

That’s what Striff is. It models every pull request as a change to your dependency graph, compares before and after, and speaks up only when the structure actually moves: a coupling spike on a component everything depends on, a first-ever boundary crossing, a cycle forming. On clean PRs it stays silent. Your linter guards style, your CI guards correctness, and the graph finally gets a guardian of its own, at whatever speed your team ships.

Install the browser extension and run it on your next pull request. It takes about thirty seconds, and the architecture layer of your codebase stops being the one thing nobody’s watching.