A lot has been said about pair programming as an effective way to develop software, and I would bet most software developers have strong feelings about the practice. Some people swear by it, and others consider it a waste of time. So much thought has gone into the practice that you can hear people debate the virtues and best practices and programming in pairs. Some will say you need to pair people with extremely different levels of expertise, while others will tell you that you should only pair for an hour at a time to maximize efficiency.
I'm not going to talk about my philosophical leanings on pair programming, but I do think I have some more practical things to say about doing effective pair programming while working remotely. I've seen some good and some bad in the past year and a half of remote work, and hopefully I can save you from some of the mistakes I've made.
What is pair programming?
I define pair programming very simply:
Developing software while in constant contact with at least one other person.
Programming while asking someone for advice and feedback live on Slack should be considered pair programming, just as programming with someone sitting next to you at your desk should be. Importantly, and often overlooked, doing a code review in person should be considered pair programming. These all satisfy the underlying purpose of pair programming: to reduce time to feedback from peers while developing software, hopefully reducing the number of errors or confusing code block in the process.
There are obviously drawbacks to programming like this:
Firstly, it can take longer than normal to churn out a piece of code if someone is constantly asking you questions about what you're doing and where you're going. You are unlikely to every reach a state of flow while pair programming, and will have to work harder to keep context for the task together in your head.
Secondly, you must have a willing partner available at the same time you are. If your partner would rather take a nap, you won't have a very productive time pairing with them, and you would probably be better off writing out a first attempt and submitting it for an asynchronous code review instead.
And lastly, pair programming can be exhausting. Managing both your code and another person's expectations and questions can be a trial on its own, and it's no wonder many developers hate the idea of pairing with a teammate. Pairing sessions that last more than an hour often become extremely inefficient, and I usually need about 20 minutes to reset after a long pairing session.
When should you pair?
Pair programming should only happen when all parties involved:
- Can dedicate a substantial amount of time to the effort
- Have enough knowledge on the task or system at hand to provide useful commentary
- Are feeling fresh
- Are willing to dedicate themselves to be either a reader or action-taker
The first three should all be reasonably obvious. Building context around software systems can take a while. Most people I know budget around 10 minutes to get into the groove; while pair programming you have to get 2 people into the groove. If you're feeling tired on unmotivated that day, or don't really know what the existing codebase looks like, it can be extremely difficult building enough knowledge on the fly to provide useful feedback.
Too many times I've paired with someone who "wanted to learn about <the project>" or "needed a nap but is probably fine" or was wrangling a child or a meal in the background while we paired, and I've been one of these people at least a few times. None of them have ended well. I've left each one of those sessions frustrated, exhausted, and feeling like I got nothing out of that time, especially when I was the one to blame. And I've kept pairing sessions going too long too many times to boot. When someone can no longer dedicate their focus to the work, or isn't feeling fresh, the pairing needs to stop.
The last bullet has come to bite me a few times in the past, where someone offered to pair on a project and then periodically would either ask to take control of the code or have me take control. Neither of these is fun, and it gets worse with remote work. At least in person one of us could hand the keyboard to the other, but over a Zoom call the steps are many and slow:
- Commit your current working tree
- Push it to the remote
- While your partner pulls down your work, switch the screen share to their screen
- Watch them struggle to get into a groove in their editor while reading through your half-completed code
But, when should you pair?
Ah, I didn't really answer the question. There are a few times where pair programming has been undeniably the correct process, and it's been made more obvious by remote working.
Bringing a new teammate up to speed
One of the best things you can do for your organization is reduce the amount of time it takes for new team members to become productive. While this is in direct violation of bullet #2 above, I have a justification for ignoring that: this person needs to have enough knowledge about the task or system at hand to provide useful commentary, and it's part of your job to get them there.
In an office, you might have some check-ins with the new person to make sure they're finding their groove and spending a few extra minutes here and there to be sure the early tasks you've given them are getting done. In the remote world, these quick check ins are much more difficult. A 10 minute Zoom call is almost as tiring as a 30 minute call for many people, and certainly takes the same amount of energy to put together.
My strategy, and one that my team has employed to great success, is to force the new person into pairing situations with the rest of the team. I put one team member in charge of our release process during their first week, but made sure I was on the call for every button clicked and command run. Together it took us quite a bit longer to complete, but afterwards that teammate was ready to handle any releases in the future with no more hand holding. A more recent new teammate was similarly tasked with launching an environment with some new tooling we'd been working on; that person quickly became the team expert in deployment.
In my experience, pair programming is the most effective way to bring new or inexperienced teammates up to a place where they can meaningfully contribute to the team.
Building a new system
I have much less experience here, and that might be why I enjoyed pairing on this project so much. Those more experienced than I may not enjoy pairing in this manner, but I'll try to explain why this was so useful to me.
When building a new system, you are often giving freedom to pick your own technologies, endpoints, design patterns, and naming conventions. For me, and for many others, this is enough to cause extreme decision fatigue. I'll stare for hours at frameworks that do basically the same thing and try to piece out which one does the thing I want ever so slightly better. I'll read up on gRPC vs. REST vs. GraphQL and agonize about how I want my network layer set up.
Sometimes you need someone on a call to yell at you for taking so long to decide between frameworks. Sometimes you need someone to tell you that they don't need to see you write out the documentation for a thing you haven't even written yet. Sometimes you need someone to put you in a position where you must make a decision.
In particular, it's extremely helpful when someone does have some domain knowledge already. I know a little about 2 Python web frameworks, but when faced with the ability to decide which one would win out, I struggled. My teammate on the call saw me open tabs for both of the frameworks and called it out: "I know Flask, I've used that before. Let's go with that for now." We built a system with Flask because both of us knew how it worked, and we were more likely to build a working system that way.
The other amazing thing about pairing with someone on a new system is the help you can get with the API. Developers often struggle to fully understand the needs and wants of their consumers, and that translates directly to the API decisions they make. If I know I need to expose a list of recent transactions, I may send all the data about those transactions back to the consumer. But if I know that consumers only care about the total amount over a timeframe, I can send them back a single number instead. While pairing with another person, I have a free consumer I can interrogate about API decisions. "What should this type of functionality be called?" and "Should this be under the same path as X or Y?" are the types of questions that can take days to bike shed and answer on design documents but are obvious while watching the system being built.
When you need a code review
The most concise form of pair programming comes in situations where you don't even have to write code at all: during code review.
I love in person code reviews. They were the tool that brought me from a code monkey to a software developer. I could ask people all the stupid questions on a code review that I would never dare type out, and they could make me justify the silly (or brilliant) decisions I had made trying to piece together a working piece of code.
Most of the code reviews I've done have had questions or comments that I haven't included on the review because they weren't fully formed or particularly relevant to the feature or fix under review. But in person you can have those conversations out loud and without worry. Sentences that trail off like "It feels like we could do something with a stream here..." can bounce around in your partner's brain and help them find a more elegant solution to the problem. And mentions of issues in the surrounding system can lead to easy bug fixes or code cleanups in follow up reviews (I remember once deleting an entire package of Java code from a codebase because someone mentioned an unreachable switch statement case during an in-person code review).
Nothing has ever made me think about my code more than pairing while writing code, but nothing has made me think about how to think about code more than in person code reviews.
When you need motivation
Some days I feel awake, but unmotivated. My brain could work, but there isn't a drive. In the office, I might take some extra time in the break room getting coffee or chatting with my coworkers, letting their energy wake up my motivation for the day.
We don't get that option when working remotely. Social chats over Zoom or Slack always feel forced and unnatural. The best way to transfer energy to other people is to pair program. While pairing, you have the opportunity to push yourself with someone else's energy. Even if you are the reader in the pair session, it can be exciting just watching and hearing someone talk through what's going on in their head.
If you are working remotely, I believe pair programming is essential. It makes up for so much lost chatter in the office and helps bring people into alignment before the official code review process begins. Personally, I'm excited to take pair programming back with me into the office (when it reopens), though only for very specific purposes. I don't think it's a magic bullet like some others do, but I've come around during my time working remotely and think it's a great way to attack certain types of problems.
And if you do not like pair programming, at least consider my last point about motivation. You may not need a programming partner, but your teammates may need your expertise and presence to help get them through the day. I will personally never turn down a teammate who wants to pair, though they may have to wait till my energy levels are acceptable for such an undertaking.