The Art of the Small Pull Request
Today is the day you become everyone’s favorite teammate by making your pull requests easy to review. -Bonus- your PRs will be reviewed faster too!
Let’s start with a story…
Once upon a time there was a team called “A”. Their pull requests that looked like this:
Oh, poor “A” developers! They didn’t know why, but they didn’t feel like they were making progress. They weren’t excited about their work. Reviewing was a dreadful process that no one looked forward to.
This is what they looked like when they saw so many changes in a single PR:
In a far-off land, a team called “B” had pull requests were looked like this:
Oh, the joyful “B” developers! Pull requests were merged to master in an effective way. Reviewing was something teammates looked forward to doing. Great discussions happened frequently.
Clean code was everywhere! Here’s a picture of a developer from this team:
Which team would you like to be part of? Which PR would you prefer to review?
- Code is only useful once it‘s deployed.
- Sometimes our processes stop us from doing exactly that.
- Our goal should be to integrate the code into the master branch as fast as possible. Otherwise the value we’re providing is delayed.
So why do big PRs go against our objectives?
Big PRs “Are Hard to Review”
You need to schedule time to review PRs.
You need to schedule A LOT of time to review a big PR. That usually means that people put it off as long as they can due to time constraints.
Reviewing is hard! You have to check the specs. Check if appropriate tests are written. Try to think of edge cases. Could this thing be implemented better? What can we improve?
Reviewing a big PR is EXPONENTIALLY harder. More written code means more possibilities for improvement. More tests can be missed. More edge cases can exist and need to be checked.
Having small PRs eases the burden on our colleagues. They’re just easier to handle. Yay, teamwork!
Big PRs “Have Conflicts”
As PRs get older and other PRs get integrated before them, more and more conflicts appear.
No one likes to fix conflicts! It feels like non-productive work and it’s usually error-prone and hard to automate.
Smaller PRs mean fewer conflicts since you have less code to conflict with.
Big PRs “Have More Than One Responsibility”
A PR should do one thing. Keep it simple.
Doing more than one thing means harder reviews. Your teammates will have to be constantly context-switch between different topics. When we have one single responsibility in the PR, better discussion happens.
Before doing a PR, think about the problem you’re really solving. Everything else should go into separate pull requests. Changing an unrelated variable name? Yeah, that’s another PR. Doing some abstraction to accommodate the new feature? Yeah, you guessed it- another PR.
Small PRs help us focus, which also means PRs are easier to understand.
Big PRs “Don’t Promote Discussion”
You’ve seen small PRs with tons of comments. You’ve seen big PRs with just a few comments. Even when they’re more complex.
We’re simple animals. We get bored after reviewing the same PR for a while.
With a smaller PR we’re able to focus and write more insightful comments. Which means better code.
Sometimes big PRs get complete reviews. When that happens, it amounts to a huge number of comments on the same PR. That means multiple parallel discussions on the same PR. Hard to manage. Not fun.
Smaller PRs can promote better discussion, both for authors and reviewers.
Big PRs “Mean Big And Fat Deployments”
Your big PR gets past the review stage. Good job! Damn, that was a lot of effort.
What comes next? QA.
Your colleague tells you there’s a bug in your code. :(
Now is when you realize you made a mistake.
Where is the error? Maybe it’s in that refactor which is barely related to the feature? Could it be the actual code of the feature? Or maybe worse, is this PR about three or four different but related features?
So you have to try to find where the mistake is in the 1000 or 2000 lines of code you changed. What a painful experience!
After hours of debugging, we’ve fixed all the mistakes. Time to go to production.
Because the PR is so big we now have a lot of things to monitor. Checking logs gets harder. Checking the metrics system also gets harder. It goes on and on.
Deploying when you have many changes at the same time isn’t cool.
Small PRs mean faster and better feedback from QA. Deploying is safer. Fixing a mistake in a small PR is way easier. Fewer moving pieces also means that software is more robust and there are fewer chances to screw up.
Big PRs “Are Slow PRs”
In conclusion, when you have a big PR, it tends to stall. A huge amount of time happens between when the PR is submitted and when it’s deployed to production. And our goal is to minimize that, remember?
When everyone works with big PRs it ends up looking something like this:
Or the GitHub equivalent:
All that code is literally doing nothing. It’s just sitting in GitHub.
Would you want to handle so many PRs? No one wants to! It’s better to have fewer PRs to manage. The only way to do that is if we’re able to integrate them as fast as possible onto the master branch.
By having a small PR, we can achieve faster lifecycles, integrating code faster. A nice side effect of this is that fewer PRs are just sitting there, waiting to be merged.
The Small PR Manifesto
Our goal is to get PRs integrated onto the master branch as fast as possible. Code isn’t useful until it gets into master.
- In order to make PRs easy-to-read and review, we’ll make them small.
- In order to avoid conflicts in our PRs, we’ll make them small.
- In order to handle a single responsibility in each of our PRs, we’ll make them small.
- In order to promote healthy and constructive discussion in our PRs, we’ll make them small.
- In order to make deployments small and easy to grasp in our PRs, we’ll make them small.
- In order to have fast PRs, we’ll make them small.
And that’s it!….
We hope that following this philosophy will help you write better code, and in a faster way.
In following posts we will explain how to achieve small PRs in practical steps. Git workflows. Branching flows. Tooling. All the good stuff. Stay tuned!