Pair Programming

B M
6 min readMar 5, 2021

Pair programming is the practice of working on lines of code on the same computer with a fellow developer.It is a very collaborative way of working and involves a lot of communication. While a pair of developers work on a task together, they do not only write code, they also plan and discuss their work. They clarify ideas on the way, discuss approaches and come to better solutions. Within the practice there’s a driver and a navigator. The driver modifies the code, while the navigator observes and suggests which code to implement, including spotting any mistakes. To get an optimal solution it’s best to switch the driver and navigator roles on a regular basis.

Common Pitfalls

  • both programmers must be actively engaging with the task throughout a paired session, otherwise no benefit can be expected
  • a simplistic but often raised objection is that pairing “doubles costs”; that is a misconception based on equating programming with typing — however, one should be aware that this is the worst-case outcome of poorly applied pairing
  • at least the driver, and possibly both programmers, are expected to keep up a running commentary; pair programming is also “programming out loud” — if the driver is silent, the navigator should intervene
  • pair programming cannot be fruitfully forced upon people, especially if relationship issues, including the most mundane (such as personal hygiene), are getting in the way; solve these first!

To pair or not to pair

Our experience clearly shows that pair programming is a crucial practice to create high quality, maintainable software in a sustainable way (see “Benefits”). However, we also don’t believe it is helpful to approach it dogmatically and always pair. How exactly pair programming can be effective for you, how much of it, and for which tasks, can vary. We’ve found it useful to set pair programming as the “sensible default” on teams, and then discuss whenever we want to make an exception.

Let’s look at a few examples where it’s helpful to balance how and when you pair.

Code Review vs. Pairing

Many people see the existence of a code review process as reason enough not to need pair programming. We disagree that code reviews are a good enough alternative to pairing.

Firstly, there are usually a few dynamics at play that can lead to sloppy or superficial code reviews. For example, when coder and reviewer rely too much on each other without making that explicit: The coder might defer a few little decisions and improvements, thinking that problems will be caught in the review. While the reviewer then relies on the diligence of the coder, trusting their work and not looking too closely at the code. Another dynamic at play is that of the sunk cost fallacy: We are usually reluctant to cause rework for something that the team already invested in.

Secondly, a code review process can disrupt the team’s flow. Picking up a review task requires a context switch for somebody. So the more often code reviews occur, the more disruptive they will be for reviewers. And they should occur frequently, to ensure continuous integration of small changes. So a reviewer can become a bottleneck to integrate and deploy, which adds time pressure — again, something that leads to potentially less effective reviews.

With Continuous Integration (and Delivery), we want to reduce risk by delivering small chunks of changes frequently. In its original definition, this means practicing trunk-based development. With trunk-based development, delayed code reviews are even less effective, because the code changes go into the master branch immediately anyway. So pair programming and continuous integration are two practices that go hand in hand.

An approach we’ve seen teams use effectively is to pair by default, but use pull requests and code reviews for the exceptional cases when somebody has to change production code without pairing. In these setups, you should carefully monitor as a team that your pull requests don’t live for too long, to make sure you still practice continuous integration.

Boring Tasks

Some coding tasks are “boring”, e.g. because they are about using some well defined boilerplate approach — so maybe you don’t need to pair? The whole team already knows this type of approach, or it’s very easy to grasp, so knowledge sharing is not that important? And live code review is less useful because the well-established pattern at hand has been used successfully in the past? So yes, maybe you don’t need to pair.

However, always consider that rote tasks might be a smell for bad design: Pairing can help you find the right abstraction for that boring code. It’s also more probable to miss things or make cursory errors when your brain goes into “this is easy” autopilot.

“Could I Really Do This By Myself?”

Pairing has a lot of benefits for programmers who are just starting out, because it is an opportunity to learn relatively quickly from a more experienced member of the team. However, junior programmers can also experience a loss of confidence in their own abilities when pairing. “Could I really do this without somebody looking over my shoulder?”. They also miss out on learning how to figure things out by themselves. We all go through moments of frustration and unobserved experimentation with debugging and error analysis that ultimately make us better programmers. Running into a problem ourselves is often a more effective learning experience than somebody telling us that we are going to walk into it.

There are a few ways to counteract this. One is to let junior programmers work by themselves from time to time, with a mentor who regularly checks in and does some code review. Another way is letting the more junior programmers on the team pair with each other. They can go through finding solutions together, and still dig themselves out of rabbit holes faster than if they were coding by themselves. Finally, if you are the more experienced coder in a pair, make sure to be in the navigator’s seat most of the time. Give the driver space to figure things out — it’s sometimes just a matter of waiting a little bit until you hit that next wall together, instead of pointing it out beforehand.

When is pairing most effective?

Pair programming can be really tiring. In my opinion, it’s even more tiring when done remotely! It’s a highly social interactive process because you constantly need to be engaged, not only with the screen, but also with your partner.

I’ve had times where I’ve spent four hours on call with another developer (an hour past my usual sign off time) with no breaks in between because we were so engrossed in what we were trying to solve. Because of this, you can often experience “screen fatigue” or just fatigue in general. That’s why it’s important to set boundaries with your pairing partner and it’s even more important when you’re working across time zones. Setting up boundaries and workflow expectations ultimately help with engagement levels while pairing, making the time you spend together as efficient as possible.

Setting boundaries and expectations

You and your peer may have different styles of working so it’s important that you both understand how each person works.

Everyone has different energy levels, interactive preferences and introversive/extroversive tendencies — this is why it’s important to incorporate breaks. It could be as little as 10 mins every hour or simply calling out whenever you need a break. Regular breaks are important as they help mitigate any feelings of fatigue that you may experience.

Communicate your preferred style of video calling. It’s okay if you prefer to have your camera off during the session, just make sure that everyone is continuously engaged in the pairing.

The key is communication

Remote pair programming definitely comes with its challenges, but the key is communication! Tell each other your expectations and use trial and error to see what works best for the both of you — no pair is the same!

I find this practice to be a really powerful way to greatly improve your development skills and I love the knowledge sharing nature of it. Even with the constraint of being in different places and time zones, I find that I’m constantly learning something new every time I pair with different engineers on my team as we push out well thought out code.

--

--