Pair Programming — a pair that’s greater than the sum of its parts. You may have heard about pair programming and wondered whether it was worth trying in your workplace. On the surface it sounds simple, but two developers sitting together are not all that it takes to achieve productive pairing.
Logistical and personal hurdles such as scheduling, tool choices, and distractions can stop you from getting the most out of pairing. But the potential advantages can make it worth the trouble of recognizing and surmounting these challenges.
How could it be more productive to take two programmers who were previously working on separate projects and have them work together on a single project? Won’t everything take twice as long? To an outsider the idea of pairing may sound counterproductive at first, but the advantages become apparent when you start to think about why we code and what we’re trying to accomplish.
Programming is not about churning out the most lines of code in the shortest amount of time, or even delivering the most features within increasingly tight deadlines. You can have engineers working around the clock pushing new features into production, but how productive are they really if those features are cranked out by individuals working in isolation according to their own unique understanding of the overall architecture? The resulting code is likely to be riddled with technical debt such as hidden bugs, performance issues, idiosyncratic syntax, and inefficient designs that may not use resources efficiently and may make it that much more difficult and time consuming to modify the code when one of those flaws surfaces.
You need your code to be meaningful and well written so that it works together seamlessly and can be modified easily. You need it to encapsulate the desired functionality so that your end product behaves properly and performs as expected. You need it to be resilient so it can withstand organizational changes that are a natural part of working together, as well as environmental changes and new customer expectations that may make today’s workable solution obsolete without much warning.
In order to make that possible, developers need to be able to agree about fundamental requirements clearly, get up to speed quickly with whatever new or established technologies may be required, and focus without interruption to test out creative solutions and develop a product that’s worth putting in front of the customer.
These are the real-world challenges that pair programming helps to address. When two developers work together in a pair, the quality of the code they produce improves along with their shared understanding of how it works. This makes it easier for the next person who reads the code to pick it up and modify it when necessary, and it reduces the danger that the only person on the team who knows how part of the code works may win the lottery and leave the team, taking that precious knowledge with them.
The time cost in mythical work hours is nowhere near the 50% that may seem intuitive if you tried to to equate the intricate art of coding with repetitive assembly line work. Some empirical studies have concluded that pair programming might result in about a 15% increase in the time it takes two programmers to accomplish the same tasks had they been working alone, but the resulting code will also be of much higher quality, with about 15% fewer observable defects to fix. Combine this with the shared ownership, deeper engagement, and faster problem solving that comes from having more than one mind engaged in solving a problem, and it’s clear why pair programming is a popular approach.
What Exactly is Pairing?
So what does it take for two developers working together to achieve the productivity and quality improvements that come from pairing? It’s mostly a matter of learning how to work collaboratively, which is not necessarily the way most of us learned to code.
By definition, pair programming doesn’t start until you have two people working together on one computer. But how does that work in practice?
Two People …
The fundamental element of pair programming is working together with your pair. When a task is accepted, it needs to be shared between both of the people working on it, and they both need to be fully engaged in the task while they’re pairing on it. That means that they both need to understand the requirements the same way, and work together to come to a shared understanding of how they want to go about meeting them.
Pairing helps people get better at verbalizing their ideas and expectations. The implicit understanding you have in your head when you’re working alone needs to be communicated so both you and your pair know you’re on the same page. Getting as explicit as possible about the work and the approach up front will help make the pairing experience much more agreeable. Pairing involves a lot of talking, as that’s the best way to keep two minds actively engaged in the problem at the same time.
For this reason, pairing is often associated with agile story writing, in which requirements for a feature are defined in consistent, plain language that can be understood equally well by Product and Engineering people with little room for ambiguity. Often pairs will ask for stories to be spelled out in Gherkin, which is a way of using common, non-technical phrases that are easy to translate into automated tests, so the pair can verify and demonstrate that each feature works as expected.
Writing in Gherkin means taking a feature and breaking it down into a simple story about a customer who wants something that this feature will deliver:
As <a customer of the product> I want <something desirable> So that <I can achieve a specific goal>
Then all the acceptance criteria are written out in a consistent syntax, defining the anticipated permutations and scenarios associated with that story:
Given <a customer in a particular state> When <something specific happens> Then <there is a specific outcome> Given <a customer in a particular state> When <something different happens> Then <there is a different specific outcome> etc.
Of course, it’s not mandatory to use this exact phrasing, but if the requirements of a feature can’t be expressed in this minimalist way, it’s possible that the expectations are ambiguous. That’s a potential red flag that’s easier for a pair of programmers to spot when they start to discuss what’s needed.
As soon as a pair accepts a story to work on, they should be able to define how they will know they are done and how they’re going to prove it. From there, they can start to figure out together how best to approach the job.
In fact, the pair working on a feature should know enough up front that they could start by writing an automated test based on the first acceptance criterion before writing any code, making sure the new test fails, and then writing just enough code to make that test pass before refactoring and then starting on the next acceptance criterion. This approach is known as behavior-driven development, and while it’s not part of the definition of pair programming, it harmonizes beautifully, along with test-driven development.
Working Together …
When you have two or more people trying to work together, the first thing they need to do is agree on a work schedule. It’s not really pairing if two developers aren’t working together at the same time. Because of this, it’s essential that the developers who plan to work together coordinate their schedules and make sure they both agree to a time and place where they will work.
One mistake I’ve seen pairs make is trying to maximize the time they work together as a pair by scheduling a full eight hours together, and sometimes trying to work together beyond that. Pairing is intensive work that requires a heightened level of focus and participation. It’s very taxing to try to pair for more than five or six hours in a day, and even that might be stretching it for even the most resilient of us. When setting up a pairing schedule, try to agree on a fixed and limited time that will fit within a typical eight-hour work day, leaving time for lunch, email, personal tasks, etc. Those personal tasks are essential to our work day, but they’re also distractions that shouldn’t be attempted during a pairing session.
It can also be socially awkward to remind your pair when the agreed pairing time has come to an end. For that reason, it can be a good idea to set an alarm that will break the news to both of you without putting the burden on one or the other.
Skill level is another area where pairs can have trouble. It’s a fair assumption that, no matter what you’re working on, the person you’re working with has a different background, experience, and comfort with the topic. Recognizing that up front is important, so neither of you will feel the need to try to hide that fact. One of the benefits of pairing is that working together naturally brings up the skills of anyone learning something new, whether that something is a programming language or a communication style.
Be gracious if you feel you’re more skilled than your pair. Treat them the way you’d want to be treated as you learned something new. And remember that the point is not only to get the work done, but to make sure that both of you have sufficient knowledge and ownership of the end result.
To that end, it’s vital that each programmer have the opportunity to sit at the keyboard and drive while the other observes and navigates through the code. The concept of taking turns may be new to anyone whose exclusive experience as a programmer has been solo work, so there will be a learning curve as you adapt to verbalizing your intentions when navigating, or carrying out someone else’s ideas when driving.
A programmer new to pairing but comfortable with the task at hand can easily get into a pattern of holding onto the driver role for as long as possible. Similarly, if you’re not driving at the keyboard and you’re not all that familiar with the code, it’s easy to find your mind wandering back to your phone, your email, and your other tasks. When that happens, you end up with one person coding alone and the other person sitting in the same room scrolling through social media.
One of the clues that a pair might be having trouble taking turns is silence. Pairing is a noisy process, involving a lot of questions, feedback, discussion, and collaboration. When a pair finds themselves going for more than a minute or two without saying a word, it’s likely the pairing has stopped.
One useful technique that can keep pairs from falling into this antipattern is to use a Pomodoro timer. These timers will keep a running countdown of the seconds as you work in 25-minute increments, and then tell you to take a break for five minutes. By switching roles between the driver and the navigator during these breaks, a pair can avoid lapsing into extended sessions with just one driver.
On One Computer …
Pairing only works when two people dedicate their full attention to a single computer. It’s better to avoid the distraction of having two (or more) active screens going during a pairing session. Even if one person just wants to look up some relevant code examples or check on the status of a background process, it’s better to do that on the one shared computer. If it’s a search, both developers can see how the search is constructed and what potential results come up. If it’s a status update, neither developer needs to be left behind.
So in any pair, both developers must be able to see the screen they are working on together clearly. One of the essential tools for pairing is a monitor big enough that both developers can see what’s being written clearly. Depending on the circumstances, this can be accomplished with a shared laptop if you don’t mind huddling together and you use a large enough font with adequate contrast. A better solution is a larger desktop or wall-mounted monitor where the code can be displayed and viewed together more comfortably.
Remote pairing is a very viable option these days. There are a number of great solutions ranging from Slack or Zoom tools to full-blown integrated development environments and text processors that support screen sharing, conference calling, or both, allowing two people on opposite sides of the desk or opposite sides of the world to work together. Even if you’re at the next seat in an open office, screen sharing can make it easier for both of you to see and interact with the code on the screen more comfortably. (I just encourage you to stay focused and resist the urge to bring up your email in a separate window while you’re pairing remotely. It’s disrespectful, it will be obvious to the person you’re pairing with, and your distraction will make you miss out on opportunities to learn together and produce quality results.)
If a colocated pair is sharing a single machine, they’ll need to come to some agreements about the configuration of their shared computers, keyboards, mouses, etc. That ergonomic keyboard with all the custom hardware macros might not be the best choice for sharing. But if you don’t mind using the same laptop or keyboard and mouse, swapping roles from navigator to driver in a pair might be as simple as switching places.
A popular and very robust solution is to make active use of a version control system like Git. Commit your code frequently to a shared repository so each developer can pull the latest version and work on their own device when they switch roles. Using version control to handle swapping in pairs has the added advantage of creating a more detailed history of code changes for future logging and potential rollbacks. If the Git logs get too cluttered, it’s always possible to go back and squash those extra commits into a single, more meaningful one before doing a pull request.
At a higher level, once you start pairing with another developer, you’re going to notice some differences in the ways you each approach your tasks. One of you might know some fancy keyboard shortcuts, have some special aliases for common shell commands, or prefer to use a specific IDE because of its unique features. In terms of the code itself, you may also each have a different implicit understanding about how variables are named, how to structure a commit message, when to use comments, etc.
Pairing is an opportunity to make these unconscious variations in technique visible so everyone can benefit from the hidden wealth of experience and knowledge about how we code more effectively.
How to Start Pairing
There’s often a period of adjustment while building the muscle memory and learning to express ideas out loud that were once just thoughts in the back of your head. It’s also necessary to establish workable logistics to allow two people to work together, which might mean making adjustments in terms of schedules, locations, and equipment. And when you’ve got that working, you might try expanding the process to the whole team with enhancements such as mob programing for groups, or promiscuous pairing to give everyone on the team a chance to pair on all of the team’s stories.
Putting in the effort to get through the learning stages usually pays off in significant improvements, both for the quality of the code and for the happiness and sustainability of the people who create it. And if your entire team or organization adopts pairing, the learning curve will become even easier for new people, improving the onboarding process and helping everyone be more productive.