Vibe Coding

Vibe Coding Part 2: Shipping, Designing, and Not Breaking Everything

Taking vibe-coded projects from hacky prototype to something you can actually deploy.

Trần Quang Hùng
Trần Quang HùngChief Explainer of Things
December 14, 202521 min read
Share:
Split view of developer workspace transitioning from chaotic prototype coding to organized production-ready state

QUICK INFO

Difficulty Intermediate
Time Required 40-50 minutes to read; ongoing to master
Prerequisites Part 1 of this guide, one completed vibe-coded project
Tools Needed Same as Part 1: code editor with AI integration, basic git knowledge

What You'll Learn:

  • How to add lightweight guardrails without killing your speed
  • Designing interfaces by feel instead of elaborate mockups
  • Debugging techniques that preserve momentum
  • When and how to harden a prototype for production

Part 1 covered the fundamentals: the mindset, the basic workflow, tools, and AI collaboration. This part is about what happens after you have something working. How do you ship it without embarrassing yourself? How do you design interfaces when you're not a designer? What do you do when everything breaks and you want to quit?

Shipping Fast Without Breaking Everything

The tension at the heart of vibe coding is speed versus safety. Move fast and break things sounds good until you break something that matters. The trick isn't choosing one or the other; it's knowing which safeguards actually pay for themselves and which ones are theater.

The Minimum Viable Guardrails

I've landed on a short list of things I do even in the most aggressive vibe coding sessions. These cost almost nothing in terms of flow disruption but catch the mistakes that actually hurt.

Git commits every time something works. Not meaningful commits with good messages. Just git commit -am "works" whenever I hit a milestone. This takes three seconds and has saved me hours. When you inevitably break something while adding the next feature, you can get back to a working state instantly. I commit probably 20-30 times in a vibe coding session. The history is useless for understanding the project later, but that's fine. You can squash it before sharing if you care.

One manual test of the happy path before moving on. When you finish a feature, actually use it once. Click through the UI. Run the function with real input. This sounds obvious but it's easy to skip when you're excited about the next thing. The AI might have generated code that looks right but doesn't work. Thirty seconds of testing catches most of the stupid errors.

Console.log liberally, remove never. Or print statements, or whatever your language uses. Sprinkle them everywhere while you're building. Leave them in. They're not hurting anything and they'll help you when something breaks later. Production cleanup can deal with them. Vibe coding means optimizing for the next hour, not the next year.

That's honestly the whole list for pure prototypes. Git commits, manual testing, logging. Everything else is optional until you're ready to show someone.

What to Skip (For Now)

The things that slow you down without paying off during the prototype phase: unit tests, TypeScript strict mode, linting rules, comprehensive error handling, input validation beyond the basics, documentation, code review.

I can already hear the objections. These things exist for good reasons. Yes, they do. But those reasons are about maintenance, collaboration, and scale. A prototype you're building alone in an evening has none of those concerns. Adding them is borrowing problems from a future that might not arrive.

The key insight is that these aren't permanent decisions. You can add tests later. You can add types later. You can add all of it later, if the project survives long enough to need it. Most prototypes don't. Spending two hours on test coverage for something you'll abandon next week is waste.

The Sanity Check Hierarchy

When you do want to add safety beyond the minimum, there's an order that makes sense.

Start with the crashes. What errors would make the whole thing fall over? Add try-catch blocks around external API calls, file operations, and database queries. Not for graceful handling, just for not-crashing. Log the error and keep going if you can. This takes maybe fifteen minutes and catches the most embarrassing failures.

Then think about data corruption. If your app writes to a database or files, what happens if it writes garbage? Add basic validation on writes. Check that required fields exist. Verify types on anything that came from user input. This is where damage can compound, so it's worth more care than other areas.

Last, if you have time, add guards around whatever would be hardest to debug. The gnarly async race condition. The state management that's already confusing you. These are where future-you will suffer most, so present-you investing a little time has high returns.

When to Stop and Add Real Tests

