{"course":{"slug":"how-software-changed","title":"How Software Development Changed","url":"https://addaly.com/learn/how-software-changed","level":"intermediate","track":"work"},"lesson":{"slug":"reading-at-volume","title":"Reviewing code you did not write","url":"https://addaly.com/learn/how-software-changed/reading-at-volume","position":10,"of":87,"minutes":9,"answer":"You own every line you submit, whoever typed it; if you cannot explain it in review, it is not ready.","keyIdea":"You own every line you submit, whoever typed it; if you cannot explain it in review, it is not ready."},"body":{"format":"markdown","text":"## The economics of review just inverted\n\nReview used to be roughly balanced. A change that took a day to write took maybe forty minutes to read, because the author had already done the thinking and the diff carried the shape of that thinking.\n\nNow a 600-line diff can represent four minutes of author effort and forty minutes of yours. The person who submitted it may not have read all of it carefully themselves. You are the first human to think hard about those lines, and you are doing it under the social assumption that someone already did.\n\nThat asymmetry is the whole problem. It creates steady pressure toward the rubber stamp, and the rubber stamp is where the bad changes get in.\n\n## Rules that hold up under volume\n\n**Refuse the giant diff.** A 2,000-line pull request is not reviewable by anyone, and it never was. The difference now is that it takes no effort to produce one, so the norm has to be explicit. Ask for it in slices that each do one thing. This is not politeness, it is the only way the review means anything.\n\n**Read the tests first, then ask what they do not cover.** Generated tests tend to cover the path the code was written for. Look for the empty input, the duplicate, the second call, the failure of the thing it depends on.\n\n**Check the change against the intent, not only against itself.** This is the big one. Generated code is almost always internally consistent: names match, structure is clean, the comments describe what the code does. Internal consistency used to be weak evidence of care. It is now free. So compare against the ticket, the spec, the actual requirement, and ask whether this solves the problem that was posed.\n\n**Hunt for removed safety.** These are the highest-yield lines in any diff:\n\n```python\n-    if account is None:\n-        raise AccountNotFound(account_id)\n\n-except ValidationError as e:\n+except Exception:\n+    pass\n\n-@pytest.mark.parametrize(\"currency\", CURRENCIES)\n+@pytest.mark.skip(\"flaky\")\n```\n\nA check disappears, an exception net gets wider, a type gets loosened, a test gets skipped, a lint rule gets an inline suppression. Each one may be fine. Each one deserves a sentence of explanation in the pull request, and if there isn't one, ask.\n\n**Watch the blast radius.** Look at what the change touched that it was not asked to touch. A request to fix date formatting that also reorders a dictionary, renames a parameter, and updates an unrelated dependency version is three changes wearing one hat.\n\n## The question that does the most work\n\nPick two or three lines that look load-bearing and ask the author, plainly: why is this here, and what happens if it is not?\n\nThis is not a trap and it should not feel like one. It is the fastest way to find out whether the change is understood by anybody. If the answer is a shrug or a paraphrase of the code, the change is not ready, not because the code is wrong, but because nobody yet owns it.\n\n## Two norms worth arguing for\n\n**The author owns the diff.** Whoever submits it is responsible for every line, whatever produced them. \"The model wrote that part\" is not a defence and should not be treated as one. The practical form of this rule: if you cannot explain a line in review, do not submit it. Take the ten minutes to understand it or take it out.\n\n**A reviewer can say \"I don't understand this yet\" at no cost.** If admitting confusion is socially expensive on your team, you will get approvals instead of reviews, and you will not find out for months. Make the phrase normal by using it yourself, in public, on code you could probably work out if you tried.\n\n## Where the model helps in review\n\nUsing a model to help you review is useful, with one boundary. Asking it to summarise an unfamiliar diff, list every call site of a changed function, or explain what a dense regex does: good, fast, low risk, because you can verify the answer.\n\nAsking it whether the change is correct: that is the judgement you were brought in to make, and it does not have the context that makes the judgement possible: what this system is for, what broke last quarter, what the on-call rotation can tolerate. Use it to reduce your reading cost, not to replace your reading."},"check":{"question":"A colleague sends you a 900-line pull request implementing a feature you both discussed. The code is clean, consistently named, well commented, and the 40 included tests all pass. Which of these is the strongest reason to slow down rather than approve?","options":[{"text":"Forty tests is too few for 900 lines of new code, so coverage is the first thing to question.","correct":false,"tempting":"Uses test count as a proxy for confidence, when the useful question is whether any of those tests would fail if the behaviour broke."},{"text":"Nine hundred lines is too long, and length alone means the change should be rejected on process grounds.","correct":false,"tempting":"Right instinct, wrong reason: size matters because it exceeds what a human can hold, not as a rule to be enforced without thought."},{"text":"Clean, consistent, well-commented code is now free to produce, so its polish tells you almost nothing about whether it does the right thing.","correct":true},{"text":"The colleague probably used a model, and code from models needs stricter review than code from people.","correct":false,"tempting":"Sorts by origin rather than by property; a careful person with a model can produce a better change than a careless person without one, and you often cannot tell which you have."}]},"prev":{"slug":"the-honest-ledger","title":"Measuring the effect on yourself","url":"https://addaly.com/learn/how-software-changed/the-honest-ledger"},"next":{"slug":"plausible-but-wrong","title":"The new failure mode: plausible and wrong","url":"https://addaly.com/learn/how-software-changed/plausible-but-wrong"},"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) 'Reviewing code you did not write', in How Software Development Changed. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/how-software-changed/reading-at-volume (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":"Reviewing code you did not write","courseTitle":"How Software Development Changed","module":{"index":2,"slug":"reading-what-you-did-not-write","title":"Reading what you did not write"},"answer":null,"keyIdea":"You own every line you submit, whoever typed it; if you cannot explain it in review, it is not ready.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"the-economics-of-review-just-inverted","runs":[{"text":"The economics of review just inverted"}]},{"t":"p","runs":[{"text":"Review used to be roughly balanced. A change that took a day to write took maybe forty minutes to read, because the author had already done the thinking and the diff carried the shape of that thinking."}]},{"t":"p","runs":[{"text":"Now a 600-line diff can represent four minutes of author effort and forty minutes of yours. The person who submitted it may not have read all of it carefully themselves. You are the first human to think hard about those lines, and you are doing it under the social assumption that someone already did."}]},{"t":"p","runs":[{"text":"That asymmetry is the whole problem. It creates steady pressure toward the rubber stamp, and the rubber stamp is where the bad changes get in."}]},{"t":"h2","id":"rules-that-hold-up-under-volume","runs":[{"text":"Rules that hold up under volume"}]},{"t":"p","runs":[{"text":"Refuse the giant diff.","b":true},{"text":" A 2,000-line pull request is not reviewable by anyone, and it never was. The difference now is that it takes no effort to produce one, so the norm has to be explicit. Ask for it in slices that each do one thing. This is not politeness, it is the only way the review means anything."}]},{"t":"p","runs":[{"text":"Read the tests first, then ask what they do not cover.","b":true},{"text":" Generated tests tend to cover the path the code was written for. Look for the empty input, the duplicate, the second call, the failure of the thing it depends on."}]},{"t":"p","runs":[{"text":"Check the change against the intent, not only against itself.","b":true},{"text":" This is the big one. Generated code is almost always internally consistent: names match, structure is clean, the comments describe what the code does. Internal consistency used to be weak evidence of care. It is now free. So compare against the ticket, the spec, the actual requirement, and ask whether this solves the problem that was posed."}]},{"t":"p","runs":[{"text":"Hunt for removed safety.","b":true},{"text":" These are the highest-yield lines in any diff:"}]},{"t":"code","lang":"python","label":"Python","text":"-    if account is None:\n-        raise AccountNotFound(account_id)\n\n-except ValidationError as e:\n+except Exception:\n+    pass\n\n-@pytest.mark.parametrize(\"currency\", CURRENCIES)\n+@pytest.mark.skip(\"flaky\")"},{"t":"p","runs":[{"text":"A check disappears, an exception net gets wider, a type gets loosened, a test gets skipped, a lint rule gets an inline suppression. Each one may be fine. Each one deserves a sentence of explanation in the pull request, and if there isn’t one, ask."}]},{"t":"p","runs":[{"text":"Watch the blast radius.","b":true},{"text":" Look at what the change touched that it was not asked to touch. A request to fix date formatting that also reorders a dictionary, renames a parameter, and updates an unrelated dependency version is three changes wearing one hat."}]},{"t":"h2","id":"the-question-that-does-the-most-work","runs":[{"text":"The question that does the most work"}]},{"t":"p","runs":[{"text":"Pick two or three lines that look load-bearing and ask the author, plainly: why is this here, and what happens if it is not?"}]},{"t":"p","runs":[{"text":"This is not a trap and it should not feel like one. It is the fastest way to find out whether the change is understood by anybody. If the answer is a shrug or a paraphrase of the code, the change is not ready, not because the code is wrong, but because nobody yet owns it."}]},{"t":"h2","id":"two-norms-worth-arguing-for","runs":[{"text":"Two norms worth arguing for"}]},{"t":"p","runs":[{"text":"The author owns the diff.","b":true},{"text":" Whoever submits it is responsible for every line, whatever produced them. “The model wrote that part” is not a defence and should not be treated as one. The practical form of this rule: if you cannot explain a line in review, do not submit it. Take the ten minutes to understand it or take it out."}]},{"t":"p","runs":[{"text":"A reviewer can say “I don’t understand this yet” at no cost.","b":true},{"text":" If admitting confusion is socially expensive on your team, you will get approvals instead of reviews, and you will not find out for months. Make the phrase normal by using it yourself, in public, on code you could probably work out if you tried."}]},{"t":"h2","id":"where-the-model-helps-in-review","runs":[{"text":"Where the model helps in review"}]},{"t":"p","runs":[{"text":"Using a model to help you review is useful, with one boundary. Asking it to summarise an unfamiliar diff, list every call site of a changed function, or explain what a dense regex does: good, fast, low risk, because you can verify the answer."}]},{"t":"p","runs":[{"text":"Asking it whether the change is correct: that is the judgement you were brought in to make, and it does not have the context that makes the judgement possible: what this system is for, what broke last quarter, what the on-call rotation can tolerate. Use it to reduce your reading cost, not to replace your reading."}]}],"check":{"question":[{"text":"A colleague sends you a 900-line pull request implementing a feature you both discussed. The code is clean, consistently named, well commented, and the 40 included tests all pass. Which of these is the strongest reason to slow down rather than approve?"}],"options":[{"text":[{"text":"Forty tests is too few for 900 lines of new code, so coverage is the first thing to question."}],"correct":false,"tempting":[{"text":"Uses test count as a proxy for confidence, when the useful question is whether any of those tests would fail if the behaviour broke."}]},{"text":[{"text":"Nine hundred lines is too long, and length alone means the change should be rejected on process grounds."}],"correct":false,"tempting":[{"text":"Right instinct, wrong reason: size matters because it exceeds what a human can hold, not as a rule to be enforced without thought."}]},{"text":[{"text":"Clean, consistent, well-commented code is now free to produce, so its polish tells you almost nothing about whether it does the right thing."}],"correct":true,"tempting":null},{"text":[{"text":"The colleague probably used a model, and code from models needs stricter review than code from people."}],"correct":false,"tempting":[{"text":"Sorts by origin rather than by property; a careful person with a model can produce a better change than a careless person without one, and you often cannot tell which you have."}]}],"order":[3,1,0,2],"why":null},"prev":{"slug":"the-honest-ledger","title":"Measuring the effect on yourself","minutes":9},"next":{"slug":"plausible-but-wrong","title":"The new failure mode: plausible and wrong","minutes":9}}}