Engineering Collaboration Practices
Code Review As A Skill
Code review is the practice of a second person reading a change before it merges. Done well, it catches defects, improves design while it is still cheap to change, and spreads knowledge of the codebase across the team. Done badly, it is a bottleneck that adds days of latency and teaches people to send code to whichever reviewer rubber-stamps fastest. The difference is skill, on both sides of the review.
What Review Is For
Review exists to answer three questions: is this change correct, will the next person be able to maintain it, and does it teach or violate the conventions of this codebase. Review is not for style enforcement — indentation, import order, and naming format are the job of PHP-CS-Fixer, PHP_CodeSniffer, and PHPStan in the pipeline. Every minute a human spends writing "missing space after comma" is a minute not spent noticing the missing authorization check. Automate everything a machine can check, and spend human attention where judgment is required.
The Author's Half Of The Skill
Most review quality is determined before the reviewer arrives.
- Keep changes small. A 200-line pull request gets real scrutiny; a 2,000-line one gets a sigh and an approval. If the work is big, stack it into reviewable steps.
- Write the description for a reader with no context: what changes, why now, how it was verified, and anything you already know is questionable.
- Review your own diff first. Finding your leftover debug statement before the reviewer does is a courtesy; making them find it is a tax.
- Answer comments with either a change or a reason, and say which. Silence and unexplained "done" both erode trust.
The Reviewer's Half Of The Skill
- Respond quickly, even if only to say when you will review. Latency, not thoroughness, is what makes teams hate review.
- Read the tests first: they say what the author believes the change does. Then read the change and look for what the tests do not cover — the error path, the concurrent request, the malicious input.
- Distinguish severity explicitly. A blocking defect, a suggestion, and a personal preference should not arrive in the same tone. Many teams prefix minor points with "nit:" and approve despite them.
- Ask questions instead of issuing commands where genuine: "what happens if this header is missing?" both reviews the code and teaches, in whichever direction the answer flows.
- Review the change that exists, not the rewrite you would have done. If the design is wrong enough to redo, that conversation is better had synchronously — or the work re-done as a pair — than through forty comments.
Review As A System
A team's review practice is healthy when changes merge within a day, when review comments regularly catch real problems, and when juniors review seniors as a matter of course — reviewing unfamiliar strong code is one of the fastest ways to learn, and the questions juniors ask expose the assumptions the code should not be making. Pair-written code, covered in the Pair Programming lesson, was reviewed while being written, and many teams merge it without a separate pass.
Track your own review comments for a month and most fall into a few classes: missing error handling, missing tests, unclear naming, and boundary conditions. That distribution is worth knowing — it says what your pipeline should start checking automatically, and what your team should discuss once instead of relitigating in every pull request.
What To Check
Before moving on, make sure you can:
- state the three questions review exists to answer
- explain why style belongs to tooling and not to reviewers
- list the author-side habits that make a change reviewable
- list the reviewer-side habits that make review fast, useful, and humane
- explain when to abandon written review for a synchronous conversation or a pairing session
What You Should Be Able To Do
After this lesson, you should be able to submit a change that is easy to review well, review someone else's change with severity-labeled comments a colleague would thank you for, and recognize when a review has outgrown the comment thread.
Practice
Practice: Design A Team Review Standard
Show solution
Automation first: PHP-CS-Fixer and PHPStan run in the pipeline and block merges. Style and detectable defects are no longer review topics; any review comment a linter could have made is a bug in the pipeline config, not feedback for the author.
Size: pull requests target under ~300 changed lines. Larger work is stacked into reviewable steps, and a reviewer may bounce an oversized PR with "please split" as a complete review.
Latency: first response within four working hours, even if only "reviewing tomorrow morning." Review is the top of the priority list after production issues, because unreviewed work blocks a colleague.
Comment convention: blocking comments state why the change cannot merge; everything else is prefixed "nit:" and never blocks. Approve-with-nits is the default for healthy changes. Questions are genuine questions, and three unanswered rounds on a thread means switching to a call or a pairing session.
Author's side: description says what, why, and how it was verified; the author reviews their own diff before requesting review; every reviewer comment gets a change or a stated reason.
Revisit the standard after a month against evidence: merge latency, and whether review comments are catching real problems.
Practice: Diagnose A Review That Failed
Task
Explain the failure at the level of the review system, not the reviewer, and prescribe changes that would have caught it.
Show solution
Blaming the reviewer misses the system that made careful review impossible. Nobody scrutinizes 1,900 lines; past a few hundred, humans switch from reading code to skimming shapes, and approval becomes a social act. The forty-minute "LGTM" is the predictable output of an oversized input.
Systemic fixes, in order of leverage:
- Size discipline. Had the change arrived as six stacked pull requests, the controller with the missing check would have been a reviewable 150-line diff where its absent authorization stood out.
- Read tests first. The missing check implies a missing test — no test asserts a 403 for the unauthorized case. A reviewer whose habit is "find the negative-path tests before reading code" catches the gap without reading every line.
- Automate the class of defect. An authorization check on every controller action is a convention a tool can enforce — a PHPStan rule or a test iterating routes and asserting unauthenticated requests fail. The strongest response to an incident is making its whole class unreviewable-by-humans because a machine now catches it.
- Make rubber-stamping visible. Track approvals under N minutes on PRs over N lines; the pattern, not the person, is the target.
"Review more carefully" is not on the list, because it is not a mechanism.
Practice: Write Your Reviewer Checklist
Write the personal checklist you would run when reviewing a typical PHP web-application pull request, ordered by what you check first, with a one-line reason per item.
Show solution
Then write comments with severity marked, approve with nits when nothing blocks, and say when a re-review would beat another written round.