There's a moment when vibe coding should yield to more disciplined approaches. The signals: you're about to accept money from users; you're about to invite collaborators; you've had the same bug come back three times; you can no longer hold the whole system in your head.

Any of these means the prototype phase is over. Time to slow down and add the infrastructure you've been skipping. But only then, and not before.

Designing by Feel: UI Without Figma Hell

I don't use Figma. I don't make wireframes. I don't do design systems for prototypes. This horrifies some people but it works fine for the kind of projects where vibe coding makes sense.

The Live Tweaking Workflow

My design process is: build a rough version of the UI with whatever defaults the framework gives me, then adjust it live until it looks right. React hot reloading makes this borderline enjoyable. Change a margin, see the result instantly, change it again.

The key is trusting your eyes over any abstract notion of what's "correct." If something looks off, fix it. If you're not sure what looks off, try random changes until something feels better. This sounds unprincipled because it is. But visual design is fundamentally about what looks good, and you can see whether something looks good faster than you can reason about it.

I'll often spend 20-30 minutes just nudging CSS values. Padding up by 4px, down by 2px, try 8px, back to 6px. This is tedious but it's also meditative. You're developing intuition for what works even if you can't articulate why.

Stealing Reference

Every professional designer does this. Find something that looks like what you want, study it, and adapt the patterns to your context. Not copying, just learning from what works.

For prototypes, I keep a folder of screenshots from apps I like. When I'm stuck on how to lay something out, I'll flip through and see if anyone has solved a similar problem. Usually someone has. The patterns in UI design are pretty finite.

Actually, let me clarify that. I'm not talking about taking someone's exact design. I'm talking about noticing that all these apps put the primary action in the top right, or that this spacing pattern creates nice rhythm, or that cards with subtle shadows feel more clickable. Principles, not pixels.

The Tailwind Advantage

If you're doing web UI and you're not using Tailwind or something similar, you're making this harder than it needs to be. The utility class approach is perfect for vibe coding because you never leave your component file. No switching to CSS files, no naming things, no cascade confusion. Change p-4 to p-6 and see what happens.

I resisted Tailwind for years because the class soup looked ugly in the HTML. I was wrong. The ugliness is worth the speed. You can always extract components later if the repetition bothers you.

When You Need a Real Designer

Some things I can't do by feel: complex data visualization, anything with heavy illustration, apps where brand identity matters a lot. If your prototype succeeds and becomes a real product in one of these categories, hire a designer. The handoff from vibe-coded UI to professional design is usually easier than people expect because you've already worked out the basic flows and interactions.

For most prototypes, though, "good enough" design is genuinely good enough. Users care less about visual polish than developers think. They care about whether the thing works and solves their problem.

Debugging in Vibe Mode

Bugs kill momentum. You're in flow, everything's working, then suddenly nothing works and you can't figure out why. The temptation is to rage-quit or fall into a debugging spiral that consumes your whole session.

The 10-Minute Rule

When something breaks, set a timer for 10 minutes. If you haven't fixed it by then, stop and try a different approach. This prevents the death spiral where you keep trying the same thing with minor variations for an hour.

Different approaches after hitting the 10-minute wall: ask your AI assistant for help (paste in the error and relevant code), revert to your last working commit and try a different path, isolate the problem by commenting out code until you find the culprit, take a break and come back in 20 minutes.

The last one is underrated. Often your brain will solve the problem in the background while you're doing something else.

Strategic Console.log Placement

When something's not working and you don't know why, the answer is almost always to add more logging until you can see what's actually happening. Start at the entry point and log your way forward until reality diverges from expectation.

I'll sometimes add 15-20 console.logs in one go, run the thing once, see where the unexpected value appears, and then focus investigation there. This is faster than reasoning about the code because your mental model is probably wrong. The logs tell you what's actually true.

Using AI for Debugging

AI assistants are genuinely good at debugging, often better than at writing new code. The trick is giving them enough context. Don't just paste the error message; paste the relevant function, what you expected, and what happened instead.

