We had bad code long before we had AI and vibe coding. The way this would come about is people carelessly piling features and complexity on top of an existing code base without taking care to maintain and improve it. As all that cruft accumulates, adding new features becomes harder and harder, until everything is so tangled and messed up that nothing works anymore. The system's complexity has outgrown the capacity of those who created it.
Enter AI. Undaunted by logic that's spread over dozens of files, and indefatigable in its attempt to get just one more feature shipped, it might very well let you keep working on that messy code base a little while longer.
But a fundamental truth remains: Left unchecked, any coder, whether human or AI, will create a system that is too complex for it to comprehend. Maybe that threshold gets crossed a little later with AI, but it is there and it cannot be escaped.
The key phrase is the "left unchecked" part. Current coding agents seem to be trained to please unreasonable managers at any cost. That means shipping features as fast as possible and not caring about boring stuff like maintainability, refactoring, and complexity. Let our future selves worry about that.
That's where we, as software engineers, get to apply our judgment. And it doesn't have to mean checking every AI change ourselves. It does mean setting up an environment that pushes back on complexity, much of which can be automated, some of which involves creative nudges (e.g. "Could we replace these nested conditionals with a hand-rolled state machine?")
In a very large project, adding new features will inevitably be slower than in a small and fresh project, as it needs to fit neatly with what's already there. The role of good design is to ensure that development doesn't crawl to a halt and instead progresses steadily.
Tips for you: If you're struggling with that in your codebase or are worried that it could happen soon, here are few quick wins:
Use a simple code analysis tool that identifies the most complex parts (functions that are too long, classes with too many public methods, that sort of thing), then ask the AI to tackle the worst offenders. You can even automate that as a regular job.
Encourage the agent to spend time after shipping each feature to do the "refactor" step of the red/green/refactor loop that's integral to test-driven development.
Instruct your agent to flag when making a change like adding a feature or fixing a bug felt harder than it needed to be, then log and tackle those issues.
That should already get you quite a bit further than your average self-proclaimed agentic coder. If you find that this isn't enough in your particular case, though, hit reply and tell me about it.
