Code Review

Async Review vs Pairing on the Same Change

Two engineers open the same pull request. One leaves a comment at 9:40 p.m. from a kitchen table, three sentences and a suggestion. The other gets on a call the next morning, shares a screen, and talks through the change for forty minutes. Both reviews happen. Both reviewers are competent. The differences between what those two sessions produce, and what they cost, are large enough that most teams pick one and quietly pretend the other does not exist.

The pull request is the unit of work that made this question unavoidable. A change sits in a branch, waiting. Someone has to look at it. The team can route it through a written comment thread that unfolds over hours, or it can put two people in front of the same diff at the same time. These are not two flavors of the same activity. They are different instruments, and they fail in different ways.

What async review actually produces

An async review leaves a record. That is its first and most underrated property. Every concern, every suggested rename, every "this branch can be simpler" sits in a thread with a timestamp and a name attached. Six weeks later, when someone asks why the retry logic looks the way it does, the thread is still there. The reasoning survived the people who had it.

The record also has a cost. Written comments tend to be more clipped than spoken ones. A reviewer typing at the end of a long day writes "this looks wrong" and moves on, and the author reads it as a verdict rather than a question. Tone is the tax on written review, and it is paid in small misunderstandings that cost more time to unwind than the original comment saved.

Async review also scales in a way pairing cannot. One senior engineer can leave thoughtful notes on six changes in a morning. The same engineer cannot pair on six changes in a morning. For a team with a wide surface area and a thin layer of experienced reviewers, the written thread is the only mechanism that keeps the queue moving.

What async review struggles with is the class of problem that is hard to name in a comment. The design that is technically correct but wrong for this codebase. The abstraction that will not survive the next feature. A reviewer can sense the discomfort and still fail to articulate it in three sentences, and so the comment gets softened into "looks fine to me" and the change merges.

What pairing does to a diff in real time

Pairing on a change collapses the feedback loop to seconds. The author proposes a function, the pair frowns, and the frown is information. That is the whole advantage. The pair does not need to compose a paragraph explaining why the naming feels off; the hesitation itself is the message, and the author adjusts before the thought is even fully formed.

This matters most for changes that are still soft, where the shape is not settled. A refactor in progress, a new module with no precedent, a tricky migration. In those sessions the review and the writing blur together, and the result is often a smaller, cleaner diff than the author would have produced alone. The pair catches the wrong turn while the car is still moving slowly enough to correct.

Pairing also transfers knowledge in a direction the written thread cannot. The author learns how the reviewer thinks, not just what the reviewer concluded. Watching someone trace a bug through four files teaches more about debugging than any comment that says "consider extracting this."

The costs are real and they are not small. Pairing consumes two calendars at once. It requires both people to be present, focused, and reasonably rested, which rules out the late evening and the fragmented afternoon. A forty-minute session for a change that would have taken six minutes to review in writing is a poor trade on a trivial diff. And pairing leaves almost no record. The conversation evaporates when the call ends.

The six-minute change and the six-hour change

Change size is the first fork in the road, and it is sharper than most teams treat it. A dependency bump, a config tweak, a one-line fix to an off-by-one error: these belong in async review, full stop. Pairing on them wastes a second person's attention and adds ceremony to a decision that needs none. The written thread is faster, and the record is worth more than the conversation would be.

The larger the change, the more pairing earns its cost. A diff that touches forty files and introduces a new pattern has too many moving parts to review well in a comment thread. The reviewer scrolls, loses the thread, and leaves a handful of surface notes. A pair working through the same diff can hold the whole shape in view and ask the questions that only make sense against the whole.

There is a middle zone that causes most of the argument. A change of a few hundred lines, a new endpoint, a moderate refactor. Async review works if the reviewer is sharp and the author wrote a clear description. Pairing works better if the design is still contested. The honest answer is that the middle zone depends on the people and the stakes, and teams that pretend there is a universal rule are usually rationalizing whatever they already do.

Where written threads quietly break down

Async review has a failure mode that gets blamed on individuals when it is really structural. A comment sits unanswered for a day. The author moves on to other work. By the time the reply arrives, the author has lost the context and answers curtly. The reviewer reads the curtness as hostility. The thread stalls, and the change merges with the concern unresolved.

This is not a personality problem. It is what happens when a conversation is stretched across time and interleaved with everything else each person is doing. The written thread assumes both parties return to it with the same context they left it with. They rarely do.

Pairing avoids this by keeping the context resident in two heads at once. It introduces its own failure mode, though: the pair gets tired, agrees too easily, and waves through the last twenty lines of a long session. The diff that looked clean at minute thirty looks questionable at minute fifty-five, and nobody has the energy to reopen it.

The social cost of a public comment

A written review is a public act. The comment lives where the whole team can see it, and that changes what people write. Reviewers soften criticism. Authors defend positions they would abandon in a conversation. The thread becomes a small performance, and the technical content gets bent to manage how each person appears.

Pairing is private by default. The pair can say "this is bad" without it becoming a permanent artifact, and the author can concede without losing face. That privacy makes candor cheaper, and candor is where the useful review actually lives. A team that only ever reviews in writing will produce politer comments and slower corrections.

The trade is that the private conversation leaves nothing behind. The decision that emerged from the pairing session has to be written down separately, or it is lost. Teams that pair heavily and document lightly tend to rediscover the same arguments every few months.

Reviewer attention is the scarce resource

Every review method spends the same currency: the focused attention of an experienced engineer. The question worth asking is which method spends it best on a given change. Async review spends attention in short bursts across many changes. Pairing spends it in one long block on one change. Neither is more efficient in the abstract; they are efficient for different shapes of work.

A team with four senior engineers and forty changes a week cannot pair on everything. It would exhaust the seniors and leave the queue untouched. That team needs async review as its default and pairing as a deliberate exception for the changes that matter most. A team of two working on a single critical system can pair on nearly everything and lose little, because the coordination cost is low and the design questions are constant.

The mistake is treating the choice as a matter of team culture or personal preference. It is a matter of matching the instrument to the change, and most teams have a strong default and a weak exception process. The default is fine. The exception process is where the leverage sits.

A workable split for a normal week

Here is a split that holds up in practice. Small and routine changes go to async review with a required description and a response window measured in hours, not days. Medium changes go to async review by default, with pairing triggered when the author and reviewer disagree twice in the thread or when the change introduces a pattern the codebase has not seen.

Large and structural changes start in pairing, before the diff is complete. The pair works through the design at the whiteboard or the shared editor, and the resulting change goes out for async review as a formality and a record. This ordering matters. Pairing on a finished large diff is expensive and late; pairing on the design that produces the diff is cheap and early.

The trigger conditions are the part teams skip. "Pair when it feels necessary" is not a trigger; it is an invitation to never pair. Written rules, even crude ones, like "pair if the diff touches more than three modules" or "pair if the thread has gone three rounds," turn a vague intention into a decision someone can actually make at 4 p.m. on a Thursday.

What the record cannot hold

There is one thing pairing captures that no thread ever will: the moment of hesitation. The half-second pause before a reviewer says "I think this is fine, but." That pause is where the most valuable review lives, and it does not survive transcription. It is gone the instant the session ends, carried only in the memory of two people who were there.

This is why the strongest teams treat pairing as a tool for the changes that will be hardest to fix later, and async review as the tool for everything that can be corrected cheaply. The record is for the archive. The hesitation is for the change that has not been made yet.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button