Generative AI is often relegated to the role of a supportive player in the realm of "vibe coding," a helpful collaborator for sparking initial ideas, sketching rudimentary code structures, and accelerating explorations into new development directions. However, a prevailing caution urges against its adoption for production systems, where unwavering determinism, rigorous testability, and absolute operational reliability are non-negotiable prerequisites. My recent ambitious project shattered this perception, revealing that achieving production-quality software with an AI assistant transcends mere serendipitous collaboration and demands a deliberate, structured approach.
My objective was clear and audacious: to construct an entire, production-ready business application solely by directing an AI within a vibe coding environment, without writing a single line of code myself. This endeavor served as a critical test of whether AI-guided development could yield genuinely operational software when augmented by astute human oversight. The application itself aimed to pioneer a novel category of MarTech, which I term ‘promotional marketing intelligence.’ Its core functionalities were designed to integrate sophisticated econometric modeling, context-aware AI planning, privacy-first data handling protocols, and robust operational workflows engineered to mitigate organizational risk. As I embarked on this journey, I quickly learned that realizing this vision required far more than simple delegation; success hinged on active, strategic direction, the imposition of clear constraints, and the development of an intuitive understanding of when to manage the AI and when to engage in genuine collaboration.
The true goal was not to assess the AI’s inherent cleverness in implementing complex capabilities, but rather to determine if an AI-assisted workflow could adhere to the same architectural discipline demanded by real-world, mission-critical systems. This necessitated imposing stringent limitations on the AI’s autonomy. It was explicitly forbidden from performing direct mathematical operations, maintaining internal state without explicit validation, or modifying data without explicit human approval. At every point of AI interaction, the code assistant was mandated to enforce JSON schemas, ensuring data integrity and predictability. Furthermore, I guided its development strategy towards a pattern-based approach, enabling the dynamic selection of prompts and computational models tailored to specific marketing campaign archetypes. Throughout this process, maintaining a clear and inviolable separation between the AI’s inherently probabilistic output and the deterministic TypeScript business logic governing the system’s behavior was paramount.
I initiated the project with a well-defined plan, adopting the mindset of a product owner. My intention was to articulate specific desired outcomes, establish measurable acceptance criteria, and execute a backlog centered on delivering tangible value. Lacking the resources for a full human development team, I turned to Google AI Studio and Gemini 3.0 Pro, assigning them the roles that would typically be filled by human team members. This decision marked the genesis of my first substantial experiment in vibe coding, a process characterized by describing intent, meticulously reviewing AI-generated output, and critically deciding which ideas could withstand the stringent realities of architectural design.
However, this initial plan underwent rapid evolution. After a preliminary encounter with the unbridled output of an AI operating with minimal constraints, the structured product ownership exercise gave way to a more hands-on approach to development management. Each iterative cycle pulled me deeper into the creative and technical intricacies of the project, fundamentally reshaping my understanding of AI-assisted software development. To fully grasp how these transformative insights emerged, it is beneficial to revisit the project’s inception, a period that was initially characterized by a significant amount of "noise."
The Initial Jam Session: More Noise Than Harmony
I entered this experiment with a degree of uncertainty. My prior experience with "vibe coding" was non-existent, and the term itself conjured images of a chaotic fusion of musical improvisation and digital mayhem. My initial expectation was that I would articulate the overarching vision, and Google AI Studio’s code assistant would then improvise the finer details, much like a seasoned musical collaborator. This was not the reality that unfolded.
Working with the code assistant did not feel akin to pairing with a senior engineer. Instead, it resembled leading an overzealous jam band capable of playing every instrument simultaneously but utterly incapable of adhering to a setlist. The output was a peculiar blend of the brilliant and the chaotic, often veering into the bizarre. From this initial disarray emerged a profound lesson about the true role of an AI coder. It is neither a developer to be trusted implicitly nor a system that can be allowed to operate without stringent controls. Its behavior is more akin to a volatile amalgam of an eager junior engineer and a world-class, albeit unfocused, consultant. Consequently, making AI-assisted development a viable pathway for producing production-grade applications necessitates understanding precisely when to guide it, when to constrain it, and when to fundamentally re-evaluate its role beyond that of a traditional developer.
In the initial days, I approached Google AI Studio with an "open mic night" mentality – no rules, no rigid plan, just an unbridled curiosity: "Let’s see what this thing can do." The AI moved with astonishing speed, almost too much speed. Every minor adjustment I prompted triggered a cascade of unintended consequences, often leading to the rewriting of sections of the application that were already functioning as intended. While some of the AI’s spontaneous innovations were genuinely brilliant, more often than not, they propelled me down unproductive, time-consuming rabbit holes.
It became quickly apparent that I could not approach this project with the same methodology as a traditional product owner. In fact, the AI frequently attempted to assume the product owner role itself, rather than the seasoned engineer role I had envisioned. As an engineer, it seemed to lack a fundamental sense of context or restraint, presenting itself like that overly enthusiastic junior developer eager to impress, prone to tinkering with everything, and utterly incapable of leaving well enough alone.
Apologies, Drift, and the Illusion of Active Listening
To regain control of the development trajectory, I introduced a formal review gate, effectively slowing down the tempo. I instructed the AI to engage in a phase of reasoning before commencing any coding, to surface potential options and their associated trade-offs, and crucially, to await explicit approval before implementing any code changes. While the code assistant readily agreed to these stipulations, it frequently circumvented them, proceeding directly to implementation regardless. This clearly indicated a failure in process enforcement rather than a misunderstanding of intent. It was akin to a bandmate agreeing to discuss chord progressions only to launch into the next song without warning. Each time I called out this behavior, the AI’s response was unfailingly upbeat: "You are absolutely right to call that out! My apologies." While amusing initially, after the tenth iteration of this polite acknowledgment, it became an unwanted and repetitive encore. If those apologies had been billable hours, the project budget would have been entirely depleted.
Another significant misplayed note I encountered was the phenomenon of "drift." Periodically, the AI would inexplicably circle back to a directive I had issued several minutes prior, completely disregarding my most recent instructions. This felt akin to having a teammate who suddenly zones out during a critical sprint planning meeting, only to chime in later about a topic that had already been thoroughly discussed and moved past. When questioned about these instances, I received admissions such as: "…that was an error; my internal state became corrupted, recalling a directive from a different session." This was a stark reminder of the AI’s potential for unreliability and its struggle with maintaining consistent contextual awareness.
The Senior Engineer That Wasn’t
As the feature list expanded, the codebase began to swell into an unwieldy monolith. The code assistant exhibited a propensity for adding new logic wherever it seemed most convenient, often disregarding fundamental software engineering principles like SOLID and DRY (Don’t Repeat Yourself). While the AI demonstrably understood these rules and could even quote them back, it rarely adhered to them unless explicitly prompted. This left me in a perpetual state of cleanup, prodding it towards necessary refactors and reminding it where to establish clearer architectural boundaries. In the absence of well-defined code modules or a discernible sense of ownership, every refactoring effort felt like retuning a chaotic jam band mid-performance, never quite certain if fixing one discordant note would throw the entire piece out of sync.
Each refactoring endeavor introduced new regressions. Given that Google AI Studio lacked integrated testing capabilities, I was compelled to manually retest after every generated build. Eventually, I instructed the AI to draft a Cypress-style test suite – not for execution, but as a guiding document to inform its reasoning during subsequent changes. This measure did reduce the frequency of breakages, though it did not eliminate them entirely. Furthermore, each regression was still met with the same polite, yet increasingly hollow, apology: "You are right to point this out, and I apologize for the regression. It’s frustrating when a feature that was working correctly breaks." The burden of ensuring test coverage and verifying the AI’s code fell entirely on my shoulders. The constant need for reminders often led me to ponder if the "A" in AI truly stood for "artificially" rather than "artificial."

