Skip to content
Back to all field notes vibe · 7 min

You shipped code you can't read. Now what?

The quiet panic of vibe coding: the app is live, people use it, and you cannot follow a single file. This is the way out, and it is not learning to read every line.

field note 7 min

Here is a sentence a lot of people are thinking and very few are saying out loud: I can’t read my own code. The app works, real people use it, you built it, and if you open any file you cannot really say what it does or why. Every change is a bet. Every bug is an excavation. You are running software you do not understand, and you are the whole support team.

This is one of the most common and least discussed states in modern software. It is not a personal failing and it is not permanent. But the way out is not the obvious one, and the obvious one will drown you.

The obvious plan that fails

The instinct is: sit down and read the whole thing until you understand it. Line by line, file by file, until it clicks.

This fails for a specific reason. AI-generated code is often locally reasonable and globally sprawling. There is a lot of it, it is spread thin, and reading it top to bottom gives you thousands of details and no structure. You finish more tired and no clearer, because understanding software is not about having read the lines. It is about knowing the shape: what the real parts are, how they connect, where the important behavior lives. That is a different thing from the text, and reading the text does not hand it to you.

The second failing instinct is to rewrite it, so at least you will understand the new version. That trades a working app you do not understand for a broken app you do, and rebuilds the same gaps in the process. Almost never the answer.

What understanding actually means

You do not need to know every line. No working engineer knows every line of a system they own. What they have is a map at the right altitude, and the ability to zoom in on demand.

Concretely, being in control of your app means you can answer, without reading code:

  • What are the four or five real pieces of this app, and what is each one for?
  • When a user does the main thing, what happens, in order, across those pieces?
  • Where does the data live, and what shape is it?
  • If I change this, what else could feel it?

That is the target. Not fluency in every file. A navigable model of the whole, with the detail available when you need it and out of your way when you do not.

How to build the map

You can do a version of this by hand today. It is slow, but it works, and it is worth doing at least once so you know what the map should contain.

Start from the outside, not the code. List what the app does from a user’s point of view. The features, the flows, the roles. This is the spine you will hang everything else on.

Trace one flow all the way through. Pick the single most important thing a user does. Follow it from the screen to wherever the data ends up, naming each part it passes through. Do not read anything you do not have to. You are drawing the route, not surveying the terrain.

Name the real parts. By the end of a couple of traces, the same few components keep showing up. Those are your real parts. Write them down with one sentence each. Most apps have surprisingly few.

Ask the agent to explain, then verify. You can have a model summarize a file or a flow. This is genuinely useful and genuinely dangerous, because a plausible summary of code that does something else is worse than no summary. Treat every explanation as a claim to check against behavior, not a fact. The same discipline that a green build is not proof applies here: an explanation that sounds right is not the same as one that is right.

When you can sketch the parts and trace the main flow from memory, you have crossed from passenger to driver. You still cannot read every line. You no longer need to.

Write it down before you forget it again

The cruel part of this state is that you were in it once already, at the start, and it faded. The understanding you build now will fade too, unless it lives somewhere outside your head. So as you build the map, write it down: the parts, the flows, what each is for. This is the beginning of the documentation the prototype never had, and it is what stops you landing right back here in two months. A map that only lives in memory is a map you will lose, which is why it eventually wants to become a living map of the code, not bigger prompts you retype every session.

This is stage one of a longer bridge

Getting readable is not the whole job, it is the first stage of it. Once you can navigate the app, the next moves are to write down what it is supposed to do, put a safety net under the current behavior, and reinforce the structure, in that order. Understanding is what makes all three possible: you cannot specify, test, or fix what you cannot find. The full route from here is from vibe coding to production.

Where PaellaDoc fits

The manual map works once. The problem is that the code keeps changing and the map in your head goes stale immediately, which is how you got here. PaellaDoc reads an existing repo into a navigable model of its real parts and flows, and keeps that model attached to the code as it changes, so the map stays true instead of rotting the day after you draw it. The goal is not to read the code for you. It is so “what does this app actually do” has an answer that survives longer than your memory of building it.

You are not stuck. You are one map away from being in control of your own app again.

FAQ

How do I understand AI-generated code I didn’t really read? Not by reading every line. Build a map at the level of parts and flows: what the real pieces are, how the main user action moves through them, and where the data lives. Understanding is knowing the shape, not having read the text.

Should I rewrite code I don’t understand? Almost never. A rewrite trades a working app you don’t understand for a broken one you do, and recreates the same gaps. Map it and reinforce it in place instead.

Can I just ask the AI to explain my code? As a starting point, yes, but treat every explanation as a claim to verify against actual behavior. A confident summary of code that does something else is worse than no summary.