The Art of the Self-Documenting Pull Request

We’ve all seen it. A pull request with the title Fix bug and a description that is either empty or, if you’re lucky, as per ticket. You’re now faced with deciphering a hundred lines of code changes across five files with zero context. This isn’t just annoying; it’s a bottleneck that slows down the entire team.

A Pull Request is not a chore to be rushed through. It is a form of asynchronous communication, a historical document, and the most important story you will ever tell about your code. A great PR doesn’t just ask, “Can this be merged?”; it explains the why, the what, and the how of a change.

Investing a few extra minutes in writing a good PR description is one of the highest-leverage activities a developer can do.

Anatomy of a Great PR

A great PR is a narrative. It guides the reviewer through the change, making their job easier, faster, and more effective. Here is a template I’ve used with my teams that works wonders.

### Why

*(This is the most important section. Start here. Don't explain the code, explain the reason for the code. What is the business context? What problem are we solving for the user? Link to the ticket: [LINEAR-123](https://linear.app/team/issue/LINEAR-123/fix-the-thing).)*

### What

*(A high-level summary of the technical approach. How did you solve the problem? Don't repeat the diff, but explain the architecture of your solution.)*

*   *Introduced a new `InvoiceGenerator` service object to encapsulate the logic for creating invoices.*
*   *Added a `state` column to the `invoices` table, managed by AASM.*
*   *Refactored the `InvoicesController` to be a slimmer, more conventional RESTful controller.*

### How to Test

*(Provide clear, step-by-step instructions for the reviewer or QA to manually verify the changes. Assume they have no context.)*

1.  *Log in as a user with the `admin` role.*
2.  *Navigate to the `/invoices` page.*
3.  *Click the "Create New Invoice" button.*
4.  *Verify that the new invoice appears in the list with a "draft" status.*

### Screenshots / Recordings

*(For any UI change, this is non-negotiable. Show the before and after. A quick screen recording (using Kap, Cleanshot, or Giphy Capture) is even better for demonstrating a flow.)*

**Before**

![Old UI Screenshot](https://example.com/before.png)

**After**

![New UI Screenshot](https://example.com/after.png)

The Power of Atomic Commits

The story of your PR begins with your commits. A PR with a single, massive commit titled WIP is hard to review. A PR with a series of small, atomic commits that tell a story is a joy.

Consider this commit history:

  1. refactor(Invoices): Extract InvoiceGenerator service
  2. feat(Invoices): Add state machine for invoice status
  3. fix(Invoices): Correctly calculate tax on invoice line items
  4. test(Invoices): Add coverage for InvoiceGenerator

Each commit is a logical, reviewable step. The reviewer can walk through your thought process, making it easier to spot issues and understand the evolution of the change.

Code Comments vs. PR Description

A PR description is for the reviewer. Code comments are for the next developer. They serve different purposes.

  • PR Description: Explains the change in the context of the business and the system at a moment in time.
  • Code Comments: Explain the why behind a specific, non-obvious piece of code. They live forever with the code.

This is a good comment. It explains a business constraint that is not obvious from the code itself.

# We have to apply the discount before calculating the tax, not after.
# This is a legal requirement for our EU customers as per the 2021 tax code update.
final_price = (base_price - discount) * (1 + tax_rate)

Conclusion: Culture is Built Through Action

Writing a great PR is a habit, and it’s a cornerstone of a healthy engineering culture. It fosters collaboration, reduces review friction, and creates a rich, searchable history of your project’s evolution.

It’s not about rigid rules; it’s about respect for your teammates’ time and a commitment to quality. The next time you open a pull request, don’t just ask for a review. Tell a story.