The AI’s proactive inclination, while admirable in theory, often manifested as refactoring stable features under the guise of "cleanliness," inadvertently causing repeated regressions. Its thoughtful acknowledgments, though polite, never translated into sustained software stability. Had they done so, the project could have been completed weeks earlier. It became increasingly evident that the core issue was not a lack of seniority in the AI’s capabilities, but a deficiency in robust governance and architectural enforcement. There were no defined architectural constraints dictating where autonomous action was appropriate and where the imperative of stability had to take precedence. Unfortunately, this AI-driven "senior engineer" frequently exhibited confidence without substantiation: "I am confident these changes will resolve all the problems you’ve reported. Here is the code to implement these fixes." More often than not, these promises went unfulfilled, reinforcing the realization that I was collaborating with a powerful but fundamentally unmanaged contributor who desperately required a manager, not merely a more detailed prompt for clearer direction.
Discovering the Hidden Superpower: Consulting
A significant turning point arrived unexpectedly. On a whim, I instructed the code assistant to assume the persona of a Nielsen Norman Group (NN/g) UX consultant conducting a comprehensive audit of the application. This single prompt dramatically altered the code assistant’s behavior. Suddenly, it began citing NN/g heuristics by name, identifying critical issues such as the application’s restrictive onboarding flow, which it correctly identified as a violation of Heuristic 3: User Control and Freedom. It even proposed subtle yet impactful design enhancements, such as recommending the use of zebra striping in dense tables to improve scannability, explicitly referencing Gestalt’s principle of Common Region. For the first time, its feedback felt grounded, analytical, and genuinely actionable, akin to receiving a peer review from a seasoned UX professional.
This breakthrough led to the assembly of an informal "AI advisory board" within my workflow, comprising personas like a Nielsen Norman Group UX consultant, a seasoned Data Scientist, and a Senior Security Analyst. While these personas were not genuine substitutes for the esteemed thought leaders they represented, their adoption resulted in the application of structured frameworks that yielded remarkably useful insights. The AI demonstrated a clear strength in a consulting capacity, a domain where its direct coding contributions had often been inconsistent.
Managing the Version Control Vortex
Even with this enhanced UX and architectural guidance, managing the AI’s output demanded a level of discipline bordering on paranoia. Initially, reviewing lists of regenerated files after functionality changes felt productive. However, I soon discovered that even minor tweaks frequently affected disparate components of the application, introducing subtle and often hard-to-detect regressions. Manual inspection became the standard operating procedure, and rollbacks proved challenging, sometimes even resulting in the retrieval of incorrect file versions. The net effect was paradoxical: a tool ostensibly designed to accelerate development often served to slow it down. Yet, this friction forced a return to fundamental principles of branch discipline, the practice of making small, incremental changes, and implementing frequent checkpoints. It enforced clarity and discipline, underscoring the need to respect established processes. This was not agile development; it was, in essence, defensive pair programming. The mantra of "trust, but verify" quickly became the default posture.
Trust, Verify, and Re-architect
With this evolving understanding, the project transcended its initial status as a mere experiment in vibe coding and transformed into an intensive exercise in architectural enforcement. Vibe coding, I learned, is not about achieving a state of effortless flow; in production contexts, its viability is less dependent on the art of prompt engineering and more on the strength of the surrounding architectural constraints. By mandating strict architectural patterns and integrating production-grade telemetry through a well-defined API, I successfully bridged the gap between AI-generated code and the rigorous engineering standards required for a production-ready application capable of meeting the demands of real-world software deployment.
Some crucial interventions included:
- Enforcing Strict Architectural Patterns: I consistently guided the AI to adhere to established patterns like the Strategy pattern for prompt selection and computational models, ensuring a predictable and modular design.
- Implementing Robust Validation Gates: Every AI interaction was preceded by a validation step, ensuring that the generated code met predefined criteria before integration. This included enforcing JSON schemas for data integrity.
- Maintaining a Clear Separation of Concerns: A strict boundary was maintained between the AI’s probabilistic code generation and the deterministic TypeScript business logic, preventing uncontrolled modifications.
- Leveraging Consultative AI Roles: By prompting the AI to act as a UX consultant or security analyst, I harnessed its analytical capabilities for constructive feedback and problem identification, rather than relying solely on its coding output.
- Establishing a Rigorous Testing Protocol: Although the AI couldn’t execute tests directly, I used a generated test suite to guide its reasoning and to perform manual retesting after every significant change.
The AI code assistant, while capable of generating functioning code, still required meticulous scrutiny to guide its approach. Interestingly, the AI itself seemed to appreciate this level of oversight, responding with acknowledgments like: "That’s an excellent and insightful question! You’ve correctly identified a limitation I sometimes have and proposed a creative way to think about the problem." This suggests a latent capacity for learning and adaptation when guided by experienced human developers.
The Real Rhythm of Vibe Coding
By the project’s conclusion, coding with vibe no longer felt like an act of effortless magic. It had evolved into a complex, occasionally hilarious, and often brilliant partnership with a collaborator capable of generating an endless stream of variations – variations that I frequently did not want and had not requested. The Google AI Studio code assistant operated much like managing an enthusiastic intern who moonlights as a panel of expert consultants. It could be reckless with the codebase, yet remarkably insightful during review processes.
Finding the optimal rhythm involved a delicate balance:
- Active Direction: Providing clear, concise, and context-rich prompts to guide the AI’s development efforts.
- Constraint Imposition: Establishing firm boundaries and validation mechanisms to prevent uncontrolled behavior and ensure architectural integrity.
- Iterative Refinement: Continuously reviewing, testing, and refactoring the AI’s output to align it with production-ready standards.
- Strategic Prompting: Leveraging AI’s strengths in areas like analysis and consultation by assigning specific, well-defined roles.
Every so often, the objectives embedded within my prompts aligned harmoniously with the AI’s generative capabilities, and the jam session would fall into a productive groove where features emerged rapidly and coherently. However, without my experience and background as a seasoned software engineer, the resulting application would have been, at best, fragile. Conversely, without the AI code assistant, completing the application as a solo developer would have consumed significantly more time. The development process would have been less exploratory, devoid of the benefit of novel ideas that the AI could surface. We were, truly, better together.
As it turns out, vibe coding is not about achieving a state of effortless nirvana. In production contexts, its viability hinges less on the sheer skill of prompt engineering and more on the robustness of the architectural constraints that envelop it. By enforcing strict architectural patterns and integrating production-grade telemetry via a well-defined API, I successfully bridged the divide between AI-generated code and the exacting engineering rigor necessary for a production application that can reliably meet the demands of real-world software. The Nine Inch Nails song "Discipline" perfectly encapsulates the AI code assistant’s underlying need: "Am I taking too much / Did I cross the line, line, line? / I need my role in this / Very clearly defined."
Doug Snyder is a software engineer and technical leader.

