3 Good Practices for Creating Pull Requests (and Getting Them Merged Fast)
As a software developer, a good chunk of your time is spent creating and reviewing pull requests (or PRs for short). PRs are essential for shipping quality code and spreading knowledge within a team that shares the codebase. Reviewing code can sometimes be significantly more difficult and time-consuming than writing new code. It often requires you to spend time reading, to zoom out and see the big picture and zoom in on the problem at hand. Finally, you will need to respond in a way that encourages collaboration and good decision-making.
It is important that we craft our PRs well. This helps avoid our work piling up in the “In Progress” pile of your favourite project management system, and reduce the likelihood of potentially negligent LGTM ("looks good to me 👍") approvals.
So, what makes a good PR? Here's the top 3 things to keep in mind. There is plenty to be said about the reviewing process as well, but here I'll focus on the role of the pull request author.
#1: Make smaller pull requests
It might seem like common sense, but this is the most important factor in getting your PR reviewed and approved fast. Even if it means there will be more of them!
The smaller the PR, the smaller the barrier of entry for a reviewer, who has to dedicate time to review your PR. This way, it’s easier for them to grasp the context and the logic. If a small PR is not possible, try creating more smaller (and readable) commits.
You are less likely to introduce bugs that fly 🪰 unnoticed in your code if your code changes are small and focused. The smaller the code, the fewer potential (code) conflicts you might have with your peers down the line.
One final note on PR size: Don’t fall into a refactoring rabbit hole in the middle of feature development — it’s a trap! Been there plenty of times by following the boy-scout rule of "Always leave the code better than you found it". Refactoring code is a great thing to do from time to time, but mangling a refactoring effort with a new feature (or two) is a recipe for a bad time. It is better to spend a little more time breaking down the problem you’re trying to solve, and then create a new PR/task for the refactor as a follow up.
#2: Give enough context
We often use the verb “to read” when we try to acquaint ourselves with a new piece of code. Sure, there is a common (programming) language that we share with the authors, which helps us “read” and determine what a particular line of code is doing. However, when we read someone else’s code, we have to build our own mental models from scratch, and usually at a faster pace than if we were the ones writing it. It is not an easy task, unless you are either already familiar with the particular part of the codebase or someone takes the time to acquaint you with it.
Here’s some ways to give valuable context for the reviewer of your code:
- Have a self-explanatory title of your PR.
- Provide a link to a document or ticket with relevant information.
- Have a “Start from here” section in your PR description — this is super valuable as we want to start the creation of mental models needed to understand the code as soon as possible, and the entry point to a changeset spanning multiple files is gold.
- Add comments in your PR to help guide the reviewer — you don’t need to explain the code, but give pointers on where to look. If you do feel the need to explain the code, consider adding actual comments inside the code itself.
- Draw it out! — screenshots help a lot with visualizing the flow. When making complex data model changes, drawing out the model (with an online tool like draw.io or excalidraw, unless you’re feeling particularly artistic) helps the reviewer reason about the changes better.
#3: Include Tests
Adding tests gives us confidence that our code is working as expected. Please have them 🥹 Your future self will thank you, when you get to look back on your code from many moons ago, and you can make changes in it or around it without major issues.
You can also demonstrate how a piece of code is used by covering its use cases in the tests, which your PR reviewers will appreciate. Tests improve (but don't replace) documentation, immensely.
The different kinds of tests, how to prioritize them, and what’s the “ideal” test coverage are all beyond the scope of this post. They are all good topics to discuss with your team though, hopefully outside of your PR!
Final note
To let developers focus on what matters, parts of the pull request creation (and review) process can be automated. Of course, the bigger the project, the bigger the need to automate processes. Here are some ways to do that:
- Linters — tools that analyze source code, for coding style and consistency (e.g. flake8, mypy, isort for Python; ESLint, Prettier for JavaScript; Golang developers got lucky with
go fmt
but there's alsogo vet
). - Conventional commits — making the messages both human and machine readable.
- Automated checks for PR titles, commit formatting and descriptions.
PR templates — for example Github offers you a way to start every PR with a template where you can fill in the necessary context for the reviewer in the description, when you make a new PR.
And remember that opening a PR means inviting your teammates to take part in a discussion about your work. This means that at least one more human (we assume 👽) with their own perspective is taking time to look at your code, and maybe learn something themselves. It may require that you put yourself “out there” and feel vulnerable by opening up your work for critique.
Keeping a friendly and thoughtful tone will ensure the team grows and continues sharing knowledge and working together in the future. It should be a fun and collaborative process where we make our codebase and ourselves a little bit better each time. So, happy hacking!