The exact same technical concern — "this could cause a null pointer error" — gets received completely differently depending on three or four words of phrasing. Code review is a communication skill as much as a technical one.
Lead with the question, not the verdict
Less effective: "This is wrong, it'll break if data is empty."
More effective: "What happens here if `data` is empty — does the
.map() below throw, or does it just render nothing?"
The second version invites a conversation and gives the author a chance to explain something you might be missing (maybe data is guaranteed non-empty upstream) — while still surfacing the exact same concern. If the concern is valid, this gets to the same fix; if you're missing context, you find out without an unnecessary back-and-forth.
Distinguish "must fix" from "worth considering"
Unlabeled comments force the author to guess how seriously to take each one — a blocking bug and a stylistic preference read identically in plain text:
🔴 Blocking: This SQL query concatenates user input directly — SQL injection risk.
💭 Non-blocking: Consider extracting this into a named function — just a suggestion.
Some form of severity signal (emoji, a prefix like "nit:", a team convention) turns a flat list of comments into something the author can triage quickly — fix the blocking ones first, consider the rest at their own discretion.
Explain the "why," not just the "what"
Less effective: "Use a Set here instead of an array."
More effective: "Using a Set here avoids an O(n) .includes() check inside
this loop — with an array this becomes O(n²) as the list grows."
A comment that only states the desired change teaches nothing and can read as arbitrary preference. A comment that explains the reasoning helps the author actually learn the underlying principle, and makes it much easier for them to apply the same reasoning themselves next time, without needing the same comment repeated on a future PR.
Praise specific things, not just generic positivity
Less effective: "Looks good!"
More effective: "Nice catch handling the race condition here with the
AbortController — that's an easy thing to miss."
Specific praise reinforces exactly the behavior worth repeating, and it's genuinely rare enough in most review cultures that it stands out and is remembered — generic positivity is pleasant but doesn't actually teach or reinforce anything specific.
Batch related comments instead of a comment per line
Ten separate one-line comments on the same underlying issue, scattered across a diff, reads as more overwhelming (and more nitpicky) than one comment addressing the pattern once:
Less effective: 8 separate "add a null check here" comments across 8 similar lines.
More effective: One comment: "Several of these functions (lines 12, 34, 56, 78...)
assume the input is never null — worth a shared guard, or should the type
itself reflect that null isn't actually possible here?"
The second version also surfaces a genuinely better fix (a shared guard, or a type change) that individual line comments would never suggest — pattern-level feedback often points at pattern-level solutions.
Reviewing your own PR before requesting review
A brief self-review — reading through the diff as if you were the reviewer, before requesting one — regularly catches obvious issues (a leftover console.log, an unintended file included, a comment that no longer applies) that are mildly embarrassing to have a teammate point out and cheap to catch yourself first. This isn't a substitute for real review, but it measurably reduces the number of trivial comments a reviewer has to spend time on, leaving more of their attention for substantive feedback.
Responding to review comments as the author
The same care applies in reverse — acknowledging a comment explicitly (even just "good catch, fixed" or "intentional, here's why") closes the loop for the reviewer, who otherwise has to re-check the diff to see whether their comment was addressed at all. Silently pushing a fix with no response, or resolving a comment thread without any acknowledgment, leaves the reviewer uncertain whether their feedback registered or was dismissed.
Timing matters as much as wording
A large, sprawling PR reviewed all at once, days after it was opened, tends to get shallower feedback than several small PRs reviewed promptly — not because reviewers care less, but because review quality genuinely degrades with diff size and delay. Encouraging smaller, more frequent PRs (and reviewing them promptly rather than letting them queue) is itself a form of effective review practice, even though it's a process choice rather than a comment-wording one.
Asynchronous review across time zones
For distributed teams, a review left open overnight can stall a whole day of progress on the author's side. Writing comments with enough self-contained context that the author can act on them without a live conversation — a specific line reference, the concrete concern, and (where possible) a suggested direction — keeps async review from turning into a multi-day back-and-forth over what should be a same-day fix.
Common mistakes
- Phrasing every comment as an unqualified directive ("change this to X") even for genuinely subjective or context-dependent suggestions — this reads as more authoritative than intended and can shut down a conversation the author might have useful pushback on.
- Leaving purely negative feedback with no acknowledgment of what's working well in the same PR — even strong PRs usually have at least one thing worth specifically calling out, and doing so keeps review from feeling like purely fault-finding.
- Commenting on the same recurring pattern line-by-line instead of once, as a batched, higher-level observation — this is both more overwhelming to receive and misses the more useful pattern-level fix a single comment could suggest.
- Approving a PR with unresolved "must fix" comments still open, relying on the author to remember to address them before merging without a re-review — if it's genuinely blocking, the review status should reflect that.
Related reading
- How to Structure Your Developer Day for Deep Work — shares tags: productivity (same category).
- Git Hooks Explained: Automate Your Workflow — shares tags: productivity.
- Keyboard Shortcuts That Will Save You Hours Every Week — shares tags: productivity.
- Clean Code Principles That Actually Hold Up in Practice — shares tags: programming.
- CI/CD Pipelines Explained: From Commit to Production — shares tags: programming.