Healthy Code Reviews

7 min read Original article ↗

I landed my first freelance gig sometime around 2009, building a sentiment dashboard for a marketing agency. Twitter was still called Twitter, the API limits felt roomy, and I was wrestling with Django 1.2 on a five-year-old MacBook. Our team of seven wore the same badge of honour: “We’re agile, we move fast, we break things.” Code reviews? Those sounded like corporate paperwork for people in beige cubicles, so we skipped them (and congratulated ourselves on the time saved).

Eight months later the repository looked like Minesweeper on expert mode. Duplicate logic everywhere, four different JSON parsers doing the same job, and a grab-bag of code styles that made git blame feel like archaeology. Bugs were an issue, sure, but the bigger problem was nobody understood anyone else’s code well enough to fix them without breaking something else.

That mess finally convinced us that maybe, just maybe, the “boring” practice we’d ignored could save us. Code reviews, it turned out, are less about bureaucracy and more about making tomorrow’s changes cheaper. I wish I’d realised that before pulling three all-nighters cleaning up my own spaghetti.

If you’re skipping reviews today, you’re basically mortgaging your future. The house probably won’t collapse this sprint, but one Friday at 17:00 you’ll push a hotfix and discover the foundation is sand. In a startup, there isn’t always budget for a second foundation.

There’s real data behind this — I recall reading somewhere that teams with systematic reviews caught significantly more defects pre-merge. I’m sure the exact ratio varies, but the direction is clear. Plenty of articles dissect the “how,” yet every team still ends up with its own flavour. So here’s mine. Steal the pieces that resonate, ignore the rest.

Quick note before we dive in: managers will occasionally trade review time for “just ship it” speed. I get it — features win deals. Still, I’ve never seen that gamble pay off past the first quarter. Your mileage may vary.

From a day-to-day engineering perspective, reviews matter because:

  1. A fresh set of eyes resets your overconfidence. I don’t care how senior you are — you’re blind to your own typos after hour three. One reviewer is usually enough; two is luxury. (Anything beyond that starts to feel like committee theatre.)
  2. The reviewer is a proxy for Future-You. If they need a diagram to understand the flow, tomorrow’s on-call engineer definitely will. Rewrite until comprehension happens at first glance.
  3. Humans miss guidelines. Linters catch commas; peers catch the subtle race condition that unit tests forgot. Combining mandatory reviews with automated gates keeps egos out of it — the CI bot rejects style issues so humans can focus on logic.

Now, about the human side of authoring a PR.

First trap: personal attachment. Treat code like a Google Doc, not a diary. In six months you’ll barely remember writing it, so don’t link your self-worth to a variable name. (I still catch myself doing this, but less than I used to.)

Second trap: “us vs. them.” Reviewers aren’t gatekeepers delaying your feature; they’re co-owners protecting both of you from 03:00 pager duty. Over-strict reviewers can stall progress, though, so keep an eye on impact: is this nit worth blocking deployment?

Before the review

Two things to sort out before the first PR ever appears:

  1. Definition of Done
  2. Coding Standards

Definition of Done
Get painfully specific here. “Code compiles” is not done. My rule of thumb: written, tested, documented, deployable without emergency coffee. Anything fuzzier turns into perpetual half-finished tasks (I’ve tripped on that rake more than once).

Coding Standards
Years ago I spent an afternoon with the team writing a one-page style doc. Everyone signed it, literally — Sharpies on printer paper. The next month’s reviews were calmer because any stylistic bikeshedding pointed back to that page rather than personal taste. If a standard isn’t written down, it doesn’t exist.

Automate everything that can be automated. A pre-commit linter plus CI style checks means reviewers talk about semantics, not spacing. It also removes the “you” from the conversation; the robot failed the build, not Karen.

Nail these basics and reviews stop feeling like trial by fire.

Standardizing everything

With foundations set, move to checklists and tooling.

