Pair programming and code reviews are often considered alternatives. Your team either does pair programming or code reviews, but it is unlikely you do both. Even some regulations requiring the 4-eyes principle could be satisfied by either approach. But are these methods really exchangeable? Is the argument valid that you don’t need code reviews because your team already does pair programming? In this blog post we want to find out if pair programming provides the same advantages as code reviews and vice versa.
Before we jump into the topic, let’s quickly recap what code reviews and pair programming are. The basic idea behind both approaches is the same. A second developer looks at your code to find ways how to improve it and to share knowledge. The main difference is the point in time when this happens.
Pair Programming: As the name suggests, pair programming takes place when the code is written. One developer, the driver, is typing the code while a second one, the navigator, is observing the process and giving feedback. Both parties usually sit in front of the same screen and communicate during the entire process.
Code Reviews: Code reviews are performed as soon as the code is considered mature by the author. The author usually opens a pull/merge request and the reviewer then searches for bugs and ways how to improve the proposed changes. Both parties mainly communicate asynchronously through text comments.
In the following we want to take a look at some shortcomings of pair programming and how code reviews would perform better in these situations.
The main advantage of pair programming is the strong communication between the two involved developers. The driver not only writes the code, but is also supposed to explain it and the reasoning behind it to the navigator. At first glance, having someone to guide you through the code sounds like a great advantage, but it also comes at a price. You miss the opportunity to verify whether the code is actually self-explanatory. If it is difficult to understand, you will not notice this until someone tries to modify the code in the future.
In code reviews the reviewer usually has to understand the code changes only based on the pull/merge request description and the code itself. You basically put it to the test whether someone else is able to understand it. If this is not the case, it should be a sign to add more comments to your code or reconsider whether your approach is really maintainable.
Did you ever write a piece of code, or even just text, and thought it is flawless until you looked at it again the next day? Suddenly you notice all the bugs and typos? This is not just an illusion, it is your brain trying to be smart. Psychologist Dr. Tom Stafford from the University of Sheffield, UK explains this phenom in a WIRED article about typos. When you are working on a high level task, like conveying meaning through text, your brain focuses on whether the text matches the message in your head. It pays less attention to details like typos and you can easily become blind to your own mistakes.
If we apply the same principle to pair programming, the chances are high that a driver can unintentionally influence the navigator in a bad way. By explaining closely what they are trying to achieve, they condition the navigator on what to expect. The navigator is now more focused on checking if the code matches this high level description and pays less attention to details. This theory is also backed up by this 10 year experience report about pair programming:
When a pair of developers work on the code they both share the “author’s mind” and because of this, they cannot act as an effective editor. They have both spent a significant amount of time thinking about the problem in detail while writing the code and cannot effectively see code as a new developer would when they first encounter it.
– Anthony Sciamanna
This effect is less likely to occur in code reviews as the author doesn’t have such a big influence on the reviewer. The reviewer’s primary source for extracting meaning is the code. By the way, there is also a trick to better review your own code: By opening the code in a different editor or using an alternative color scheme, you might be able to break the association in your brain that this is your own code.
During pair programming both developers are always focused on a small part of the code and switch roles regularly. This can lead to choosing a solution that makes only sense in a narrow context, rather than the best overall approach. This gets especially tricky when one developer has alternative solutions in mind but doesn’t know if they will work. Trying them out might feel like wasting their pair’s time, so they go for the safest option instead of the potentially best one.
Code reviews make it much simpler to verify whether the overall solution makes sense. The reviewer has access to the final result and can quickly jump between different parts of the implementation.
When on-boarding new team members, you usually pay special attention to their code contributions. They are not yet familiar with your code base and norms. Pairing them with an experienced developer can therefore be a great way to share knowledge and get them up to speed.
While these pairings are great for knowledge sharing, they can take a toll on your code quality. The more experienced developer might pay more attention to explaining the existing code base than to the code being written. Performing code reviews in those situations where a developer might be distracted can help to bring focus back to the code and ensure its quality.
Another issue of pairing developers with varying skill levels is that their speed might differ. This can lead to situations in which the navigator gets overwhelmed and can’t provide useful feedback, or worse, a more experienced navigator gets distracted and puts additional pressure on the driver. In either case the code quality can suffer. Code reviews, on the other hand, are usually less time critical. The reviewer can research missing information and think at their own pace.
In the above examples, classic code reviews can provide a great advantage compared to pair programming. However, there are also situations where pair programming offers significant advantages, which we will look at in more detail below.
If there is little communication in your team regarding what you are working on, it is possible that you waste time running into the wrong direction. You may have chosen an unsuitable design or even misunderstood the requirements. It would be quite inefficient to discover this in a code review after working on it for several days and writing all the code.
There are certain ways to minimize the risk, like creating several small merge/pull requests, but this can never be as efficient as having someone tell you there is an issue before or while you are writing the code.
A frequently cited benefit associated with code reviews is knowledge sharing and it is hard to disagree with that. If you review your colleague’s code, you will certainly know more about it than if it was just committed to a git repository. You might even have a discussion about the pros and cons of their solution.
Nevertheless, most of the knowledge sharing is limited to the final version. You won’t see the discarded approaches and the reasons why they were dropped. You won’t see the tools and tricks used to write that code. Pair programming allows you to see all that and offers additional ways how you can learn from each other.
How serious do you take code reviews? This can not only differ between teams but also between team members. I once witnessed the following conversation:
A: Can you review my merge request?
B: But I don’t know much about this part of the project.
A: Just press merge.
This is an extreme example of a useless code review that serves no purpose other than checking a box for some regulatory requirement. It highlights a common problem though. Not everyone in your team might care about code quality and your processes in the same way. While the underlying issue affects both code review and pair programming, pair programming might help you spot such issues earlier. It is simply more obvious when someone is distracted during pair programming than when someone is only giving superficial feedback during code reviews.
We have looked at both sides and it should be clear that code reviews and pair programming are not completely exchangeable. Both have a big overlap, but there are certain situations where either approach is more appropriate. I am also sure that this list is not complete. While writing down the arguments, I focused on the points that are hard to avoid because they are an integral part of the process or are caused by psychological factors. A badly implemented workflow can certainly lead to more issues.
Can we somehow combine the advantages of both approaches? You could make pair programming as well as code reviews mandatory, but let’s be realistic: It would be hard to justify the additional resources this would require and some developers would consider this exaggerated and not support such a process. We need a more lightweight approach instead and only perform both when it makes sense.
In my experience a combination of mandatory code reviews and on-demand pair programming works best. Code reviews can easily be integrated into remote teams, are compatible with flexible working hours and catch most bugs. At the same time the on-demand pairing sessions can used to work on tricky problems or to come up with the right design. This should prevent most surprises during code reviews. In combination with code reviews they can also be safely used to share knowledge with new hires. This approach gives you the best of both worlds.
With SemanticDiff we now provide our code change visualization as Visual Studio Code extension. Find out how to get better diffs directly in your editor and how this affects MergeBoard.