labs · ai-assisted programming

Read-only preview. To do this lab: make your own copy of the repo ("Use this template"), open a Codespace on it, and work in lectures-and-labs/week11/vibe_coding_lab/.

AIAP Vibe Coding Lab

Build the same application three times without writing much code, then find out what you actually shipped — and build it once more the other way, so you have felt both sides of the argument rather than just heard it.

What you'll learn

Table of Contents

  1. Build it three times
  2. Read what you shipped
  3. Build it once more, spec-first
  4. Choosing a mode
  5. Common mistakes
  6. Summary

Getting started

Nothing to install — every tool in this lab runs in a browser. You need a free account on each of three prompt-first builders:

Each free plan has a daily limit, so build all three in one sitting. If a limit stops you, use Build mode in Google AI Studio instead, which needs a Google account.

Create a REFLECTION.md in this folder now; you will write into it throughout.

DIY 2 and DIY 4 use the Copilot chat in your Codespace. Open the chat panel with Ctrl+Alt+I (Ctrl+Cmd+I on a Mac). Every step that talks to the assistant names a mode: Plan reads and thinks but changes nothing; Interactive reads your files and asks before it runs a command or changes a file. This lab never needs Autopilot. Fresh conversation means press the + at the top of the chat panel first.

Tool names change. The three used here are examples of a category, not a prescription. If one has changed name, pricing or shut down, pick another prompt-first builder and note which you used. The exercise is about the category.


1. Build it three times

One brief, three tools. The repetition is the point: it separates what is true of the approach from what is true of one product.

The brief. A to-do application. Add a task, mark it done, delete it, and the list survives a page refresh.

DIY 1: The same app, three ways

  1. Write your prompt once, before opening any tool, and save it in REFLECTION.md. Use the same prompt for all three.
  2. Build the app in tool one. Record how long it took and how many follow-up prompts you needed.
  3. Repeat in tool two.
  4. Repeat in tool three.
  5. Check each app against the brief: add two tasks, tick one, delete the other, refresh the page. Note the first thing each tool got wrong — or, if it got nothing wrong, the first thing it decided that your prompt did not say, such as what happens with an empty task or the same task twice.

What you should have

Three working to-do apps, one shared prompt, and a table in REFLECTION.md recording time, number of follow-ups, and for each tool the first mistake, or the first decision it made that your prompt did not.

Hint

Using the same prompt for all three is what makes this a comparison rather than three anecdotes. Resist improving the prompt between tools — if you must, record that you did and why.

"Survives a page refresh" is the requirement that separates a demo from an app. Check it explicitly in all three. If one fails, that is your first mistake. If all three pass, look at what each one chose without being asked: what an empty task does, whether the same task can go in twice. The brief says nothing about either, so every tool answered for you.


2. Read what you shipped

You now own three applications you did not write. This section is the whole reason the lab exists.

DIY 2: Find something you would not ship

Pick one of the three and spend fifteen minutes in its source.

  1. Open its code view — the Code tab in Lovable, v0 and Google AI Studio, the <> icon in Bolt.new — and find the file that handles user input or data storage.

  2. Answer in REFLECTION.md:

    • How many dependencies did it add? Do you know what any of them do?
    • Is user input validated anywhere before being stored or displayed?
    • If this held real people's data, what would worry you?
  3. Find one line you genuinely cannot explain. Paste it.

  4. Fresh conversation, Plan, in the Copilot chat: paste the line and ask what it does. Did the explanation match what you had assumed?

  5. Fresh conversation, Plan: paste the whole file and ask directly:

    Review this code for security vulnerabilities as a security engineer would.

    Record what it finds.

What you should have

At least one concrete thing you would not ship, the line you could not explain, and the security review's findings.

Hint

Around 45% of AI-generated samples carry a common vulnerability class, so the base rate is on your side. Unvalidated input is the usual suspect — look for anything that goes from a form straight into storage: is there a limit on how long a task can be, or a check for an empty one? In plain JavaScript, also look for text that goes straight back onto the page through innerHTML. React escapes text by default, so in a React app that one is less likely.

Step 4 is the real exercise. The gap between what you assumed a line did and what it does is comprehension debt, measured directly, on code you created an hour ago.

Lovable shows its code read-only on the free plan. Reading is all this step needs.

DIY 3: Estimate the debt

  1. Pick the app you understand least.
  2. Write down what it would take to add one feature: let a user edit an existing task's text.
  3. Do not build it. Estimate: which files would you need to understand first, and how long would that take?
  4. Now answer honestly: is that estimate longer or shorter than writing the whole app yourself would have been?

What you should have

An estimate with reasoning, and an honest comparison against building it by hand.

Hint

There is no correct answer and the honest one is often "shorter" — these tools genuinely save time. The exercise is to make the trade visible rather than to conclude it is bad.

If your answer is "I would just ask the tool to add it", that is a legitimate strategy. Note what it depends on: that the tool still understands a codebase it wrote and you did not read.


3. Build it once more, spec-first

Now the other side of the argument, so your opinion is based on having done both.

DIY 4: Write the spec before the prompt

  1. In spec.md, before touching any tool, write one page:

    • What the app does
    • What it explicitly does not do
    • The data it stores, and its shape
    • Three acceptance criteria you could actually test
  2. Open spec.md. Fresh conversation, Plan, in the Copilot chat:

    Here is spec.md. Give me a plan: which files you will create and what each one does. Do not write code yet.

  3. Read the plan against your spec. Correct it where it drifted, in the same conversation.

  4. Only now switch the mode to Interactive, stay in the same conversation, and ask it to build the plan in a new folder called todo-spec next to this README. Allow the changes it asks for.

  5. Check the result against your three acceptance criteria.

What you should have

spec.md, the plan you reviewed and corrected, a working app, and a note of where the plan drifted from your spec.

Hint

Step 3 is the step everyone skips, and skipping it turns spec-driven development into vibe coding with extra paperwork. The plan is the cheapest place to catch a misunderstanding — cheaper than the code and far cheaper than the deployed app.

If your spec has no "does not do" section, it is not finished. Bounding the work is most of the value.

DIY 5: Compare, honestly

Record in REFLECTION.md:

## Vibe vs spec-driven

Time, vibe coding: ......... [minutes]
Time, spec-driven: ......... [minutes]
Which produced code you would defend? ....... [which, and why]
Which for a throwaway prototype? ............ [which]
Which for something assessed and demonstrated? [which]
Where did writing the spec change what you built? [be specific]
  1. Fill every line.
  2. Add two sentences on which mode you will actually use for your own work, and why.

What you should have

A completed comparison with a stated preference and a reason that is not "it is the responsible choice".

Hint

Spec-driven being slower is not a criticism — it is the cost, and the question is what the cost buys. If it bought nothing on a to-do app, say so. That is a real finding, and it is the argument for vibe coding on small disposable work.

The last line is the one worth thinking about: what did writing it down change about what you built? Usually something.


4. Choosing a mode

DIY 6: Write your own rule

  1. Complete this table in REFLECTION.md with your own examples:

    Task Mode I'd choose Why
    A weekend prototype
    A feature in assessed work
    Something a stranger maintains
    Code handling other people's data
  2. Add one row for a task you would give no assistant.

  3. Write two sentences on what would have to change for you to move a task from one mode to the other.

What you should have

A completed table with concrete tasks, including one you would not delegate, and a stated condition for switching modes.

Hint

Useful axes for the last question: how reversible is it, how well can you test it, how long will it live, and who pays if it is wrong.

If every row says the same mode, you have not found your boundary. Push until you do — the boundary is the actual output of this lab.


Common mistakes

Summary