Start with a clear checklist. The GitHub repo by Michael Greiler is a good template. You’ll cover behaviour, readability, security, and “are we reinventing the wheel?” questions.

From the github repo above
Pre-commit hooks helps maintain quality before hitting the repository.

And yes, you need the checklist. Airline pilots use them. Surgeons use them. I’ll happily imitate professionals who literally hold lives in their hands.

Next up: linters, static analysis, vulnerability scanners. I run a couple of Python pre-commit hooks, type-checking in CI, and auto-formatting inside my IDE. If I miss something, at least three automated voices tell me so (sometimes simultaneously, which is humbling).

Common things to look out for

Here’s the mental checklist I use while reviewing. Cherry-pick as needed.

PR size. Anything that takes more than an hour to review should probably be split. Brain fatigue is real.

Guard clauses. I prefer early exits over Russian-doll nesting. Some swear by a single return — that’s fine, agree on one approach and document it.

Guard Clauses. Source

Dead code. Delete it. Version control remembers.

Naming. “data” vs. “sumEmployees” — self-explanatory, right? Make the reader’s job easy.

Over-engineering. Were you asked for a toaster and delivered a toaster factory? Ask why. Sometimes the answer is “future roadmap,” sometimes it’s “I got carried away after coffee.”

Wheel-reinvention. Big codebases hide utilities nobody remembers. A quick search avoids two modules doing 90% the same thing.

Unplanned refactors. If a PR both adds a feature and rewrites half the persistence layer, I’ll request a split. Saves merge-conflict heartache later.

Comments. Code should say what; comments explain why. Future-me appreciates the context.

New dependencies. Licences, security, long-term maintenance — tread carefully. I usually ask a few questions before approving.

Endpoints. Data filtering, auth, idempotency. The usual suspects. A missed header check today becomes a CVE write-up tomorrow.

Plenty more could be added. Experience will tune the list. Checklists help until muscle memory forms — then keep the checklist anyway as back-up.

Great, you found issues, how to communicate

Avoid turning feedback into demotivation. I’ve seen brilliant engineers sulk for a week after a harsh review. That’s pure waste.

I lean on the principles of Non-Violent Code Review:

  • Everyone’s code can improve.
  • Critique the code, not the coder.
  • Keep emotions out of the pull request.
  • Phrase comments as invitations, not commands.
Great example of what not to do. Source Toxic Code Reviews

When something irks you, double-check whether it’s style preference or an actual flaw. If it’s the former, ask instead of dictating. Pragmatism beats theoretical purity.

❌ Bad: “You are writing code that I can’t understand.”
❌ Bad: “Your code is so bad/unclear/ ”
✅ Good: “I’m having a hard time understanding the code.”
✅ Good: “I have a feeling the code lacks clarity in this module.”
✅ Good: “I’m struggling to understand the complexity, how can we make it more clear?”

Small wording tweaks lower the emotional temperature and open dialogue.

Remember: nobody boots their IDE thinking, “Let’s write unmaintainable nonsense today.” Assume positive intent and say thanks when things look great.

Code Reviews FAQ

Rapid-fire answers to questions I hear most often:

  1. What if reviews slow us down?

If you skip them today, you’ll make up the “lost” time debugging next quarter. If your queue is still clogged, shorten checklists or automate more style checks.

  1. Do we review every line?

No. Docs typos and README tweaks can go straight to main. Major logic paths, security-sensitive code, or anything customer-facing gets a full review.

  1. Can automation replace humans?

Linters spot syntax; humans spot intent. You need both.

  1. How about distributed teams?

Asynchronous reviews work fine. Leave comments, move on, circle back. Just agree on SLAs so PRs don’t rot.

  1. Maximum PR size?

Whatever two reviewers can digest in under an hour. If it takes longer, split.

  1. Urgent hotfixes?

Fix first, review right after deploy. No skipping that second step.

Thoughts, war stories, disagreements? Comment section’s open.

Other Newsletter Issues: