About this article
As the fifth installment of the “DevOps Architecture” category in the series “Architecture Crash Course for the Generative-AI Era,” this article explains code review.
Review is the final gate of design agreement, not quality assurance. Confusing it with bug-hunting causes the chain of “PRs pile up / one-line-comment approvals / incidents surface in production.” This article handles PR granularity, review viewpoints (the 3 layers of design/implementation/convention), approval rules, and commit conventions as design that doesn’t break even as the team grows.
Before you read this
This article is mostly about the flow of building, testing, releasing and monitoring a service. If IT vocabulary is unfamiliar, reading the primer "From Development to Operations" first makes it far easier to follow. You can also look anything up in the glossary as you read.
What is code review in the first place
Think of book proofreading and editing. A different set of eyes reads the author’s manuscript, checking not just typos but also logical gaps and clarity for the reader. Just as writing done alone always has blind spots, code written alone always has oversights.
Code review is the process where another engineer checks code written by a team member before merging, detecting design issues and oversights. GitHub’s Pull Request (PR) is the canonical mechanism for this.
Without code review, design misalignment and latent bugs go unnoticed until they surface in production, ballooning rework costs many times over.
Why code review is needed
First, to catch design drift before production. Tests verify “whether the code works correctly”; no machine can judge “whether this was the right design in the first place.” Review is the last gate at which a human checks that a design decision is sound.
Second, for sharing knowledge and preventing dependence on individuals. Review lets the whole team keep hold of the codebase and stops areas only one person will touch from forming. It is the most effective way to lower the bus factor.
Third, through the exchanges in review, the team’s tacit sense of “what good code is” becomes explicit knowledge.
The 3 layers seen in review
Review is often thought of as “bug-hunting,” but the actual targets split into 3 layers. The starting point of design is not mixing things CI can mechanically guarantee with things only review can detect.
| Layer | Content | Who sees it |
|---|---|---|
| Mechanical layer | Syntax, types, coverage, Lint, format | CI (humans don’t see) |
| Code layer | Readability, naming, duplication, separation of concerns, simplicity | Reviewer (main) |
| Design layer | Public-API stability, architecture consistency, extensibility | Senior, owner |
The rule is don’t review things machines handle. Pointing out “Prettier didn’t format” or “spaces unaligned” in review just melts human time - seal that completely with CI and pre-commit. Review focuses only on code layer and design layer - whether you can make this break decides team speed.
PR granularity - smaller is faster
Review time and PR lines are not linear but exponential in degradation. A 300-line PR finishes in 60 minutes, but a 1,000-line PR doesn’t get accuracy even after a full day - empirical, but I’ve never seen exceptions in the field.
| PR lines | Realistic review time | Defect detection rate |
|---|---|---|
| ~100 | 10-20 min | High (almost all detected) |
| 100-300 | 30-60 min | Mid (recommended range) |
| 300-500 | 2 hours-half day | Low (latter half becomes skim-reading) |
| 500+ | Half day-1 day | Extremely low (almost approval ceremony) |
| 1,000+ | Unknown | Almost not seen |
Google internal research also shows that defect-detection rate plummets the moment you exceed 400 lines. Aim for PRs within 300 lines and split - the front-runner operation. Massive PRs also generate the pressure of “I already submitted, just merge it,” and quality, dev experience, and reviewer psychology all worsen.
PRs within 300 lines. If exceeded, always split or get prior design agreement.
Splitting a large pull request is the skill that follows from that.
It’s said “the feature is large so can’t split,” but in 90% of cases, splitting is possible. Below are typical split patterns.
| Split axis | Example |
|---|---|
| Separate structure prep from body | 1) directory structure / type definitions only → 2) implementation body |
| Separate refactor from new feature | 1) tidy existing code → 2) add new feature |
| Split by layer | 1) DB schema + migration → 2) API endpoints → 3) UI |
| Hide with Feature Flag | Pre-merge with flag off → publish with flag on |
| Horizontal split | Same change applied to multiple files → split per file group |
Putting refactor and new feature in the same PR is a particularly bad choice. Reviewers have to judge “is this change essential or incidental?” line by line, ballooning review time 2-3x. Pass refactor as a standalone PR first, layer the new feature on top - if this order breaks, the team’s overall speed drops.
What to see in review - phased practice
“Review viewpoint checklists” tend to formalize in the field. Practical to vary emphasis by the stage the code is in - “declaring at the start of the review which stage your PR is in” alone greatly changes how reviewers read.
| Stage | When this PR is | What to emphasize | Target time |
|---|---|---|---|
| 1. Prototype | Stage of checking whether it works | Design policy only (operation/naming secondary) | 15 min |
| 2. Implementation | The main PR before production | Logic, error handling, tests | 30-60 min |
| 3. Refactor | No functional change | Whether existing behavior is intact | 20 min |
| 4. Emergency hotfix | Incident response | Whether scope is narrow, easy to roll back | 10 min |
Pointing out “naming is long” or “should split functions” on a prototype PR is stage-mismatched, sparking PR author pushback “that’s not the goal this time.” Conversely, retroactively raising design policy on an implementation PR has large rework, so settle design discussions at stage 1.
Here is the reviewer viewpoint list to work from.
Without consciousness, viewpoints to see in review fall into the ritualization of “read, somehow OK.” Below are practical viewpoints with field effectiveness, and don’t see all every time but vary emphasis per PR type - the practical approach.
| Viewpoint | What specifically to see |
|---|---|
| Correctness | Per spec, edge cases, boundary values (0, 1, null, empty array) |
| Tests | Tests present, names that convey intent, how do you notice on failure |
| Readability | Naming, separation of concerns, function length, early return |
| Error handling | Behavior on failure, logs, user-facing appearance |
| Security | Authorization checks, input validation, SQL injection, secret leaks |
| Performance | N+1 queries, cache, useless loops |
| Backward compatibility | Public-API changes, DB schema changes, existing-client impact |
The minimum line is always seeing the 2 axes of “correctness” and “tests”. Readability and performance are pointed out only when there’s a clear problem, and the trick to keeping review-culture health is not stepping into “the realm of preference.”
Approval rules - how many, by whom
Number and attributes of approvers is a design item that looks small but decides organizational speed. Requiring 2-person approval raises quality, but if person 2 is unmoving for 3 days while person 1 instantly approves, PRs are left for 3 days.
| Pattern | Quality | Speed | Suited for |
|---|---|---|---|
| 1-person (anyone) | Marginal | High | Small / trusted teams |
| 1-person (CODEOWNERS specified) | Good | Mid-high | Front-runner (mid-size) |
| 2-person (1 from CODEOWNERS) | Excellent | Mid | Finance/medical/regulated |
| 2-person (anyone) | Good | Low | Discouraged (bottlenecks invisible) |
CODEOWNERS (the GitHub feature defining responsibles for specific dirs/files in .github/CODEOWNERS) lets you mechanically enforce “this directory always requires this person’s approval.” Today, 1-person approval + CODEOWNERS required for important areas is the front-runner composition for mid-size teams. 2-person approval looks safe but actually accumulates “review delays as person x person” - excessive design outside regulated industries.
Commit conventions and merge strategy — making history automatable
Conventional Commits is the convention of prefixing commit messages with feat: / fix: / refactor: etc. Spread around 2017, today it’s the de facto standard regardless of OSS or SaaS.
| prefix | Meaning |
|---|---|
feat | New feature |
fix | Bug fix |
refactor | Code cleanup without functional change |
perf | Performance improvement |
docs | Documentation only |
test | Tests only |
chore | Build, CI, dependency updates etc. |
Typical format is feat(auth): add passkey login flow, of the shape prefix(scope): summary. Putting the BREAKING CHANGE: note in the body becomes the breaking-change flag.
The benefits of Conventional Commits follow from that.
Adopting Conventional Commits enables release-note auto-generation (semantic-release, release-please) and SemVer auto-decision (fix→patch, feat→minor, BREAKING→major). The side effect “history transforms into a searchable spec” is also strong, and AI’s understanding accuracy when reading change history rises significantly.
| Benefit | Content |
|---|---|
| Release-note auto-generation | Pick up feat/fix to mechanically generate CHANGELOG.md |
| SemVer auto-decision | feat → minor / fix → patch / BREAKING → major |
| PR filtering | Extract only new features with git log --grep='^feat' |
| AI understanding accuracy | Structured history makes AI grasp intent easier |
Build semantic-release into CI and auto-tagging and release complete on main merge. Adoption cost is just the first week’s adjustment, after which only benefits remain - the investment.
Squash merge versus preserving history is the other half.
PR merge methods are 3 - Squash / Rebase / Merge commit - but Squash is the modern front-runner. With 100 fine WIP commits (wip, fix typo, revert, wip2) born on feature branches remaining in main, git blame becomes effectively meaningless.
| Method | Characteristics | Recommended case |
|---|---|---|
| Squash | Compress all feature commits into one to main | Front-runner (90% of teams) |
| Rebase | Linear merge preserving feature commit structure | OSS that wants to retain history |
| Merge commit | Leave feature branch and merge point in history | Combination with Git Flow |
In Squash-merge operations, the PR title becomes the commit message as is, so the rule is putting the Conventional Commits prefix in the PR title. PR title feat(auth): add passkey login → same title for the commit on main - this structure has “best chemistry” with release-note auto-generation.
Review SLA - decide response time numerically
Review delays directly kill organizational speed. The lax operation “look when noticed” has the double evil of when PRs are left for 2 days, the writer’s context disappears, dropping review quality too.
| SLA | Response time | Scope |
|---|---|---|
| First review response | Within 4 hours (business hours) | All PRs |
| Review completion | Within 24 hours | Normal PRs |
| Emergency hotfix | Within 1 hour | PRs with urgent label |
| Re-review | Same day | Re-submission after addressing comments |
Just clarifying the SLA dramatically resolves the no-one-reviews problem. As support, putting in auto-notifications to Slack/Teams (GitHub’s Pull Request Reviewer feature, pull-reminders bot) and automating “remind after 4 hours” / “re-notify at 24 hours” is the modern rule. Don’t rely on memory for waiting on human reviews - this is an area easy to mechanize and with high organizational-improvement leverage.
Review by AI is where this is heading in practice.
From 2025, AI review has rapidly entered the practical zone. GitHub Copilot Code Review, CodeRabbit, Codium, Graphite Reviewer etc. can now auto-comment on PRs. Today, while “not a replacement for human reviewers,” the field feel is crushing 50-70% of points in the first pass.
| Areas where AI review is strong | Areas where AI review is weak |
|---|---|
| Simple bugs, null references, unused variables | Domain-specific business logic |
| Naming, code conventions, doc gaps | Architecture-consistency / extensibility judgment |
| Standard security patterns | Consistency with past discussions / design agreements |
| Test gaps, missed boundary values | ”Is this change even necessary?” |
The ideal operation is the division of labor of AI returning all mechanical points first → humans seeing only design and domain logic. Not “AI reviewed so humans unneeded” but “AI does pre-processing so humans can focus on design” - the modern standard composition.
Three scenarios
If you are building solo or at a startup
One approver, with a formatter and linter doing the mechanical work, is enough. What matters more than the number of reviewers is keeping the change small: a pull request under 400 lines gets read properly. Solo, reviewing your own diff the next morning catches a surprising amount.
If you are a small or mid-size SaaS
CODEOWNERS with one approver, a stated service level on response time, and everything mechanical automated. Fix the first response at four hours and completion at 24, with automatic reminders. This is also the stage to bring AI review into CI for the first pass, so humans spend their attention on design.
If you are a large or regulated enterprise
Two approvers, CODEOWNERS by domain, and an audit trail linking every merge to its approvals. Requiring two approvals genuinely slows a team down, so pair it with a large enough reviewer pool that nobody becomes the bottleneck, and keep the blocking criteria to “does it break or not.”
AI decision axes — AI does the prep work; humans concentrate on design
Division of labor between AI review and human review
AI code review (CodeRabbit, GitHub Copilot, etc.) matches or exceeds human accuracy at detecting naming-convention violations, unused variables, type inconsistencies, and security patterns. On the other hand, correctness of domain logic, soundness of design decisions, and impact on user experience are beyond AI’s judgment.
The realistic setup is “AI auto-reviews every PR -> fixes flagged items -> humans focus on design, domain, and UX.” As a mechanism for concentrating human review time on high-value judgment, AI review has a strong ROI.
PR size determines AI review accuracy
AI review accuracy depends heavily on PR size. At 300 lines or fewer, AI grasps the full picture and leaves accurate comments. Past 1,000 lines, either the context window runs out or attention scatters, and the probability of missing important issues rises.
In other words, a PR-splitting culture is a prerequisite for maximizing the returns from AI review.
Pitfalls and forbidden moves
Review does not work on machinery alone. Here are the six that spread the moment the review culture breaks down.
| Forbidden move | Why it is bad → what to do instead |
|---|---|
| A culture of instant LGTM | it breeds the accident of waving through “I did not read it” as an LGTM → always look at correctness and tests, both axes |
| Reviews that attack the person | psychological safety collapses and it leads to resignations → criticise the code, not the person |
| Arguments about style that blow up the discussion | debating tabs and spaces on every pull request exhausts everyone → mechanise it completely with Prettier or Biome |
| Demanding changes down to personal preference | the pull request sits for a week and the context rots → restrict blocking to whether it breaks or not |
| No service level on review response | a pull request raised on Friday sits until Monday → state four hours to first response and 24 hours to completion, with automatic reminders |
| Refactoring and a new feature in the same pull request | the review time swells two- or threefold → land the refactor first, in its own pull request |
Author’s note - “2-person approval mandatory” that killed a startup’s speed
A widely-told case in the industry: a startup adopted “all PRs require 2-person approval,” and at the point members exceeded 10, average merge time exceeded 2 days. When the second reviewer is busy with other work, things stop even if the first has approved. Result: PRs pile up, conflicts increase, rebase hell begins.
This team switched to “1-person approval + CODEOWNERS, only critical directories (payments, auth) require 2-person” - average merge time shortened to half a day. “2-person approval for quality” is the front-runner in regulated industries and core areas of payment systems, but uniform application is a killer of organizational speed. Identifying areas you want to protect quality and laying heavy gear only there - the modern design thinking.
“All PRs 2-person approval” is the slowest design that looks safe.
What to decide - what is your project’s answer?
For each of the following, try to articulate your project’s answer in 1-2 sentences. Starting work with these vague always invites later questions like “why did we decide this again?”
- PR-granularity target (within 300 lines recommended)
- Approval rules (1-person/2-person, presence of CODEOWNERS)
- Review SLA (first response time, completion time)
- Commit convention (whether to adopt Conventional Commits)
- Merge method (Squash / Rebase / Merge commit)
- Review-viewpoint priorities (line of mechanization)
- AI-review tool adoption (CodeRabbit, GitHub Copilot Code Review etc.)
- Style-debate suppression (full mechanization with Prettier/Biome)
Related Articles
Summary
This article covered code review, including PR granularity, viewpoints, approval rules, Conventional Commits, Squash merge, and AI-review pre-processing.
Keep PRs within 300 lines, consolidate design judgment via 1-person approval + CODEOWNERS, automate history via Squash + Conventional Commits, AI-review pre-processing. That is the practical answer for code review in 2026.
Next time we’ll cover test design (test pyramid, contract tests, E2E).
Back to series TOC -> ‘Architecture Crash Course for the Generative-AI Era’: How to Read This Book
I hope you’ll read the next article as well.
Also popular with readers
📚 Series: Architecture Crash Course for the Generative-AI Era (64/95)