Skip to main content
Building with AI (Vibe Coding)

⏱ About 20 min20 XP

Reading Code You Didn't Write

Ownership of software means being able to answer for it — to explain what it does, to identify what could go wrong, and to change it when requirements shift. A builder who cannot read the code the AI generated for them does not own that code; they are operating it blindly. Blind operation is acceptable for a microwave oven. It is not acceptable for software that handles other people's data, makes financial transactions, or controls anything with real-world consequences. This lesson is about developing the reading fluency to take genuine ownership of AI-generated code.

A Reading Strategy for Generated Code

Reading code you did not write requires a different approach than writing code from scratch. When writing, you build understanding incrementally as you construct each piece. When reading, you must reconstruct understanding from a finished artifact. These are genuinely different cognitive tasks. A reliable strategy for reading AI-generated code proceeds in layers. Layer 1: Structure. Before reading any logic, identify the overall structure. What are the major functions or components? What does each one appear to be responsible for? How do they relate to each other? This layer is readable even without knowing the programming language deeply — you are looking at names, organization, and size. Layer 2: Data flow. Identify where data enters the code, how it moves through functions, what transformations it undergoes, and where it exits or is stored. Follow a single piece of data from input to output. Tracing data flow reveals most integration bugs — places where the format a function produces does not match what the next function expects. Layer 3: Control flow. Understand the paths through the code. What conditions cause different branches to execute? Are all cases handled? What happens when an error occurs — does the code catch it, ignore it, or let it propagate? Control flow reading reveals missing error handling and unhandled edge cases. Layer 4: Assumptions. Identify what the code assumes about its inputs. Does a function assume its input is never null? Does it assume a list is never empty? Does it assume a string matches a particular format? Assumptions are often the source of production bugs — the input that violates an assumption is usually the one a real user eventually provides.

Reading Is Not Optional

Many vibe coders test their code instead of reading it — they run it, see that it produces the right output for one input, and consider it understood. Testing and reading are complementary, not substitutes. A test checks specific cases; reading reveals the logic that handles all cases, including ones you have not tested. Both are necessary for genuine ownership.

Let us apply the layered reading strategy to a short example. Imagine an AI generated this function (written in pseudocode to be language-independent): function findOverdueOrders(orders, thresholdDays): result = [] today = getCurrentDate() for order in orders: daysDiff = today - order.createdDate if daysDiff > thresholdDays and order.status == 'open': result.append(order) return result Layer 1 (structure): One function, named descriptively. Takes a list of orders and a threshold. Returns a filtered list. Layer 2 (data flow): Input is a list of order objects and an integer. The function computes a date difference for each order and accumulates matching orders in a result list. Output is a filtered list. Layer 3 (control flow): A loop over all orders, a conditional with two clauses joined by AND. Both conditions must be true to include an order. No error handling. Layer 4 (assumptions): Assumes orders is a non-null, iterable collection. Assumes each order has a createdDate attribute. Assumes createdDate is in the same format as the value returned by getCurrentDate() — if one is a timestamp and the other is a date string, the subtraction fails. Assumes order.status is exactly the string 'open' — if statuses can be 'Open' or 'OPEN' (different capitalization), those orders would be missed. These are not obvious from the code; they are assumptions embedded in it. Reading to layer 4 revealed three potential bugs that testing a single happy-path case would not catch.

Flashcards — click each card to reveal the answer

Practical Techniques for Faster Reading

Several practical techniques make reading AI-generated code more efficient. Ask the AI to explain it. After generating code, you can prompt: 'Explain what this code does, step by step, including any assumptions it makes about its inputs.' This is not a substitute for reading — the AI's explanation can itself be wrong or incomplete — but it is a useful first pass that often surfaces the parts worth reading most carefully. Annotate as you read. Write a short comment above each function describing what you understand it to do. When you finish reading, compare your comments to the function names and any existing comments. Discrepancies indicate either a misunderstanding or poorly named code — both worth resolving. Trace with a concrete example. Pick a specific input — make it simple but realistic — and trace its journey through the code manually, noting what value each variable holds at each step. This is the most reliable way to catch logical errors and violated assumptions. Search for the dangerous patterns. Some code patterns are high-risk regardless of context: string concatenation into SQL queries (SQL injection risk), missing input validation before storage, unchecked array access, credentials hardcoded as strings, and missing authentication checks on data-modification endpoints. Learn to visually scan for these patterns; they are worth finding even before a full systematic reading.

AI Explanations Can Be Wrong

When you ask an AI to explain code it generated, the explanation is itself a prediction — another piece of text that may or may not accurately describe what the code actually does. AI models have been observed explaining code incorrectly, particularly when the code has a subtle bug. Always treat the explanation as a starting point for your own reading, not as a verified description.

A vibe coder runs their AI-generated code with three test inputs, all of which produce correct output. They conclude the code is correct. What is the flaw in this reasoning?

In the order-filtering example from this lesson, the code checks order.status == 'open'. What type of reading revealed that this assumption could cause bugs?

The Four-Layer Read

  1. Step 1: Ask your teacher or a classmate to find or write a short function (10-25 lines) in any language — something that processes a list and returns a filtered or transformed result.
  2. Step 2: Apply the four-layer reading strategy. Write your findings for each layer on separate lines:
  3. Layer 1 (Structure): What are the major parts? What is each responsible for?
  4. Layer 2 (Data flow): Where does data enter? What transformations happen? Where does it exit?
  5. Layer 3 (Control flow): What are all the paths through the code? Are all cases handled?
  6. Layer 4 (Assumptions): What does the code silently assume about its inputs?
  7. Step 3: For each assumption you identified in Layer 4, write one specific input that would violate it and describe what would happen.
  8. Step 4: Identify one test case you would run to check each assumption. Compare your four-layer analysis with a classmate's. Did you find the same assumptions?