A prompt that works: "Here's my function [paste]. When I call it with [input], I expect [outcome] but I'm getting [actual result]. The error message is [error]. What's going wrong?"

The AI can often spot the issue immediately because it's not trapped in your mental model of what the code should do. Fresh eyes, even artificial ones.

When to Give Up on a Feature

Sometimes the right move is to abandon the thing that's breaking and do something else. This feels like failure but it's often strategic. If a feature is fighting you, that might be information about the underlying architecture. Maybe you need to restructure something before this feature can work cleanly.

I'll often move on, build another feature, and find that the first problem is easier to solve after the codebase has evolved. Or I'll realize the feature wasn't that important and I don't need it at all.

Vibe coding is about momentum. Protecting your momentum is more important than any individual feature.

The Frustration Spiral

If you notice yourself getting genuinely angry at the code, stop. Walk away. The debugging session is over for now.

This isn't productivity advice; it's just how brains work. Frustrated problem-solving is worse problem-solving. You'll miss obvious things, make sloppy changes, and create new bugs. The best thing you can do for the project is give yourself 20 minutes to reset.

Turning Vibe-Coded Projects Into Real Products

Let's say your prototype worked. People want it. You might even be able to charge for it. Now what?

The Rewrite Question

First decision: do you clean up the existing code or start fresh? Both are valid. The answer depends on how messy things got and how well you understand what you're building now.

Arguments for cleaning up: you've already tested this code in the real world, you know where the bugs are, rewriting risks introducing new bugs, and you might spend weeks recreating what you already have.

Arguments for rewriting: the architecture is fundamentally wrong for what this became, the code is so tangled that changes break unrelated things, you've learned so much that the new version would be dramatically better, and the technical debt is actively slowing you down.

My rule of thumb: if you can identify the three or four worst parts of the codebase and fix them specifically, do that. If the problems are everywhere and interconnected, rewrite.

The Cleanup Checklist

When you decide to clean up rather than rewrite, here's a rough order of operations.

First, get the thing into version control properly if it isn't already. Create a clean initial commit with your current working state. Everything else branches from here.

Second, add the error handling you've been skipping. Every external API call needs a try-catch. Every user input needs basic validation. Every file operation needs to handle failures. This probably takes a day for a medium-sized prototype.

Third, extract the obvious duplications. If you've got the same 20 lines copy-pasted in four places, make it a function. Don't go crazy here; just fix the stuff that's already causing problems.

Fourth, add types if you're in a language that supports them. TypeScript for JavaScript, type hints for Python. Start with the core data structures and function signatures. This will shake out a surprising number of latent bugs.

Fifth, write tests for the parts that scare you. Not comprehensive coverage, just the hairy business logic and the integration points that have broken before. Maybe 20-30 tests for a typical prototype-to-product transition.

Sixth, write a README that explains how to run the thing and what it does. Future you will thank present you.

Production Concerns

Beyond code quality, there are infrastructure questions that prototypes don't have to answer but products do.

Deployment: how does this run? A prototype might work on your laptop, but a product needs to run somewhere. Vercel, Railway, or a simple VPS are all fine starting points. Don't over-engineer this; pick something and move on.

Monitoring: how will you know when it breaks? At minimum, you need error logging that alerts you. Sentry is fine. A Slack webhook that fires on uncaught exceptions is fine. Something.

Backups: if you have a database, you need backups. This is non-negotiable. Automated daily backups to somewhere that isn't the same server.

Security: if users have accounts, their passwords need to be hashed properly. Use bcrypt or argon2, not something you invented. If you're accepting payments, use Stripe and let them handle the scary parts.

That's the minimum. You can add more sophistication as you need it. The goal is to be able to sleep at night without worrying about catastrophic failures.

The Investment Pitch Version

If you're showing this to investors rather than users, the bar is different. They care less about production readiness and more about whether the core idea works. A demo that crashes occasionally but demonstrates clear value beats a polished product with unclear value.

What investors want to see: the problem exists and you understand it, your solution addresses the problem in a novel or better way, people actually want this (even if your evidence is just 10 beta users), and you can articulate a path to making money.

