Blog
The half-life of engineering best practices
AI agents aren’t just changing how fast we write software. They’re changing the economics behind decades of engineering wisdom.

Senior engineers carry around an extraordinary compression of experience: Don’t rewrite that system. Keep pull requests small. Design the interface carefully because changing it later will be expensive. Don’t generate code you can’t review. Prototype before committing. Make irreversible decisions slowly.
These aren’t arbitrary rules we learned from textbooks. They’re scar tissue. Most exist because, at some point, someone learned the expensive way what happens when you ignore them. But scar tissue encodes the environment in which the injury happened, and that environment is changing.
At Poolside, we pushed this to an extreme in January 2026 in an experiment called Project Deep End: for multiple weeks, I asked my team to not write code by hand. Agents wrote all of it. Humans wrote intent and reviewed the result against the specification. If someone had to step in and manually correct an agent, we treated that as a failure of our system: something about how we thought about the problem hadn’t made it into the harness yet.
Many of the constraints around which we had built our engineering practices suddenly looked different. Implementation wasn’t necessarily the expensive part anymore. Sometimes review was. Sometimes context was. Sometimes the bottleneck was a piece of senior engineering knowledge living in someone’s head. It left me with one question:
Which of our engineering best practices are fundamental truths, and which are adaptations to costs that are rapidly changing?
Every best practice has a price hidden inside it
Consider a phrase most experienced engineers have probably said (and I can’t count the number of times I pushed back with this sentence):
“We should think carefully about this API. Changing it later will be expensive.”
There are several things hiding inside “expensive.” Perhaps changing the API introduces genuine product risk. Perhaps external consumers depend on it. Perhaps two systems need to remain compatible during a migration. Those costs don’t magically disappear because an LLM can write code.
But there’s another kind of expense we’re so accustomed to that we rarely make it explicit. Someone has to find the 87 call sites. Update them. Fix the tests. Chase the type errors. Open a sequence of PRs and coordinate the rollout.
For most of software engineering history, changing software has meant paying for human attention one edit at a time. That economic reality is embedded in our engineering culture: we invest heavily in getting abstractions right, avoid large refactorings and debate alternatives before implementing them, because implementing three options just to throw two away is expensive.
None of these practices are wrong. But some of the prices from which we derived them are changing. An agent doesn’t care whether a mechanical migration touches 8 files or 800 in quite the same way a human does. It doesn’t get bored on the 47th call site. It can implement an approach, run the tests, discover that it doesn’t work, throw it away, and try another.
That doesn’t make an 800-file change safe. It changes which part of the 800-file change is expensive.
On an early platform team, we had to pick a logging framework. Because of our architecture, it wasn’t just our team’s choice: every team in the company would have to use it. We spent a couple of days trying the state-of-the-art frameworks of the time, running them through benchmarks and through the scenarios we expected to need. Back then, that care was justified. Every log line in the company would depend on the choice. You can hide a logging framework behind an abstraction, and usually you should, but things always leak through. Many of those abstractions end up rebuilding the framework’s whole API surface.
Today, choosing a logging framework is a simple decision, because changing it later is cheap. It goes further than that: when the cost of change is that low, is it still a decision a human needs to make at all? Some decisions like this should move from humans to agents.
Don’t make the old SDLC faster
There’s a tempting way to introduce agents into an engineering organization. Take the existing software development lifecycle and insert AI into it:
Ticket → engineer → agent writes code → engineer reads code → PR → reviewer reads code → merge.
Congratulations: you’ve added a very fast typist to your existing system.
The experiment showed us what happens when you push further. Agents could produce work faster than humans could approve it. Suddenly, the queue in front of the reviewer became the slowest station on the line. Increase the throughput of one stage of a system dramatically and the bottleneck moves somewhere else.
Yet a surprising amount of the conversation about developer productivity still asks how much faster AI can make implementation. That’s becoming the less interesting question. The better one is: Why does our review process look the way it does?
Code review evolved partly because humans make mistakes while producing code, and another human reading the change provides an important quality boundary. But if more of the implementation is generated, perhaps some verification should shift too.
In the experiment, humans evaluated output against the intent rather than treating the diff itself as the primary artifact. Agents were expected to produce evidence alongside their changes. In one workflow, that meant screenshots of a working feature attached directly to the pull request.
Maybe humans should spend less time verifying whether line 438 calls the right helper and more time asking whether the change satisfies the intended behavior, preserves the important constraints, and provides convincing evidence that it works. The artifact we review may slowly shift from “Here is some code. Please understand whether it is correct.” toward “Here is the intent, the implementation, and the evidence. Please decide whether the evidence is sufficient.”
What if trying three things is cheaper than debating one?
There is another engineering ritual worth repricing: the design discussion.
I used to run a platform SDK team that built framework APIs seven other teams depended on. Every new feature meant new API surface, so we had a rule: come up with three different proposals for the design, then sit together in a technical assessment meeting and verify the choice against the requirements of all seven teams. Those teams were all internal, so we had full control over every consuming component. Each of them owned up to 20 components that depended on our API. Getting an API wrong was still extremely expensive. Fixing it meant coordinating seven teams, all on tight startup schedules, to adapt their components. The changes themselves weren’t the bottleneck. The coordination was.
This can be excellent engineering. It can also be an optimization for a world in which implementation is too expensive to use as a thinking tool. What happens when that’s no longer true?
Instead of three proposals on paper and a meeting to pick one, perhaps an agent implements all three against the real call sites. Run them. Benchmark them. Break them. See which abstraction survives the awkward edge case, and ask another agent where complexity accumulated. Then make the architectural decision with evidence that previously would have been too expensive to acquire. And if the choice still turns out wrong, moving from one API shape to another could be driven by a single team instead of coordinated across seven.
This doesn’t eliminate design. It changes when design happens. We have historically treated implementation as something that follows thinking: think → decide → implement. Cheap implementation makes another loop increasingly viable: think → implement → observe → discard → think again. Software becomes a medium for reasoning, not merely the output of reasoning. An implementation can answer a question without earning the right to survive.
The senior engineer’s job becomes less about predicting every consequence before code exists and more about designing experiments that expose the consequences we care about.
Part of that job is judging whether you can manage the impact of a change at all. On the SDK team, we controlled every call site, so an agent could migrate them. At Gradle, the APIs we published were used by millions of developers around the globe, and nobody could migrate their builds for them. There, the cost of getting an API wrong hasn’t changed much, and whether agents can pick up the work looks very different.
Senior expertise isn’t becoming less valuable
You could read all of this as: experience matters less. I think the opposite is happening.
One of my favorite examples from Deep End involved database migrations. For years, migration PRs attracted comments from the same experienced engineers. Think about locking. Don’t do the backfill like this. Consider rollout order. What happens while these two versions coexist? Those comments represented years of accumulated operational scar tissue.
During the experiment, we pointed an agent at two years of those PRs and asked it to distill the review history into a reusable skill. After that, agents could approach new migrations with those lessons before a human reviewer ever saw the change.
Look carefully at what happened there. We didn’t eliminate senior engineering expertise. We amplified it.
Previously, the organization consumed that expertise one pull request at a time. A senior engineer knew something. A less experienced engineer opened a PR. The senior engineer spotted the problem. Then, six weeks later, someone made a similar mistake and the process repeated.
We tend to call that mentoring. But when the same judgment is being applied repeatedly, there’s another way to look at it: it’s an automation opportunity. The senior engineer’s most valuable contribution isn’t necessarily writing the 48th excellent review comment. It may be making sure nobody in the organization needs the 48th comment.
Software production is becoming cheap. Comprehension isn’t.
Agents can make producing software cheaper. They do not make complexity disappear. In fact, cheap production can make complexity considerably worse.
If every engineer can generate ten times as much code, ten times as many abstractions, ten times as many services and ten times as many configuration options, we haven’t created a ten-times-more-productive engineering organization. We’ve created an incomprehensible one.
Agents are making production abundant while human comprehension remains scarce. The valuable question becomes less “How much software can we produce?” and more “How much software can we confidently understand, validate, operate and change?”
This is why I don’t think the future belongs to organizations that simply generate the most code. It belongs to organizations that become exceptionally good at turning intent into validated outcomes while keeping their systems comprehensible. That requires understanding where complexity accumulates and being willing to remove things agents can produce just as easily as we add them.
And it requires senior engineers. But perhaps not always doing the things that made them senior engineers in the first place.
Reprice before you optimize
Every heuristic contains hidden assumptions about the environment in which it was learned. This creates an uncomfortable possibility: the people with the most experience can sometimes have the most assumptions to reprice. Precisely because experienced engineers have spent decades building an extremely effective model of what is expensive, risky and difficult.
I recognize this in myself. When I see a problem, I have an instinctive sense of its size. That’s a two-day refactor. That’s going to touch half the repository. We should avoid changing that interface. Increasingly, I have to ask myself: is that estimate about the complexity of the problem, or is it a memory of how much human labor this problem used to require? Those are becoming different things.
I’ve built enough parsers and compilers to know they always take longer than planned, so that’s where agents surprised me most.
Recently I was digging through a large set of agent trajectories, trying to build some intuition for the data, the behavior and the complexity of those sessions. I wished I had a query language shaped around the questions I was asking. So an agent built one: a lexer, a parser, and a translation into queries against the data lake. It didn’t need to become a product. I used it for a few hours, got the insights I needed, and threw it away. Previously, I would never have considered building a query language just to explore a dataset: my internal cost model priced it as a project, not an afternoon.
So start examining the assumptions. The next time an experienced engineer says something will be too expensive, ask which cost they’re referring to. When a reviewer leaves the same sophisticated comment for the tenth time, ask whether that judgment can become infrastructure.
None of this tells us which current best practices will survive. That’s exactly the point. Best practices aren’t laws of physics. They are accumulated answers to the conditions under which we build software. Some are rooted in fundamental properties of complex systems and human cognition. Those may become more important as software production accelerates. Others are clever adaptations to the economics of human software development.
Those have a half-life.
Our responsibility as senior engineers isn’t to defend them because they made us successful. It’s to understand why they made us successful — and notice when the reason changes. The uncomfortable question for experienced engineers isn’t whether agents can do our jobs.
It’s whether we’re still optimizing our jobs around constraints that no longer exist.
Thoughts?
If this post sparked a question or a disagreement, I'd like to hear it.