The bottleneck isn't writing code anymore. It's understanding it.
This week I was working on one non-critical feature that seemed simple at first sight. 50k lines of code later, it seemed to work as expected. In a side project, or a service where “nobody will be upset if it’s dead and kills everything around”, it would be ready to ship. But for a production-grade project, the risk of an outage is too big to skip reading the code. Unfortunately, reviewing 50k lines of AI-generated code is much harder than reviewing 50k lines written by a human.
We’re now obsessed with how much code we can create fast. But is it the right thing to optimize for? The biggest bottleneck of implementation quietly shifted from producing code to reading code. Fortunately, we don’t need to invent how to make code more readable: software engineering has had solutions for that for decades.
The next bottleneck: creating code that we can be accountable for
Many people no longer read the code that they ship. So why should we care about good coding practices and code quality if agents don’t? Keeping our code readable is still critical for one reason: it helps us overcome our biggest bottleneck, the human.
When you write code by hand, you have the entire context of what you implemented. With agent-generated code, you have to rebuild that context, and it’s easy to get overwhelmed. You miss bugs that nobody would ever write by hand. You also lose the edge cases you would have found while writing the code yourself.
We can review less code than before. It may be tempting to skip review entirely, but that’s throwing the baby out with the bathwater. The last block in the diagram is “successful delivery” for a good reason: our goal is not just to ship, but to ship working things that don’t break other things and won’t slow us down in the long term. Judging by how many outages big companies had recently, this goal is not obvious to everyone.
It’s a well-known pattern: new techniques and tools make top-performing teams even faster, while low performers get slower. It happened with the cloud and with microservices. The pragmatic teams shipped faster, while low performers got stuck in never-ending migrations. The same will happen with AI. Teams with high friction between idea and implementation won’t see the same performance gain. And if you invest in AI in the wrong places, you may even end up slower.
You can generate 100k lines of code and burn thousands of dollars on tokens in one day. That means nothing until you’re sure it works, doesn’t break other things, and solves the problem it should. In other words, it doesn’t matter how much code you can generate, what matters is how much of it you can take accountability for and whether it solves a real problem.

You generated a new feature and after a couple of iterations you believe it’s ready. What now? You have a couple of options for how to find out if it works as expected:
- Just create a PR without reading the code and let the reviewer check the feature…and wait for your team to hate you for submitting slop-PRs.
- Just read the tests and pray that AI agents didn’t forget any edge cases, that they covered all side effects, and that previous features are also protected against regressions.
- Read and understand the damn code.
The third option is the safest, but unfortunately the hardest one.
Maybe we saved a lot of time we would spend on writing code, but now we have a harder task: reviewing it. The volume of code generated by agents is much bigger than what people used to write by hand. What’s worse, reviewing code written by an agent is much harder than reviewing code that you have written by hand.
After spending hours reading and fixing the code, you start thinking “Maybe writing it by hand would be faster…”. Writing by hand sounds like a comfortable solution, but even counting the hours you spend polishing the agent’s code, you would not be faster. What helps here is making the agents’ code more readable.
The good news is that we don’t need to reinvent the wheel. Creating readable code is something that software engineers have been trying to figure out for several decades. Good practices exist to help us extend code faster. But we often miss the one part that matters most for review: readability.
Not all software is the same
We have always been big advocates of Domain-Driven Design and Clean Architecture in the Go community. We have seen how they helped us to rescue many projects. To our surprise, promoting them used to trigger pushback from many people saying “it’s overengineering and Go code should be simple”. And they have been right: Using DDD and Clean Architecture leads to overengineering… and so does skipping them. It all depends on the kind of project you apply them in and on how well you understand them.
When we talked to skeptics who advocate for “Simple Go”, we quickly figured out that their opinion often came from a single poorly implemented project. Usually, the people who built that project had no idea how to use those tools. Or this project was just a simple CRUD that didn’t need any sophisticated techniques. Any tool, when wrongly used, does more harm than good.
What works for prototypes, CRUDs, and side projects doesn’t work for production-grade complex projects. On the other hand, prototypes and simple code will suffer from many ceremonies that production-grade critical software needs. The difference matters more than ever with AI-assisted coding.
Not reading generated code is also fine
I don’t read every piece of AI-generated code. One type of code I often don’t review at all is the presentation layer (frontend, for example). As long as it looks good and works as expected, I don’t care about the implementation. This is where any kind of layered architecture helps us: we separate the boring code from the critical code, so we don’t need to spend the same mental effort on all of it.
Next time you hear someone say they never read generated code, check what kind of code they write. Most of the time it may be presentation-heavy non-critical software. It can be a sane strategy, as long as you apply it deliberately to one part of the project.
The more things change, the more they stay the same
Many software engineers now face an existential crisis: did everything we learned over the years become obsolete? If someone spent years learning languages, frameworks, and vim motions, then it’s true: those skills are much less relevant now.
Even if we see more and more examples of agents doing impressive work, it’s mostly in scenarios with a clear feedback loop that agents can “brute-force”. The challenge starts when success criteria are unclear. That describes most of the business software we create.
I also see arguments like “software is dead, my girlfriend just vibe coded in a weekend what I used to write in half a year”. Even if it may be true, we come back to the same point: not all software is the same. Shipping a PoC in a weekend is light years from building production-grade software with many users. If that PoC became popular, it would take a team of engineers to develop it and keep it working (and making money).
An expert product engineer decides what to build and why, not only how. If that’s you, your knowledge of what code to write is still valid and in demand. Part of this job was always taking accountability for the changes we ship. It doesn’t matter if the code was written by hand or generated by an agent: you ship it, you own it. Not much has changed. Taking accountability was always the area where the best job offers were sitting.
Good coding practices were never for the machines. Compilers never cared about them, and agents may work slightly better with clean code, but they are fast enough without it. Good practices were always for you, the person accountable for what you ship.
The one thing that changed is that we, as software engineers, now have to figure out how to collaborate with agents to create code efficiently. In the next posts, we’ll show you how we do it.