None of that requires production-grade code. It requires a compelling demo and a clear story. Vibe-coded prototypes are often perfect for this because they exist, they work, and they can evolve based on feedback.

Common Vibe Coding Mistakes

After watching myself and others vibe code for a while, there are patterns in how things go wrong. Here are the ones I see most often.

Over-Hacking Without Any Structure

Vibe coding isn't an excuse to never think about organization. If every file is 800 lines and there's no discernible structure, you haven't achieved freedom from architecture; you've just created a mess that's hard to navigate.

The fix: pause occasionally and ask whether future-you could find things. Create folders that make sense. Split giant files when they're hard to scroll through. Give functions names that describe what they do. This isn't traditional architecture; it's basic hygiene.

AI Copy-Paste Without Reading

The thing that makes AI assistants dangerous is that their code often works. So you paste it, run it, see that it works, and move on. Then later something goes wrong and you have no idea what half your codebase does.

The fix: take 30 seconds to read each chunk of AI-generated code before moving on. You don't need to understand every line, but you should understand the overall approach. If you can't explain roughly what a function does, you've accumulated debt that will come due.

Skipping the Manual Test

I mentioned this earlier but it's worth repeating because it's the most common source of wasted time. You implement a feature, the code looks right, you move on to the next thing. Then ten features later you discover the first one never actually worked.

The fix: actually use each feature once after implementing it. Click the button. Submit the form. Call the function with real data. Thirty seconds of manual testing catches 90% of the stupid mistakes.

Solving Problems You Don't Have

Sometimes vibe coding gets derailed not by bugs but by anticipation. You imagine a future scaling problem, or a hypothetical edge case, or a potential security issue. You spend two hours solving it. Then you never encounter the problem in practice.

The fix: write down the hypothetical problem and move on. If it becomes real, you'll address it then. Most of them never do. Your job in vibe coding mode is to solve the problems in front of you, not the problems you can imagine.

The Infinite Polish Loop

The opposite of shipping too early is never shipping at all because it's never good enough. You keep adding features, fixing minor issues, polishing edges. The project never reaches users because you're never satisfied.

The fix: set a deadline and ship whatever you have. External commitment helps. Tell someone you'll show them on Friday. Post in a community that you'll share your project next week. The deadline creates pressure that breaks the polish loop.

Losing Track of What Works

When you're iterating fast, it's easy to lose track of which version was actually working. You make a bunch of changes, something breaks, and you can't remember the last good state.

The fix: commit more often. I said this in the guardrails section but it applies especially here. git commit -am "works" every time something works. Your git history will be ugly but you'll always be able to get back to a functional state.

Abandoning Too Early

The final mistake isn't a mistake of commission but omission. Vibe coding makes it easy to start projects, which means you might start too many and finish too few. A half-working prototype that you abandon teaches you less than a shipped product that you see through.

The fix: notice the pattern and resist it. Force yourself to ship the current thing before starting the next thing. The discipline of finishing is separate from the discipline of building and both are worth developing.

Troubleshooting

Problem: You shipped something and users found bugs you should have caught

This is going to happen. The question is how you respond. Fix the bugs immediately, apologize if appropriate, and add guardrails to prevent that specific class of bug in the future. One embarrassment usually means one new item on your pre-ship checklist.

Problem: Your codebase has become incomprehensible even to you

Time for a consolidation session. Block off 2-3 hours and just organize. No new features. Split files, rename things, add comments explaining what the tricky parts do. This is maintenance and it's part of the process, even in vibe coding.

Problem: The AI keeps suggesting bad solutions

Try a different model, start a fresh conversation, or rephrase the problem. Sometimes the AI has latched onto a wrong approach and needs a clean slate. Also consider that you might be asking the wrong question; if the AI keeps misunderstanding, the problem description might be unclear.

Problem: You're not sure if the project is worth making production-ready

Get it in front of users first. Even five people using your hacky prototype will teach you more than a week of speculation. Their feedback determines whether this is worth hardening. If nobody cares, move on without guilt.

