The driver in the cockpit: The human element in AI-assisted development
The ability to speed up development using AI is undeniable, but simply letting AI set the pace is a high-speed gamble. While it accelerates initial development, you risk losing control without a steady hand on the wheel. As a developer, you are the driver in the cockpit, it is your responsibility to steer the AI, ensuring that the code you ship isn’t just fast, but secure and truly maintainable.

As a web developer, I’ve already witnessed bad working practices adopted in the name of speed, where the pressure to churn out work at a higher rate has led to overlooked quality and technical debt. In this post, I’ll share a few real-world examples of these pitfalls and outline some recommended practices we need to employ to maintain high standards in an AI-assisted development workflow.
From vibe coding to production reality
One of the most seductive aspects of using AI is the sheer velocity it offers for initial development. Using AI we can churn out a Proof of Concept (POC) in minutes, giving us a powerful feeling of momentum. It’s never been easier to create a polished-looking demo that instantly wins over stakeholders.
The danger lies in mistaking a functional POC for production-ready code. Because we didn't have to wrestle with the logic line-by-line, we tend to skip the unglamorous but vital steps. The resulting code is often devoid of robust error handling, essential security headers, or proper accessibility considerations. This oversight creates a huge amount of technical debt incurred before the feature has even been fully scoped. Taking a vibe-coded POC straight to production is exactly like trying to build a skyscraper on a foundation of "vibes", it’s very impressive that it was built so fast until the moment it collapses.
Consider a scenario I encountered where a developer created an AI-generated POC for a complex feature the team had been struggling to approach. While undeniably impressive, it was still just a POC. In a rush to hit production, decisions were made to convert this POC directly into a feature branch, planning to patch issues and add styling as they went. The immediate consequence was a structural catastrophe: the starting point of that feature branch was already a monolithic, unmanageable “wall of code” (more on this in the next section). Because the foundational logic hadn't been reviewed, the branch was fundamentally flawed from the start. We spent months chasing bugs and uncovering hidden issues, all while operating outside the rigor of our standard PR review process. By the time it reached a state of stability, we had effectively bypassed the very checks designed to ensure quality and maintainability, leaving us with a feature that was technically "working" but architecturally toxic.
Looking back, we realized there were far more efficient approaches to handling that POC. First, we could have cherry-picked functional modules from the POC into smaller, manageable chunks, allowing them to pass through our standard PR process. Alternatively, starting from scratch while using the original POC purely as a reference would have allowed us to plan the architecture properly, avoiding the structural debt that crippled us. Regardless of the path, we should have treated the feature branch with the same rigor as a merge to master, enforcing strict review checks throughout. Eventually, on other features we shifted our strategy to using feature flags: this allowed us to merge code into master early, subjecting it to our full suite of automated checks, while keeping the functionality hidden until it was truly production-ready.
This experience is the quintessential 'efficiency paradox': by prioritising short-term speed, we inadvertently locked ourselves into a long-term cycle of remediation. What seemed like a shortcut cost us months of stress, technical debt, and lost productivity. Had we invested the time upfront to adopt the strategies mentioned above we likely would have arrived at a production-ready feature far sooner. This serves as a stark reminder that 'fast' is not synonymous with 'productive'. Faster is not better; scalable, maintainable, and readable code is.
The PR problem: Moving beyond the wall of code
When AI can generate thousands of lines of robust-looking code in seconds, the temptation is to accept the entire block as a single, monumental commit. This is the "AI-Bloat" Phenomenon. We hit the accelerator, generate a huge new feature, and then immediately run into a critical point of friction: the Pull Request. The problem is that our human review processes are not equipped to handle this velocity.
When a reviewer opens a PR containing a "wall of code" that represents a week's worth of traditional coding, the brain naturally defaults to exhaustion. Reviewers become complacent, leading to the dreaded "rubber stamp". This is incredibly dangerous because AI-generated code rarely contains simple syntax errors; its mistakes are subtle logical flaws or hidden security issues that require more scrutiny, not less. We have outsourced the complexity of writing, but we cannot outsource the cognitive load of verification.
Of course, noting these challenges isn't to say AI cannot play a constructive role in the PR process. In fact, it has become a central part of my review workflow. Before I dive into the code myself, I often ask an AI to summarize the entire PR and outline the structure of the changes. I ask it to assess whether the code aligns with the scope of the original ticket, helping me identify if we are staying on track. Beyond that, the AI is remarkably adept at spotting both glaring errors and subtle logical flaws, often suggesting specific feedback I can leave for the author, which significantly accelerates the review cycle. Most importantly, it gives me a much deeper, faster understanding of the PR’s purpose and the logic behind it, a process that used to require constant back-and-forth between the ticket and the code. However, while these AI-assisted speed boosts are significant, they don't fully solve the challenge of reviewing code at the velocity at which it is created.
Fortunately, the global development community has already established a robust set of best practices to help us navigate these complexities efficiently. One that solves this issue is the practice of Atomic PRs. We must force ourselves to break down AI-assisted work into the exact same small, logical chunks we would have used if we wrote the code manually. Treat the AI as a hyper-efficient assistant that delivers small, verifiable packets of work. This respects the human capacity for review, mitigates the risk of subtle bugs slipping through, and ensures we are managing our technical debt from the moment the code is generated.
While Atomic PRs are a vital step, they are only one part of the broader toolkit that keeps us productive. It’s easy to view established development principles, like clean code standards or rigorous testing, as speed bumps when AI-driven momentum feels so good. Yet, the opposite is true: these foundational practices are not expendable. In an era where we can generate code instantly, our commitment to established best practices must be stronger than ever, as they provide the guardrails that prevent our newfound velocity from becoming a liability.
The driver in the cockpit rule
I’ve had to review PR’s that are way too big, but I’ve also had to review PR’s that are small enough yet are completely unreadable. When I’ve checked the functionality I found it seems to all work fine, but reading the code I struggle to understand why. Obviously this is a problem for two main reasons, first, what if we’re introducing bugs that we haven’t noticed, and second, are we going to struggle to build functionality on top of this code later because we can’t understand what it does. When reviewing these PRs, I treat AI-generated code with the same scrutiny as human-written code. When I find something hard to understand one step is to ask the author to walk through how the logic works. If they cannot clearly explain it, that immediately flags a deeper issue with code ownership. Even if the author can explain the code, we must ensure future maintainers won't struggle with it. While AI tools can significantly assist in the review process by summarizing changes and identifying obvious flaws, approving code that remains obscure to human developers creates long-term confusion and technical debt.
To prevent this, we should focus on simplifying complex logic, adding clear documentation, or improving variable naming. Poorly named variables are especially problematic because they lead both human reviewers and AI assistants to make false assumptions about code behavior, even when the underlying logic runs correctly. Addressing these clarity issues before merging keeps the codebase accessible and maintainable for everyone.
Ultimately, the developer should remain the driver in the cockpit, maintaining full ownership and understanding of every line of code committed. You are 100% accountable for the outcome, regardless of whether the logic was generated by an AI assistant or written by hand. Treat AI as a high-speed intern whose output demands rigorous verification; if you cannot clearly explain the implementation and its implications to a senior reviewer, the code is not ready to be merged into the production codebase.
I’ve heard plenty of developers voice their frustration at how our day-to-day is shifting away from the creative act of writing code toward the more detached role of reviewing it. I deeply sympathize with this; I feel the same friction myself. There is a genuine sense of loss when you spend less time crafting logic and more time acting as a gatekeeper.
Yet, we have to be realistic: this is simply the direction the industry is moving. We aren’t just developers anymore; we are architects, auditors, and mentors to the AI models we steer. It might not be the career trajectory we imagined a few years ago, but embracing this shift rather than fighting it is how we stay relevant and effective as engineers.
Balancing AI velocity with engineering rigor
As we navigate this new era of software development, it is easy to get swept up in the rapid velocity AI offers. While there are many ways to adopt AI responsibly, these core takeaways highlight how we can balance speed with quality:
Don’t fall for The Efficiency Paradox: Short-term speed is an illusion if it leads to long-term technical debt. Shipping a feature in record time is meaningless if we spend months untangling bugs and stabilizing fragile architecture. "Fast" is not synonymous with "productive". Scalable, maintainable, and readable code must remain our primary goal.
Double down on engineering best practices: AI is a powerful accelerator, but it is no replacement for established software engineering principles. Concepts like Single Responsibility Principle, Separation of Concerns, TDD, and clean code are not speed bumps; they are the essential guardrails that keep us on track. In an era of infinite code generation, these practices are more critical than ever.
The shift from writer to reviewer: Perhaps the most profound shift is in the review process, which encapsulates everything else. Our roles are transitioning from active writers of code to rigorous reviewers and architects. While this evolution can feel uncomfortable and is a shift many developers might resist, it is the reality of our changing landscape. We must embrace our roles as the critical gatekeepers and mentors to the models we steer.
Ultimately, the path forward isn't to reject AI out of fear or to embrace it blindly at the expense of quality. By combining the speed of AI tools with the rigor of proven engineering practices, we can build software that is both fast to deliver and built to last.
Matt FirmstonDeveloper, UK




