Introduction

Vibe coding is a term introduced by Andrej Karpathy.

vibe coding

While some perceive vibe coding as using AI for merely writing code, I see it as:

  • a method to learn new concepts
  • a way to write higher-quality code
  • leveraging AI to handle boilerplate code, allowing me to focus on more critical aspects, such as:
    • product vision
    • tech stack decisions
    • architectural design
    • design patterns
    • test cases

At work, I use GitHub Copilot for projects written in TypeScript and C#. Outside of work, I use Cursor to collaborate on open-source projects and build my own products. The languages I work with range from TypeScript to Python and Swift. So far, I have been able to create more than I ever imagined.

In this blog, I want to share my experiences with vibe coding.

Ninja Level

Using AI for vibe coding is not just about tab tab tab.

Provide Context

Large Language Models (LLMs) rely heavily on in-context learning, so providing high-quality prompts is crucial:

  • Use shortcuts like @ (in Cursor) to reference files or functions.
  • Add lines of code to the chat using cmd + L (in Cursor).

By offering more context, the model can better understand your intent and analyze the codebase effectively.

add context

Here are some useful cheat sheets:

Keep Context Relevant

Focus on asking questions about the same topic to avoid context switching. This helps the model reason more effectively.

Applications like Cursor and GitHub Copilot likely use a history mechanism under the hood. Keeping your questions and tasks relevant minimizes the summary size of that history, allowing you to use more tokens for the task at hand and achieve better results.

When you’re done with one topic, simply start a new chat (use the + button in the chat window in both Cursor and GitHub Copilot).

Here’s an example of chat history I’ve maintained:

chat history

Ask vs. Agent Mode

I primarily use the agent mode because it automates many tasks for me. However, there’s a caveat: I only use agent mode when I’m working on boilerplate code.

Every developer is familiar with certain boilerplate patterns, so it’s fine to let the agent mode handle those for you.

When I encounter a topic I don’t understand, I highly recommend switching to ask mode. This allows AI to act as an educator, helping you learn new concepts.

For example, when working on a Swift project, I often ask the LLM to explain unfamiliar topics in a language I’m more comfortable with.

Here’s an example:

ask mode

Notes:

  • Use backticks to escape special keywords like @.
  • The agent mode for Xcode can be tricky. Files may be created locally but won’t appear in Xcode. You might need to adjust the project settings manually.

Rockstar Level

Now, let’s talk about the medium level of vibe coding.

For medium-level usage, having a solid technical background is essential. It’s not just about tricks but about how much you know regarding:

  1. Specific language features
  2. Effective design patterns
  3. Good architecture

Mastering Language Features

When I ask Copilot to generate unit tests, I often request it to use Jest tables for implementation. However, it frequently defaults to the describe.each() syntax:

jest each

What I actually prefer is the describe.each`table` syntax:

jest table

Keep in mind that LLMs are trained on outdated datasets with varying code quality. Don’t expect all open-source code to be of exceptional quality.

For example, when Java introduced lambda functions in 2014, the training corpus likely lacked sufficient examples. While LLMs can mimic patterns from other languages, it’s still crucial for developers to deeply understand and master their chosen language.

Applying Design Patterns

While working on a metrics feature, I used an internal SDK built on top of the Azure AppInsights SDK. Ideally, we should have a class to represent an entry:

class UserAction {
  constructor(
    public userId: string,
    public action: string,
    public timestamp: Date,
    public details: Record<string, any>
  ) {}
}

We can then send custom events using:

function sendCustomEvent(userAction: UserAction) {
  appInsights.trackEvent({
    name: "UserActionEvent",
    properties: {
      userId: userAction.userId,
      action: userAction.action,
      timestamp: userAction.timestamp.toISOString(),
      ...userAction.details,
    },
  });
}

However, due to historical reasons, there wasn’t a single class representing metrics, and properties were scattered across different functions. This was a clear indication that a builder design pattern was needed to assemble custom metrics.

