Everybody in the Ruby community says they love pair programming. We often use it as a proxy for the awesomeness of a developer shop. Developer candidates regularly ask me if we pair as part of their attempt to determine if we know what we are doing.
I wish we’d cut that out. Pairing is not a proxy for how good a development shop is.
Pairing is also not, in my experience, a great tool for increasing team productivity and code quality. At least, not without putting a significant amount of effort into structuring the team to take advantage of pairing.
Intermittent pairing can be useful for teaching, knowledge transfer, or generally getting a common understanding of a problem. But it can also be frustrating, marginalizing, exhausting, and logistically challenging.
This is to say, that while I have had pairing experiences where I have shared information about the system with other developers, and I’ve occasionally had experiences where I was able to work better than I would have alone, I have rarely, if ever, had a pairing experience that I thought was better (at least in the short-term) than the two developers would have been working separately.
You’ve probably had a great experience with pairing. Congratulations! I look forward to you telling me all the things I’ve gotten wrong, this is how we improve.
Pairing is not merely sitting down with a co-worker for 30 minutes to fix a bug. Pair programming, as a full XP practice, as the idea that all production code is written by two developers at one machine, is a radical re-design of how teams work that takes an awful lot of organization, team logistics and trust to do well. It’s also, I think, significantly alienating to quite a few developers.
Pairing is a genuine skill that takes training and effort. It’s not that case that you can drop two developers in front of the same computer and magically get a huge benefit. Just sitting two people together on one machine is not likely to give you an efficiency or code quality boost and can easily reinforce existing power structures on your team in ways that are not useful. There is experience involved in knowing how to share control when pairing, there are skills involved in not having your pair hate you at the end of the session.
Unskilled pairing can easily worse then not pairing. And my suspicion is a lot more of you are doing unskilled pairing than you think.
Absent your willingness to do all that training and logistical setup, “pair all the time” or even “pair most of the time” is probably not going to help your team write better code, and you are just going to feel vaguely guilty that you aren’t pairing more.
I’ll also say that I personally don’t like pairing with another developer for an extended period of time. It makes me anxious, and I feel out of control of my schedule. As a result, I may not be the best at pairing. You are free to use this fact to dismiss the rest of this argument. Also, a disproportionate amount of my pairing time has been spent explicitly in a mentor or teacher situation, which probably warps my viewpoint.
I’ve been at one place in my career that really pushed continual pairing, not quite to the “pair all the time” level, but quite close. Here are all the things that made pairing work in that environment:
- A large team. About 15 to 20, if I recall. Pairing on small teams, like under five, is very logistically challenging. You’d think that a two-person team would be perfect for pairing, but in fact, you’re bound by the limits of both person’s schedules. A larger team gives you more flexibility in the face of meetings, sickness, and other responsibilities.
- Neutral pairing stations. Nobody was pairing on their own laptop, there were dedicated computers with dual keyboard and mouse setups and a common configuration. This is, I think, a huge and underrated issue. When pairing on one developer’s idiosyncratic setup, you have a situation where that developer is always the more comfortable of the pair, plus you have that developer’s email notifications or whatever as distractions.
- An environment where noise was okay. Another underrated issue. Pair programming requires developers to talk to each other, and as a result, it’s loud. This is fine if everybody is doing it and everybody understands it, but if you are trying to be a one-off set of pairs in an open office where everybody else is quiet, you’re going to stick out and that’s going to feel very awkward.
- Dual story responsibility. The story tracker was customized so that the pairs had dual responsibility and source control commits were made jointly by the pair. This is a little hard to do (though the tools have gotten better), but critical to maintaining an understanding of who was responsible.
- Pair rotation. The team had a very strong cultural norm that pairs should not last longer than a couple of days. This was actually very useful in knowledge transfer, and made sure that people tended to work with all members of the team. If you are on a team that pairs heavily, I do recommend rotating regularly.
- No remote culture. The team did not encourage or support working at home much, and didn’t invest in technology to support remote pairing.
This team did not train people in pairing, or show any particular awareness of or interest in power dynamics or different communication styles.
This is a not insignificant investment in hardware, in space, in team structure, and in planning. And it paid off in the sense that they wound up with a very robust culture of pairing. People got better at pairing, and the actual experience with pairing got pretty good, certainly the best pairing experience I’ve had to date.
Here’s the thing, though, about this pair-adise. Nearly everything else about the place was terrible.
Management pretty explicitly talked about pairing as a way to force developers to say on task, which made pairing feel a lot ickier than you might imagine (I did learn, though that the idea that a pair can’t slack is not true, you just have to slack together…). All the pairs were kind of thrown together in a bullpen without a ton of space (and no personal space for any individual), surrounded by management in individual cubicles, which didn’t feel great either.
There were other team problems that aren’t worth getting into here, except to say that being good at pairing doesn’t prevent you from being bad at other XP/Agile practices.
The big question, I guess, is did all this pairing lead to better code? I’ve thought about this a lot over the years, and my considered opinion is “maybe?”. It certainly didn’t seem at the time that it was some kind of super-productive team, though the other project issues didn’t help there.
The team had little to no culture of code review, the main effect of which was that duplicate or inconsistent code got added all the time because if neither pair happened to know about other uses, then they just proceeded in ignorance. In practice, this was a big problem, and it wouldn’t surprise me if the costs of not doing code review outweighed the value of pairing.
Like pretty much every other even mildly complex issue in software projects, the formal empirical evidence for or against pair programming is pretty thin. The last time I checked, there was some research that pairing led to better quality with some up-front cost in speed. Whether that finding is robust, or applied to your workplace, is really anybody’s guess.
Pair programming is like a lot of Agile practices in that the way to really get in trouble with them is to kind of dip a toe in and not really commit.
In pairing, that means pairing occasionally, and not doing any of the above interventions to make pairing more effective. As a result, your team doesn’t get good at pairing. And you don’t get any benefit.
If you are committed to pairing, make sure that you are creating an environment where pairing can be successful (and yes, this includes having developers that want to pair). If you aren’t in a situation where you can set up that kind of environment, you’re likely better off setting up a good code review process. You’ll still get a lot of the benefits of pairing but at a fraction of the organizational cost.