{"course":{"slug":"building-apps-with-ai","title":"Building Apps with AI","url":"https://addaly.com/learn/building-apps-with-ai","level":"beginner","track":"build"},"lesson":{"slug":"reading-code-you-did-not-write","title":"Reading code you did not write","url":"https://addaly.com/learn/building-apps-with-ai/reading-code-you-did-not-write","position":19,"of":87,"minutes":9,"answer":"Read code to answer one question at a time, and confirm claims by using the app rather than searching the text.","keyIdea":"Read code to answer one question at a time, and confirm claims by using the app rather than searching the text."},"body":{"format":"markdown","text":"## You do not need to understand every line\n\nProfessional programmers do not read code the way you read a novel. They read to answer a question. You can learn that in an afternoon, and it is the single skill that turns AI output from a gamble into a tool.\n\nThe question is almost always: **what happens when someone does this thing?**\n\n## Trace one action, end to end\n\nPick a single thing a user does. Follow it through the code. For a booking form:\n\n1. **Find the button.** Search the project for the button's text: \"Book now\". You land in a file that draws the form.\n2. **Find what the button calls.** Something like `onSubmit={handleSubmit}` or `action=\"/api/bookings\"`. Follow it.\n3. **Find where it goes on the server.** A file like `app/api/bookings/route.ts`. Read that function top to bottom. It is usually thirty lines.\n4. **Find where it touches the database.** An `insert` or `INSERT INTO`. That is the moment something becomes permanent.\n5. **Find where it is read back.** Whatever query the bookings page runs.\n\nYou now understand that feature. Not the whole codebase: that feature. Do this three times and the shape of the project stops being a mystery.\n\n## Four questions for any chunk of code\n\n- What goes in?\n- What comes out?\n- What does it change that survives after the request ends: the database, a file, an email that was sent?\n- What happens when it fails?\n\nThat fourth one finds most problems.\n\n## Things to look for, specifically\n\n**Errors that go nowhere.**\n\n```js\ntry {\n  await saveBooking(booking)\n} catch (e) {\n  // ignore\n}\n```\n\nThe save can fail and the user still sees \"Booked.\" This shows up constantly, because swallowing errors makes the code stop complaining, and code that stops complaining looks finished.\n\n**Checks that happen in the browser only.** If the only thing stopping a bad action is a hidden button or a disabled input, there is no check at all. More on this in lesson 8.\n\n**Values typed straight into the code.** A price, a tax rate, a phone prefix, a URL like `http://localhost:3000` sitting inside a function. It works on your machine and breaks the moment you deploy.\n\n**Code nobody calls.** Agents leave orphans behind. If you cannot find anything that uses a function, it may be dead, or the thing you thought was running is a different function with a similar name.\n\n**A second copy.** Ask the model to fix a bug twice and you can end up with `formatDate` and `formatDateNew`, one of which is still wrong and still used somewhere.\n\n## Read the diff, not the file\n\nAfter a change, look at what changed rather than re-reading everything. `git diff` in the terminal, or the source control panel in your editor, shows you added lines in green and removed in red. Ninety percent of your reading should be diffs. If a request to add a cancel button produced changes in nine files, something happened that you did not ask for, and you want to know what before you move on.\n\n## Make the model explain, then check the explanation\n\n\"Explain what this function does, line by line, as if I have never seen this framework\" is a good use of the tool. Explanations are easier to evaluate than code.\n\nBut an explanation is a second generation, not a source of truth. It can describe code the model intended to write rather than the code on disk. So verify claims against reality, and prefer verifying by **behaviour** over verifying by **text**.\n\nIf it says \"I added validation so invalid emails are rejected,\" do not search the file for the word \"validate.\" A comment mentioning validation will match. Instead, open the form and submit `a@b`, then submit nothing at all, and watch what the app does.\n\nSearching the source tells you what the code says about itself. Using the app tells you what it does.\n\n## A five-minute review you can actually do\n\nAfter each change:\n\n1. Read the diff. Every file. Skim is fine.\n2. Anything you do not recognise, ask: \"why did you change this file?\"\n3. Find the failure path. What happens when the input is empty, wrong, or duplicated?\n4. Use the feature. Then use it wrongly on purpose.\n5. Commit if it works.\n\nYou will catch more than you expect, because most AI bugs are not subtle. They are loud, and nobody looked."},"check":{"question":"The agent says: \"I added a check so a stylist cannot be double-booked.\" What is the strongest way to find out whether that is true?","options":[{"text":"Open the app and try to book the same stylist for the same time twice.","correct":true},{"text":"Search the codebase for the word \"overlap\" or \"conflict\" to confirm the check exists.","correct":false,"tempting":"Treats a text match as proof of behavior: a comment, a variable name, or an unused function all match, and none of them stop a double booking."},{"text":"Ask the agent to review its own work and confirm the check is correct.","correct":false,"tempting":"Seeks a second opinion from the same source, which produces new confident text rather than new evidence."},{"text":"Read the agent's summary again carefully, since it lists exactly which files it changed.","correct":false,"tempting":"Uses the summary as the record of what happened, when the summary is generated alongside the code and can describe intentions rather than the file on disk."}]},"prev":{"slug":"questions-the-model-should-ask-you","title":"Making the model ask before it guesses","url":"https://addaly.com/learn/building-apps-with-ai/questions-the-model-should-ask-you"},"next":{"slug":"reading-a-diff-properly","title":"Reading a diff properly","url":"https://addaly.com/learn/building-apps-with-ai/reading-a-diff-properly"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Reading code you did not write', in Building Apps with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-apps-with-ai/reading-code-you-did-not-write (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Reading code you did not write","courseTitle":"Building Apps with AI","module":{"index":3,"slug":"reading-and-checking","title":"Reading and checking what came back"},"answer":null,"keyIdea":"Read code to answer one question at a time, and confirm claims by using the app rather than searching the text.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"you-do-not-need-to-understand-every-line","runs":[{"text":"You do not need to understand every line"}]},{"t":"p","runs":[{"text":"Professional programmers do not read code the way you read a novel. They read to answer a question. You can learn that in an afternoon, and it is the single skill that turns AI output from a gamble into a tool."}]},{"t":"p","runs":[{"text":"The question is almost always: "},{"text":"what happens when someone does this thing?","b":true}]},{"t":"h2","id":"trace-one-action-end-to-end","runs":[{"text":"Trace one action, end to end"}]},{"t":"p","runs":[{"text":"Pick a single thing a user does. Follow it through the code. For a booking form:"}]},{"t":"ol","start":1,"items":[[{"text":"Find the button.","b":true},{"text":" Search the project for the button’s text: “Book now”. You land in a file that draws the form."}],[{"text":"Find what the button calls.","b":true},{"text":" Something like "},{"text":"onSubmit={handleSubmit}","code":true},{"text":" or "},{"text":"action=\"/api/bookings\"","code":true},{"text":". Follow it."}],[{"text":"Find where it goes on the server.","b":true},{"text":" A file like "},{"text":"app/api/bookings/route.ts","code":true},{"text":". Read that function top to bottom. It is usually thirty lines."}],[{"text":"Find where it touches the database.","b":true},{"text":" An "},{"text":"insert","code":true},{"text":" or "},{"text":"INSERT INTO","code":true},{"text":". That is the moment something becomes permanent."}],[{"text":"Find where it is read back.","b":true},{"text":" Whatever query the bookings page runs."}]]},{"t":"p","runs":[{"text":"You now understand that feature. Not the whole codebase: that feature. Do this three times and the shape of the project stops being a mystery."}]},{"t":"h2","id":"four-questions-for-any-chunk-of-code","runs":[{"text":"Four questions for any chunk of code"}]},{"t":"ul","items":[[{"text":"What goes in?"}],[{"text":"What comes out?"}],[{"text":"What does it change that survives after the request ends: the database, a file, an email that was sent?"}],[{"text":"What happens when it fails?"}]]},{"t":"p","runs":[{"text":"That fourth one finds most problems."}]},{"t":"h2","id":"things-to-look-for-specifically","runs":[{"text":"Things to look for, specifically"}]},{"t":"p","runs":[{"text":"Errors that go nowhere.","b":true}]},{"t":"code","lang":"js","label":"JavaScript","text":"try {\n  await saveBooking(booking)\n} catch (e) {\n  // ignore\n}"},{"t":"p","runs":[{"text":"The save can fail and the user still sees “Booked.” This shows up constantly, because swallowing errors makes the code stop complaining, and code that stops complaining looks finished."}]},{"t":"p","runs":[{"text":"Checks that happen in the browser only.","b":true},{"text":" If the only thing stopping a bad action is a hidden button or a disabled input, there is no check at all. More on this in lesson 8."}]},{"t":"p","runs":[{"text":"Values typed straight into the code.","b":true},{"text":" A price, a tax rate, a phone prefix, a URL like "},{"text":"http://localhost:3000","code":true},{"text":" sitting inside a function. It works on your machine and breaks the moment you deploy."}]},{"t":"p","runs":[{"text":"Code nobody calls.","b":true},{"text":" Agents leave orphans behind. If you cannot find anything that uses a function, it may be dead, or the thing you thought was running is a different function with a similar name."}]},{"t":"p","runs":[{"text":"A second copy.","b":true},{"text":" Ask the model to fix a bug twice and you can end up with "},{"text":"formatDate","code":true},{"text":" and "},{"text":"formatDateNew","code":true},{"text":", one of which is still wrong and still used somewhere."}]},{"t":"h2","id":"read-the-diff-not-the-file","runs":[{"text":"Read the diff, not the file"}]},{"t":"p","runs":[{"text":"After a change, look at what changed rather than re-reading everything. "},{"text":"git diff","code":true},{"text":" in the terminal, or the source control panel in your editor, shows you added lines in green and removed in red. Ninety percent of your reading should be diffs. If a request to add a cancel button produced changes in nine files, something happened that you did not ask for, and you want to know what before you move on."}]},{"t":"h2","id":"make-the-model-explain-then-check-the-explanation","runs":[{"text":"Make the model explain, then check the explanation"}]},{"t":"p","runs":[{"text":"“Explain what this function does, line by line, as if I have never seen this framework” is a good use of the tool. Explanations are easier to evaluate than code."}]},{"t":"p","runs":[{"text":"But an explanation is a second generation, not a source of truth. It can describe code the model intended to write rather than the code on disk. So verify claims against reality, and prefer verifying by "},{"text":"behaviour","b":true},{"text":" over verifying by "},{"text":"text","b":true},{"text":"."}]},{"t":"p","runs":[{"text":"If it says “I added validation so invalid emails are rejected,” do not search the file for the word “validate.” A comment mentioning validation will match. Instead, open the form and submit "},{"text":"a@b","code":true},{"text":", then submit nothing at all, and watch what the app does."}]},{"t":"p","runs":[{"text":"Searching the source tells you what the code says about itself. Using the app tells you what it does."}]},{"t":"h2","id":"a-five-minute-review-you-can-actually-do","runs":[{"text":"A five-minute review you can actually do"}]},{"t":"p","runs":[{"text":"After each change:"}]},{"t":"ol","start":1,"items":[[{"text":"Read the diff. Every file. Skim is fine."}],[{"text":"Anything you do not recognise, ask: “why did you change this file?”"}],[{"text":"Find the failure path. What happens when the input is empty, wrong, or duplicated?"}],[{"text":"Use the feature. Then use it wrongly on purpose."}],[{"text":"Commit if it works."}]]},{"t":"p","runs":[{"text":"You will catch more than you expect, because most AI bugs are not subtle. They are loud, and nobody looked."}]}],"check":{"question":[{"text":"The agent says: “I added a check so a stylist cannot be double-booked.” What is the strongest way to find out whether that is true?"}],"options":[{"text":[{"text":"Open the app and try to book the same stylist for the same time twice."}],"correct":true,"tempting":null},{"text":[{"text":"Search the codebase for the word “overlap” or “conflict” to confirm the check exists."}],"correct":false,"tempting":[{"text":"Treats a text match as proof of behavior: a comment, a variable name, or an unused function all match, and none of them stop a double booking."}]},{"text":[{"text":"Ask the agent to review its own work and confirm the check is correct."}],"correct":false,"tempting":[{"text":"Seeks a second opinion from the same source, which produces new confident text rather than new evidence."}]},{"text":[{"text":"Read the agent’s summary again carefully, since it lists exactly which files it changed."}],"correct":false,"tempting":[{"text":"Uses the summary as the record of what happened, when the summary is generated alongside the code and can describe intentions rather than the file on disk."}]}],"order":[3,2,1,0],"why":null},"prev":{"slug":"questions-the-model-should-ask-you","title":"Making the model ask before it guesses","minutes":8},"next":{"slug":"reading-a-diff-properly","title":"Reading a diff properly","minutes":8}}}