design pattern

To write clean code, you need to learn and understand design patterns thoroughly. Here’s a great resource: Refactoring Guru.

Architectural Design

At a certain level, applying good design patterns to your project becomes essential. For instance, while working on an iOS app managing passcodes, I wanted to track every user operation—add, delete, update, rotate.

I decided to use the Event Sourcing architectural design pattern. Here’s the prompt I used:

event sourcing prompt

The LLM generated the event models for me:

events model

It then created an event store:

events store

Finally, it integrated the event store into the target object:

events integration

I was impressed with the quality of the generated code. The LLM correctly applied the event sourcing pattern to the Passcode class, utilized Swift’s Codable protocol, and integrated Core Data for event storage.

The key takeaway here is that understanding architectural design patterns like Event Sourcing is crucial before asking AI to implement them.

Pro Level

To fully leverage AI for end-to-end project development, you need to use it as:

  1. A Product Manager (PM)
  2. An Architect
  3. A Tech Lead

Don’t rush into coding. Instead:

  • Understand what you want to achieve.
  • Ask questions. Starts with why.
  • Define what features you want to build.
  • Evaluate trade-offs. Software development is an art of balancing trade-offs.
  • Plan wisely.
  • Execute the plan using agent mode.
  • Document everything—from functional requirements to major updates and architectural designs.

PM

Use the ask mode and treat AI as your PM. Express your goals clearly. For example:

(WHY)
I want to build a passcode management app so that (...).

(WHAT)
Users can:

- Create new passcodes
- View & hide passcodes
- Rotate passcodes
- Lock passcodes

Can you help me come up with a feature list and delivery plan?

Once you have the feature list, divide and conquer each work item.

Architect

Switch to ask mode and treat AI as your architect. Ask questions like:

Given the above requirements:

- What architectural design pattern would you recommend?
- What storage mechanism should we use and why?
- What logging framework would you suggest?
- What metrics should we track, and which framework should we use?
- How should we handle deployment?

After a few iterations, you’ll arrive at the right design pattern for your project’s scope.

Tech Lead

Before diving into code, switch to agent mode and treat AI as your tech lead. Ask questions such as:

- What should the folder structure look like?
- What does each function do?
- What design patterns can we use for each module?

Then we ask the teach lead to:

- Use the best [Object-Oriented Design](https://www.geeksforgeeks.org/oops-object-oriented-design) patterns
- Follow the [Test-Driven Development](https://en.wikipedia.org/wiki/Test-driven_development) practices
- Write function. For each function:
  - Only write the function signature
  - Write detailed descriptions
  - Leave `TODO` placeholders

The goal is to avoid local optimization and think holistically about the project.

Implementation

The final step is to use agent mode for implementation.

Documentation

Documentation is crucial. Document:

  1. Design choices
  2. Features
  3. Design patterns

This helps preserve the project’s context, which can later be fed back into the LLM model.

Wizard Level

For now, AI coders cannot fully replace developers. I am not sure about the future.

I strongly encourage you to continue learning hard topics and reading classic books. This will help you become a better developer and allows you to truly leverage AI for handling boilerplate codes.

Here are some classic books I highly recommend:

Closing Words

I’ve always been enthusiastic about AI. Even before GPT became popular, I was already familiar with the transformer model.

When LLMs started gaining traction, I initially focused on building AI products. It never occurred to me to use AI to make my own work easier.

In January 2025, I started using GitHub Copilot (it’s free at Microsoft!). I was amazed by how much it improved my productivity—I became at least five times more efficient.

In April 2025, I began using Cursor after hearing great things about it. Once again, I was impressed by how powerful the IDE and the Claude model are. With these tools, I’ve been able to create products I never thought possible.

To conclude, I’ll leave you with a quote from Andrew Ng:

AI won’t replace human workers, but people that use it will replace people that don’t