Vibe Code to codebykarun.com: What I Learned (Part 6)

6 min read
lessons learnedaiproductivityvibe coding

Part 1 of 5 in Evolution & Growth • Previously: Design System & Theming (Part 1: Foundation)

After completing the foundation of Code by Karun in the first series, I deployed to production and lived with it. This second series covers the evolution—the lessons, optimizations, and growth of a live project. Let me start with what I learned.

Lesson 1: AI Amplifies Your Skills, Not Replaces Them

What I Expected

I thought AI would write code while I sat back and watched.

What Actually Happened

The best results came when I stayed deeply engaged:

  • Asking "why?" after implementations
  • Suggesting alternatives
  • Pushing back on solutions that didn't feel right
  • Adding context from my experience

The Moment It Clicked

AI suggested this for article loading:

// Initial suggestion
export async function getArticles() {
  const files = fs.readdirSync(contentDir);
  return files.map(file => {
    const content = fs.readFileSync(file);
    return parseArticle(content);
  });
}

Me: "This reads files synchronously. Won't that block the event loop?"

The Response: "You're absolutely right. Let's use async file operations..."

// Refined version
export async function getArticles() {
  const files = await fs.readdir(contentDir);
  return Promise.all(
    files.map(async file => {
      const content = await fs.readFile(file, 'utf8');
      return parseArticle(content);
    })
  );
}

The lesson: Your experience and intuition matter. Vibe coding works best when you're an active participant, not a passive consumer.

Lesson 2: Specificity Gets Better Results

Bad Prompt

Make the site look better.

Result: Generic changes that didn't match my vision.

Good Prompt

The article cards feel cramped. Increase the vertical spacing between them 
to at least 2rem. Add subtle hover effects—maybe a slight lift and shadow. 
The excerpt text should be slightly muted (use text-muted-foreground) to 
create visual hierarchy. I want a clean, airy feel like Apple's design 
language.

Result: Exactly what I wanted.

The Pattern

Be specific about:

  • What you want
  • Why you want it
  • How it should feel
  • Examples to reference
  • Constraints to respect

Think of it like explaining to a talented junior developer—clear, specific, with context and constraints.

Lesson 3: Iterate in Small Steps

The Mistake I Made

My Bad Prompt:

Build the complete article system with MDX processing, syntax highlighting, 
SEO metadata, reading time, tags, and category filtering. Make it work with 
Server Components and include proper TypeScript types.

Result: Overwhelming. Hard to review. Bugs in multiple places.

What Works Better

Breaking it down:

Step 1:

First, let's get basic MDX file loading working. Read files from the content 
directory and return their raw content.

Step 2:

Now add frontmatter parsing using gray-matter. Extract title, excerpt, date, 
and tags from the frontmatter.

Step 3:

Add syntax highlighting to code blocks using sugar-high. Apply it only to 
code elements within the MDX content.

Each step was reviewable, testable, and understandable.

The lesson: Vibe coding is like pair programming. You wouldn't ask your pair to "build the entire feature while I get coffee." You'd work together, step by step.

Lesson 4: Understanding the Code Matters

The Temptation

When AI generates working code, it's tempting to just accept it and move on.

Why That's Dangerous

I made this mistake with the MDX rendering pipeline. It worked, but I didn't fully understand the component customization system.

Later, when I wanted to add custom components for callouts, I was lost.

The Solution

Always ask: "Can you explain how this works?"

Example:

const components = {
  code: ({ children, ...props }: any) => {
    const codeHTML = highlight(children);
    return <code dangerouslySetInnerHTML={{ __html: codeHTML }} {...props} />;
  },
};

My Follow-up Prompt:

Why are we using dangerouslySetInnerHTML here? Isn't that usually a security 
risk? And why is the code prop typed as 'any' instead of having proper types?

Now I understood it. I could modify it. I could debug it. I owned it.

Questions to Ask

  • "What happens if [edge case]?"
  • "Why did you choose this approach over [alternative]?"
  • "What are the performance implications?"
  • "Could you add comments explaining the key parts?"

Lesson 5: Test As You Go

The Problem

I built several features in quick succession without testing. When I finally ran the dev server, multiple things were broken, and I couldn't isolate the issues.

The Better Approach

After each feature:

  1. Run the dev server
  2. Test the functionality
  3. Check in the browser
  4. Verify in different scenarios

Vibe coding is fast, but that speed can create a false sense of completion. Just because code is generated doesn't mean it works in your specific setup.

Lesson 6: The AI Doesn't Know Your Preferences

The Pattern I Noticed

AI would sometimes use patterns I don't prefer:

  • Default exports vs named exports
  • Certain naming conventions
  • File organization approaches

The Solution

Be explicit about preferences:

For this project, I prefer:
- Named exports over default exports
- Arrow functions for components
- Descriptive variable names
- Utility files in a lib/ directory

Please follow these conventions consistently.

After that, consistency improved dramatically.

What Surprised Me Most

Three things stood out:

1. Speed Without Sacrificing Quality

What would normally take days took hours. And the code was cleaner than what I'd write alone because I could focus on architecture while AI handled boilerplate.

2. Learning Acceleration

Every interaction was a learning opportunity. "Why did you structure it that way?" led to insights about React Server Components, TypeScript patterns, and Next.js optimizations.

I didn't just build faster—I learned faster.

3. Design Confidence

As a non-designer, I expected design to be painful. Instead, through the right prompts and iteration, I created something I'm proud of.

The secret wasn't AI doing the design—it was AI helping me articulate and execute my vision.

The Reality Check

Vibe coding isn't magic:

  • You still need to understand software engineering
  • You still make the architectural decisions
  • You still need to test and debug
  • You still own the code

But it multiplies your effectiveness by handling:

  • Boilerplate
  • Documentation lookups
  • Pattern implementations
  • Best practices application

Coming Up Next

In the final part, I'll share the best practices that emerged, common pitfalls to avoid, and give you ready-to-use prompt templates for your own vibe coding journey.


Next in the Series

👉 Continue to Part 7: Best Practices & Templates

Get practical advice, prompt templates, and a framework for successful vibe coding.


More in this series: Part 1: What is Vibe Coding?Part 2: Tech StackPart 3: First HourPart 4: MDX PipelinePart 5: Design SystemPart 7: Best Practices