Pair programming and pull requests — Different ways to get code review done
It wasn’t until 2.5 years ago that I started to work with a pull request (PR) model on my day job. Before that, I spent almost 10 years doing pair programming and pushing to master.
Going from working with someone on the same problem, sharing a screen and keyboard, to working alone and submitting my changes for review was a big change. I started to notice how the two practices aim to achieve the same goal, ensure the quality of the codebase, and how different the trade-offs were.
My objective here is not to pick a winner but to highlight what I think are the most impactful trade-offs. By understanding the main differences in their pros and cons, you can better tailor your process. You may end up deciding to use both depending on the project and team context.
Tight feedback loop vs loose feedback loop
When doing pair programming we get immediate feedback from our teammate. The feedback cycle from “not quite good” to “ship it” is invisible. After the pair pushes, your new software is ready for customers.
Pull requests are another step in our value stream mapping*. It can add time to your delivery. Will this impact be too much? It depends on how quickly the team responds to them and how aligned they are as to “what to review”. Lack of alignment usually looks like long PRs and lots of bikeshedding.
Exclusive feedback vs Inclusive feedback
When we do pair programming, the feedback on code, design, and decision making is made between the two people pairing. The rest of the team is excluded from most of it and they will later consume the output of the decisions. The feedback is super-rich and fluid, however, it reaches only two people. On small teams, this is usually not a big deal as they tend to more quickly get into their “groove” and reach a common understanding of design patterns and code styles they would like to follow. This story is different if you have a team with more than 4 engineers. In a large team, it is easy for a pair, with their best intentions at heart, to deliver something that ends up building technical debt. One big complexity of pair programming in a large team is that we need to be careful of the seniority balance and personality match. Something we can explore in a different post :)
As a code review mechanism, pull requests allow for multiple teammates to review which can be whole more inclusive. Instead of getting the eyes of one teammate, you can have everyone, a minimum number of reviewers, or a subset of the team such as code owners. Whatever choice you make here, it is more inclusive than only one person.
Broad review vs narrow review
Code review in pair programming happens when you are writing the code for a new feature or bug. This means that the two folks working on it are immersed in the reality of the codebase when they are making their design decisions. Aside from code reviewing, the pair ends up helping with the system’s evolutionary design. They are also having debates over architecture and refactoring opportunities. The entire process of adding a change is under review, not just the output of it.
Pull requests are giving the reviewer a very narrow view. “Here are all the files I added, removed, and changed to get X working”. It won’t show the reviewer the options the author had, only the final decision they made.
If you end up using PRs as your code review process, ensure the team knows that PRs are not the only place where code quality and architecture should be discussed. If the PR is the first opportunity to review a big change you will probably run into some increased cycle time**. You should also encourage your team to review the changes locally so they can catch any opportunities for refactorings that are not clear when you only look at the files changed.
Tacit knowledge vs codified knowledge
In pair programming, there’s a lot of tacit knowledge being used throughout the pairing session. A good pair will always speak up and think aloud to allow those to be communicated more explicitly. If they fail, the other person on the pair can always ask. In the end, there’s a greater opportunity for people to learn from one another in a way that transcends what can be codified. At the same time, the knowledge that was transferred can’t be easily spread to the rest of the team. It is shared with those two team members only.
A pull request review is, by default, forcing people to codify their knowledge when they add comments and questions. This is a great way to start to disseminate knowledge, however, you need to be careful of the quality of written communication on the team. Team agreements can help mitigate the almost inevitable misunderstandings that will happen.
Synchronous work vs asynchronous work
This is an obvious difference but an important one. Especially as teams move to be more distributed and companies start to realize that time flexibility is an amazing perk. Pair programming is synchronous. You need to have two people available at the same time to do it.
Pull requests are extremely friendly to remote teams and folks working in different timezones. Imagine a truly globally distributed team: you can have New York-based engineers submitting PRs for peers in San Francisco or EMEA to review. The timezone difference can be played to your advantage and reduce the lag between feedback sent vs feedback responded.
Conclusion
As I said, this is not about picking one versus the other but understanding what you are choosing to do. I’ve seen teams be extremely successful using both where simple changes like a button color would use PRs and pair on developing large new pieces of functionality.
Regardless of the decision, the most important thing is to ensure the rules of engagement are clear and that people understand what they are trying to get out of the review process.
Glossary
* Value stream mapping is a lean practice tool that maps out all the important steps of your work process necessary to deliver value from start to finish.
** Cycle time is the delta of time between the start and finish of any steps in your process to deliver working software.