Throw away bad (AI-generated) code
By Stefan Gussner
We have been doing this all along
AI tools have dramatically reduced the cost of writing code, but they haven't eliminated the need to learn the problem space. We often realize that our existing code is suboptimal. We build on what we learned from the existing code and rewrite it. We often justify this with the adoption of a new framework or shifting business needs, but the truth is that we’ve been doing this all along. Whether we are writing the code ourselves or guiding an AI agent, the first draft is rarely the right one.
Historically, building a throwaway prototype felt too expensive, so we'd hide our prototypes as "v1" and promise ourselves we'd clean them up in a later refactor. But we can move faster by admitting what happened: we needed a first pass through the mechanics of building the software to uncover the edge cases and pitfalls of the initial implementation. Maybe the library you picked doesn't work quite the way you expected, or some pieces don't fit together quite right.
We also get compounding requirements that we didn't foresee in our architecture. You probably know the feeling of learning about a new requirement and the dread that comes when you realize you have to hack something in or rewrite significant parts of your codebase to accommodate it.
Why it feels so good to rewrite code
After you rewrite a piece of software, you usually feel good about how it turned out. Part of this joy comes from the logic being fresh in your mind, meaning you don't have to relearn the codebase you used to know, or never knew because the developer who wrote it left the company. Maybe you became more familiar with the framework you are using and can use it more effectively during your rewrite. Sometimes you even get the bonus of using better tools and libraries that weren't available when the first version was built.
Most importantly, you have absorbed the requirements documented in the old implementation and restructured the code accordingly. You can build abstractions that actually fit those requirements and remove features that turned out to be unnecessary. During the rewrite, you run into fewer "oh, didn't know about that" moments, which allows you to make better choices.
Not just for old code
You get the very same lessons when building a new feature. During the development process, you learn through building. "That code looks so ugly," "Wow, I like how that fit together," or "Oh, I forgot about that edge case" are common takeaways while building a new feature.
When building with AI agents, you quickly spot where your prompts lacked specificity or where the agent got stuck and started piling on edge-case logic. If you prompt the agent to fix something, it adds "backward compatibility" for an interface the coding agent just wrote and nobody is using. Or it goes in circles, desperately trying to fix a bug in the increasingly messy code it has slopped together.
Just throw it away
If you find yourself staring at a sloppy PR, where the coding agent got it done but it doesn't feel right, or where it struggled and produced 3000+ lines of messy code in a single file, please do yourself and your team a favor: throw it away.
I know it took a while to get there, and it works now, but trust me: rewriting it with a more complete understanding usually goes much faster. Let your coding agent run in a worktree; it won't even keep you from working on other things. Also, you can always go back to the old feature branch if the rewrite didn't work out. That's why we have version control software, right?
Go back to your base branch, create a new feature branch, and start fresh with a new prompt. Take your previous prompts and consolidate them. Tell the agent up front about all the pitfalls you or it ran into during the first attempt. Don't try the same prompt again and hope for the best. This is about sharing your learnings upfront, so you can explore a different part of the solution space.
Instead of polluting the agent's context window and hoping it magically figures out how to refactor its own mess, we can stick with what works. We can keep building software the way we always have: throw away bad code and rewrite it. It is now cheaper than ever.