What's Next

You've now got the full picture: from initial idea through prototype, from debugging to production. The remaining skill is just repetition. Build more things. Ship more things. Each project teaches you something the previous ones didn't.

If you want to go deeper on specific tools, Cursor's documentation covers their AI features in detail, and the Tailwind docs are worth reading if you're doing web UI. For the production side, the Twelve-Factor App methodology is a good framework even if you don't follow it exactly.

Otherwise: go build something. Then ship it.


PRO TIPS

When debugging, log the actual values, not just "got here" messages. console.log("user:", user) beats console.log("checkpoint 1") because you can see what the data actually looks like.

For UI work, browser DevTools let you edit CSS live. Tweak values in the Styles panel before committing them to code. This is faster than save-refresh cycles.

If you're stuck on what to build next in a project, ask yourself what would make you actually use this thing daily. Build that feature. Your own usage is the best test.

Keep a "parking lot" file for ideas that don't fit the current scope. When you think "I should also add X," write it down and keep going. Most of these ideas won't survive scrutiny later, and that's fine.


FAQ

Q: How do I know when a prototype is "done enough" to show someone?

A: When it demonstrates the core value proposition without crashing on the happy path. Users can tolerate rough edges and missing features. They can't tolerate crashes and confusion about what the thing does.

Q: Should I add tests to a prototype before showing it to investors?

A: Probably not. Investors care about the idea and your ability to execute, not your test coverage. A working demo that might have bugs is better than a bulletproof architecture document. Ship faster.

Q: How do I price a vibe-coded product?

A: Pick a number that feels slightly embarrassing to ask for, then double it. You're probably undervaluing your work. Start higher than you think and lower the price if nobody buys. Raising prices later is harder than lowering them.

Q: When should I stop vibe coding and switch to "real" engineering?

A: When you're no longer the only person who needs to understand the code, or when bugs in production are costing you users/money/reputation. Both indicate that the prototype phase is over.

Q: Is vibe coding just for web apps?

A: It works best for projects where you can see immediate results: web apps, CLI tools, scripts, mobile apps with hot reload. It works less well for things like embedded systems or infrastructure code where feedback loops are slow. The principle is adaptable but the specific techniques assume fast iteration.


RESOURCES


PROMPT TEMPLATES

Debugging with AI

Here's my code:

[paste the relevant function or component]

When I [specific action], I expect [expected behavior].

Instead, I'm getting [actual behavior]. The error message is:

[paste error message if any]

What's causing this and how do I fix it?

Customize by: Being as specific as possible about expected vs actual behavior. Vague descriptions get vague fixes.

Cleanup Planning

I have a vibe-coded prototype that works but is messy. Here's the current structure:

[paste file tree or describe architecture]

The main problems I've noticed are:
- [problem 1]
- [problem 2]

What's a reasonable order to clean this up without breaking everything? I want to get it production-ready without rewriting from scratch.

Customize by: Adding specific pain points you've experienced. The more context about what's actually broken, the better the cleanup plan.

Production Readiness Check

I'm about to deploy this prototype for real users. Here's what it does:

[brief description]

Here's the current error handling and security situation:

[describe what you have]

What am I most likely to regret not adding before launch?

Customize by: Being honest about what you've skipped. The AI can only help with risks you've disclosed.

Tags:vibe codingshipping fastprototype to productiondebuggingUI designrefactoringAI codingsolo developerMVP development
Trần Quang Hùng

Trần Quang Hùng

Chief Explainer of Things

Hùng is the guy his friends text when their Wi-Fi breaks, their code won't compile, or their furniture instructions make no sense. Now he's channeling that energy into guides that help thousands of readers solve problems without the panic.

Related Articles

Stay Ahead of the AI Curve

Get the latest AI news, reviews, and deals delivered straight to your inbox. Join 100,000+ AI enthusiasts.

By subscribing, you agree to our Privacy Policy. Unsubscribe anytime.

Vibe Coding Part 2: Shipping, Designing, and Not Breaking Everything | aiHola