[{"data":1,"prerenderedAt":4},["ShallowReactive",2],{"post-content-your-pull-requests-are-too-big":3},"\u003Cp>Last year I reviewed a pull request that was 4,107 lines spread across 61 files. The author had been building for three weeks, and somewhere in the middle he'd rewritten most of the data layer because \"it made sense at the time.\" I spent an evening reading it, found one real bug, left 14 comments, and approved it anyway — because the only alternative was telling the whole team to stop and untangling a branch that had already gone stale twice.\u003C\u002Fp>\n\n\u003Cp>The bug shipped to production. Most of those 14 comments were never addressed, because by the time the PR finally merged, nobody could remember what they referred to.\u003C\u002Fp>\n\n\u003Cp>That PR didn't fail because of lazy reviewers. It failed structurally: no human can meaningfully review 4,000 lines of unfamiliar code in one sitting. This week the \"unreviewable mega-PR\" discussion blew up on dev.to again, and I keep seeing the same take — \"review harder, leave more comments.\" That's not the fix. The fix is making the PR small enough that review actually works.\u003C\u002Fp>\n\n\u003Ch2>Big Diffs Don't Get Reviewed, They Get Skimmed\u003C\u002Fh2>\n\n\u003Cp>Classic code inspection research pegs the effective review rate at a few hundred lines per hour. Beyond that, defect detection falls off a cliff. My own experience matches: reviews of 100–300 line PRs talk about logic and trade-offs. Reviews of 2,000-line PRs are mostly \"LGTM\" plus a couple of style nits at the top of the file list.\u003C\u002Fp>\n\n\u003Cp>It's not that reviewers are lazy. It's that a diff is a story, and nobody can hold a 61-chapter story in their head at once. By the time you're at file 40, you've forgotten what file 3 did. The interactions between files — the bugs that actually bite in production — become invisible.\u003C\u002Fp>\n\n\u003Cp>\u003Cstrong>A 400-line PR gets a different kind of review than a 4,000-line PR. Same reviewers, same codebase, completely different outcomes.\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Ch3>The merge noise problem\u003C\u002Fh3>\n\n\u003Cp>There's a compounding effect I didn't appreciate until I lived it: the longer a branch lives, the more merge churn it collects. The diff a reviewer sees isn't just your work — it's your work tangled with everyone else's. Once that happens, reviewers can't tell your logic from the merge noise, so they trust more and verify less.\u003C\u002Fp>\n\n\u003Cp>That's how a busy month becomes a series of PRs where every reviewer approves things they barely understood, and the bug you find in production three weeks later traces back to \"that giant PR from March.\"\u003C\u002Fp>\n\n\u003Ch2>Why PRs Get Huge (It's Rarely Laziness)\u003C\u002Fh2>\n\n\u003Cp>Nobody wakes up planning a 4,000-line PR. They happen through accumulation:\u003C\u002Fp>\n\n\u003Col>\n\u003Cli>\u003Cstrong>Refactors smuggled into features.\u003C\u002Fstrong> You're adding a settings page and you rename half the models on the way. Now the reviewer can't tell which changes are behavior and which are just renames.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Copy-pasted code.\u003C\u002Fstrong> The same 20-line helper pasted into seven files turns a one-line fix into a seven-file PR. I'm guilty of this one constantly.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Long-lived branches.\u003C\u002Fstrong> Two weeks of divergence means the merge itself is a maze. Splitting the work cleanly stops being possible once it's already tangled.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Dependency chains.\u003C\u002Fstrong> PR 3 depends on PR 2 which depends on PR 1, so they all get bundled into one giant review instead of landing one at a time.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>No ceiling.\u003C\u002Fstrong> Nobody ever said \"this is too big,\" so it grew until it was done.\u003C\u002Fli>\n\u003C\u002Fol>\n\n\u003Cp>Every one of these has a mechanical fix, and none of them require heroics.\u003C\u002Fp>\n\n\u003Ch2>The Size Limits That Actually Hold Up\u003C\u002Fh2>\n\n\u003Cp>Every team has its own comfort zone, but after a decade of doing this I've seen the same numbers work everywhere:\u003C\u002Fp>\n\n\u003Cul>\n\u003Cli>\u003Cstrong>Under 200 lines added:\u003C\u002Fstrong> ideal. Review it in minutes, catch everything.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>200–400 lines:\u003C\u002Fstrong> normal. Deserves a real review, takes about 15–20 minutes.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Over 400 lines:\u003C\u002Fstrong> review quality drops fast. Split it, or accept a shallow review.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Over 1,000 lines:\u003C\u002Fstrong> nobody is reviewing this. It's getting merged on vibes.\u003C\u002Fli>\n\u003C\u002Ful>\n\n\u003Cp>Pair that with a naming rule: \u003Cstrong>one PR = one thing you can describe in a single sentence.\u003C\u002Fstrong> \"Adds a password reset flow\" is a PR. \"Adds a password reset flow and migrates the auth module to the new session store\" is two PRs wearing a trench coat.\u003C\u002Fp>\n\n\u003Cp>Don't just agree with this — enforce it. A size check in CI is ten lines and saves everyone the argument:\u003C\u002Fp>\n\n\u003Cpre>\u003Ccode class=\"language-yaml\"># .github\u002Fworkflows\u002Fpr-size.yml\non:\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  check-size:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          fetch-depth: 0\n      - name: Count added lines\n        run: |\n          added=$(git diff --numstat HEAD^ HEAD | awk '{s+=$1} END {print s+0}')\n          echo \"Added lines: $added\"\n          if [ \"$added\" -gt 400 ]; then\n            echo \"This PR adds $added lines. Split it into smaller PRs.\"\n            exit 1\n          fi\n\u003C\u002Fcode>\u003C\u002Fpre>\n\n\u003Cp>When that check fails, the author splits the PR \u003Cem>before\u003C\u002Fem> the review starts — not after 14 comments have already been left on a diff that's about to change anyway.\u003C\u002Fp>\n\n\u003Ch2>How to Split a Mega-PR Without Losing Your Mind\u003C\u002Fh2>\n\n\u003Ch3>Cut vertical slices, not layers\u003C\u002Fh3>\n\n\u003Cp>\"Backend PR first, frontend PR second\" doesn't work, because the backend half usually isn't shippable on its own — and a PR that can't ship is a PR that can't be properly reviewed. Instead, cut by user-visible behavior. A checkout flow becomes: (1) schema and API, (2) the payment UI, (3) edge cases and error handling. Each piece lands, each is reviewable, each is shippable.\u003C\u002Fp>\n\n\u003Ch3>Stack your PRs\u003C\u002Fh3>\n\n\u003Cp>Stacked PRs are the single biggest unlock for teams that build big features. PR A is the foundation, PR B builds on top of it, PR C on top of that. Each diff stays under 300 lines, and you merge in order. Tools like \u003Ccode>gh stack\u003C\u002Fcode> make the bookkeeping painless, but even without tooling the discipline works: merge the foundation first, rebase the next branch, repeat.\u003C\u002Fp>\n\n\u003Ch3>Ship refactors as their own PR\u003C\u002Fh3>\n\n\u003Cp>A pure rename PR is reviewable in five minutes. Mixed into a feature PR, it becomes noise that buries the actual logic. Same for formatting changes and dependency bumps. \"No behavior change\" is the most powerful sentence in code review — it lets the reviewer skim confidently and move on.\u003C\u002Fp>\n\n\u003Ch3>Let CI be the first reviewer\u003C\u002Fh3>\n\n\u003Cp>Type checks, lint, tests — if those run before a human ever looks, the human spends their attention on logic instead of typos. This sounds obvious, but I've watched teams skip it and then wonder why reviews take three days. Fast CI feedback also makes small PRs feel safe, which is the whole point: the quicker the loop, the smaller the steps people take.\u003C\u002Fp>\n\n\u003Ch2>What This Looks Like in Practice\u003C\u002Fh2>\n\n\u003Cp>Compare the three-week mega-PR to the stacked version of the same feature: five PRs of 150–300 lines each, merged over five days. The mega-PR merged in week three with one shipped bug and a pile of dead comments. The stacked version merged in about a week and a half, and every review comment was actually addressed — because the reviewers understood what they were reading.\u003C\u002Fp>\n\n\u003Cp>The numbers I've seen on my own projects and with teams I've worked with: review turnaround drops from days to hours, and the \"I don't remember what this does\" comments disappear. Nobody misses the mega-PRs. Not once.\u003C\u002Fp>\n\n\u003Ch2>Stop Copy-Pasting Your Way Into Bigger Diffs\u003C\u002Fh2>\n\n\u003Cp>Here's the sneaky one, because it compounds over months: a 20-line date formatter pasted into seven files means every future change to that logic touches seven files. A 50-line feature becomes a 400-line PR just because the codebase has no single home for the thing it needs.\u003C\u002Fp>\n\n\u003Cp>The fix is boring and effective: keep reviewed utilities in one place and import them. I built \u003Ca href=\"\u002Fsnippetark\u002F\">Snippet Ark\u003C\u002Fa> for exactly this — a local-first snippet library where a helper lives once, gets reviewed once, and every new PR is a one-line import instead of another paste. Your diff size is a direct symptom of how much duplicated code you're carrying.\u003C\u002Fp>\n\n\u003Ch2>AI Reviewers Won't Save You\u003C\u002Fh2>\n\n\u003Cp>One more thing, because it comes up every time this topic trends: if you're running AI over a 4,000-line PR, you're not fixing the problem — you're automating the skim. I've written before about \u003Ca href=\"\u002Fposts\u002Fai-code-review-system-that-actually-works\u002F\">building an AI code review system that actually works\u003C\u002Fa>, and the single biggest factor was the same as for human review: small diffs. AI review shines when it's pointed at a focused change with clear intent. Point it at a 61-file mess and it will politely summarize the mess.\u003C\u002Fp>\n\n\u003Ch2>Your Next PR\u003C\u002Fh2>\n\n\u003Cp>Here's the rule I use now: \u003Cstrong>if you can't describe the PR in one sentence, it's two PRs. If it's over 400 lines, it's three.\u003C\u002Fstrong>\u003C\u002Fp>\n\n\u003Cp>What's the biggest PR you've ever reviewed — and did the bug that shipped later come from it? I'd genuinely like to know. And next time you're about to open a monster, split it first. Your reviewers will thank you, and so will the codebase in six months.\u003C\u002Fp>\n",1789366677349]