How to Write a Pull Request That People Actually Want to Review

by Arif Ikhsanudin, Backend Developer

Why PRs Sit in the Queue

You've seen this: a PR that was opened three days ago, hasn't been reviewed, and the developer is frustrated. The delay isn't usually because reviewers are ignoring it. It's because the PR is hard to review.

Hard to review means: it's not clear what the change does, why it exists, what the testing story is, or where to start reading. The reviewer opens it, sees fifteen changed files with no context, and closes the tab to come back "when they have time." They never have time.

A PR that's easy to review gets reviewed quickly. Not as a matter of reviewer motivation, but because easy reviews get done during small windows of time — ten minutes between meetings — while hard reviews require uninterrupted focus that nobody has spare.

The Three Things Every PR Description Needs

What this PR does, stated plainly. Not the implementation details — the purpose. One or two sentences that a developer who hasn't been following the work can read and immediately understand.

## What
Adds idempotency key support to the payment charge endpoint to prevent
duplicate charges when the client retries after a network timeout.

Why this PR exists. The business reason, the incident that triggered it, the technical debt it addresses. This is the context the diff can't provide.

## Why
After the incident on March 14, we found that network timeouts were causing
clients to retry charge requests that had already succeeded. This resulted in
20 duplicate charges before monitoring caught it. Idempotency keys are the
standard solution (Stripe's API uses the same mechanism — see their docs on
idempotency).

How to verify it works. What tests exist. What you manually verified. What the reviewer should check if they want to validate the behavior themselves.

## Testing
- Unit tests: `PaymentGatewayClientTest#idempotencyKeyOnRetry`
- Integration: `PaymentFlowIntegrationTest#noDuplicateChargeOnRetry`
- Manual: tested with `scripts/simulate_timeout_retry.sh` against staging,
  confirmed single charge appears in Stripe dashboard after simulated timeout

The Diff Is Not the Description

A common failure: the PR description is left blank, or just the commit message, with the implicit expectation that reviewers will read the diff and figure it out. This is technically possible. It's also the fastest way to get shallow reviews.

When a reviewer has no context, they review defensively — they look for obvious errors and style problems, because they can't evaluate design decisions without knowing what problem was being solved. You get comments on variable names and missing null checks, but not on whether the architectural approach is right.

When a reviewer has context, they review strategically — they evaluate whether the approach is correct for the problem, whether the edge cases are covered, whether the design will hold up as requirements evolve. That's the review that actually improves the code.

Self-Reviewing Before You Request Review

Before you hit "Request Review," read your own PR as if you were a reviewer who knows nothing about this work. Specifically:

Read the diff from the outside in — start with the highest-level changes (new files, changed signatures) and work toward the details. If you get lost, the reviewer will too.

Look for the code that requires context to understand. A complex conditional, a counter-intuitive data structure choice, a performance optimization that obscures intent. Leave inline comments on these explaining the reasoning:

# Using a sorted list here instead of a set because we need to maintain
# insertion order for the retry sequence — set iteration order is
# nondeterministic and would produce inconsistent retry behavior.
retry_sequence = sorted(attempts, key=lambda a: a.timestamp)

Inline comments in the diff are visible to reviewers as context, not as code changes. They're the most efficient way to pre-answer questions.

PR Size and Its Effect on Review Quality

A 1,500-line PR does not get the same quality of review as three 500-line PRs covering the same changes. The research on this is consistent: reviewer effectiveness declines significantly above 400 lines of diff (Cisco's internal study on peer code review found defect detection rates dropped sharply above this threshold).

This is not a reviewer failure. It's a cognitive load problem. Above a certain size, the reviewer is context-switching so frequently between files and concepts that they lose track of the thread.

If your PR is large because the feature is large, split it:

PR #1: Add database schema and migration for idempotency keys
PR #2: Add idempotency key generation to payment service
PR #3: Add idempotency key validation in gateway client
PR #4: Add integration tests and monitoring

Each PR in the sequence is reviewable in isolation. Reviewers can see the progression. Reviews can happen in parallel for the later PRs if the first one is already merged.

A Practical PR Template

GitHub supports PR templates via .github/pull_request_template.md. A minimal template that actually gets used:

## What
[One to two sentences on what this PR does]

## Why
[Why this change is needed — link to ticket, describe the problem]

## Testing
[What tests were added or modified, and what was manually verified]

## Notes for Reviewer
[Anything that needs attention, known tradeoffs, areas of uncertainty]

Keep the template short. A five-section template with required fields turns into a compliance exercise that gets filled with placeholder text. A four-field template that takes three minutes to complete gets filled with actual content.

The Metric Worth Tracking

Time from PR open to first review comment is a signal of how reviewable your PRs are. If it's consistently over twenty-four hours, either your team is overloaded or your PRs are hard to start reviewing. Both are fixable, but they require different interventions — and a good PR description is always part of the fix.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Integration Tests Are Not Just Bigger Unit Tests

Integration tests and unit tests answer different questions. Treating integration tests as unit tests that cover more lines leads to slow, brittle suites that provide neither the speed of unit tests nor the coverage of true end-to-end tests.

Read more

Your Table Structure Is Making Your Queries Harder Than They Need to Be

Schema decisions that feel neutral at design time create query patterns that are unnecessarily complex, slow, or fragile — recognizing the structural mismatches between your schema and your access patterns is the first step to fixing them.

Read more

How to Onboard a Remote Backend Contractor So They Deliver From Week One

Contractor onboarding isn't employee onboarding with fewer steps. It's a different process with a different goal — and most startups set it up wrong.

Read more

The Essential Tools We Use to Work Remotely

Remote work sounds simple—just a laptop and internet. In reality, the right tools are what make everything actually work.

Read more