At Shopify, we use pair programming to share knowledge with team members, create high-quality solutions, and have fun doing it all! By pairing, we come up with new and innovative ways of solving problems and we can refine ideas into solutions. Involving pairing in onboarding helps us bring new team members up to speed and integrate them into existing teams.
With this article, we hope to help other teams share in the benefits we’ve seen from pair programming and accelerate the spread of pair programming knowledge in the industry.
What is Pair Programming?
Pair Programming is when two people write, debug, or explore code together. It’s simple, but getting the most out of your pairing session can take some work. Pair programming is a complex practice requiring skill to master. There are many resources on pair programming, but sometimes engineers are dropped into a pairing session with little preparation and expected to just figure it out.
Pair Programming Benefits?
It’s important to understand why we pair and what we’re hoping to accomplish. Aside from making work more enjoyable (although it may take some practice), there are tangible benefits around the work itself. Pairing can:
- remove knowledge silos to increase team resiliency
- build collective code ownership
- improve learning
- increase efficiency
- improve software design
- improve software quality
- reduce the incidence of bugs
- increase satisfaction
- help with team building
- accelerate on-boarding
- serve as a short feedback loop, similar to a code review happening live
- increase safety and trust of the developers pairing
- increase developer confidence
Table of contents
- Terminology
- When Should You Pair Program?
- Pairer Combinations
- Roles
- Addressing Pitfalls
- Pairing Station
- Pair Programming Techniques
- Additional Resources
Terminology
Problem: What is being solved or explored by the pair.
Pair or 🍐:
- (noun) Either two people pair programming or the pairing partner. E.g., “The pair can try alternating roles”, “Try spending some time asking your pair about their day before you start working on the problem“.
- (verb) The act of pairing, E.g., “To pair or not to pair, that is the question.”
Pairer: A member of a pair.
Session: A stretch of time where two people are pairing. It ends when the pair splits up for longer than a short break.
Driver: The pairer at the keyboard typing. Despite what NCIS taught us, it’s not useful or practical to have more than one person typing at the same time.
Navigator (sometimes called the observer): The pairer that isn’t driving. Generally, the navigator figures out the strategy, and guides the driver in implementing that strategy. More details on this relationship later.
Development Environment/Station: The environment where the pairing is happening. At a minimum includes a desk, computer(s), keyboards, IDE. The environment also includes anything that might make the pairing session better or worse outside of the pair itself.
Solution: The approach currently being taken to either resolve the problem or explore it.
Expert: The member of the pair that is relatively more experienced or knowledgeable, especially within the particular problem domain. Not related to seniority
Novice: The member of the pair that is relatively less experienced or knowledgeable especially within the particular problem domain. Not directly related to seniority.
Disengagement: When one member of the pair isn’t focusing on the work or engaging in the pairing. This is a waste of the pairer’s time and it’s the biggest pitfall of pairing, so it needs to be avoided and/or addressed.
Watch the master: Where the expert does puts on a performance while the novice watches and doesn’t take part. This scenario lowers the novice’s satisfaction with the pairing session and the expert misses out on the key contributions from the novice. Disengagement and a break down the pairers’ relationship can follow. Sometimes watch the master is a valid mentoring approach, but it is not useful for pairing.
When Should You Pair Program?
Whenever! Pairing doesn’t need to be structured or planned. Ad hoc pairing works very effectively, especially if the pairers have already done a few sessions together. This isn’t to say that pairing should be done constantly or in every circumstance, it’s an individual decision. While some teams or pairs find full day pairing effective, others find some balance of pairing and solo work is better for them.
It’s important to understand that pairing is quite tiring. During a pairing session, the pair is always focused and keeping that intensity is exhausting. It’s great to take breaks, at least every 2 hours or so. Additionally, just because one pairer is up to keep going, doesn’t mean the other has to be.
Pairer Combinations
This is a somewhat shallow and brief breakdown of the different pair combinations, but the Dreyfus Squared model provides a more in-depth view.
Expert-Expert
Both parties are knowledgeable within the problem space.
Pros:
- Both members of the pair share knowledge and ownership of the solution increasing team resiliency
- Both members of the pair learn new things if they have different approaches
- Improved software design and quality because the review feedback loop is short
Cons:
- Can resolve the problem faster, but at the cost of more total man-hours if the pairers don’t challenge one another
- Can lead to disengagement if both experts take the same approach and lack diversity of thought, or if the problem is simple
Expert-Expert works best if both members of the pair are experts in different parts of the problem space and, in this case, expert-expert pairing is very effective.
Expert-Novice
The most traditional type of pairing, and the most beneficial in the greatest number of scenarios.
Pros:
- The novice brings insight and questions the status quo
- The expert provides mentorship and can guide the flow
Cons:
- Can lead to a watch the master scenario
Novice-Novice
This type of pairing often happens when exploring a new area or working on something unusual and involves a lot of learning and discovery. A novice-novice pair has many benefits, but also the most potential downsides.
Pros:
- Can be extremely satisfying
- Lots of learning involved
- Often leads to interesting and unique solutions
Cons:
- Can introduce and reinforce bad practices
- Can lead to the pair getting stuck and wasting time
- Can be very frustrating for the pair when they get stuck
Roles
The two roles, driver and navigator serve different purposes. It’s often not clear who does what and keeping the guidelines here in mind can be helpful.
Driver
The driver is the clearest role, because it’s the person at the keyboard. The driver is responsible for the implementation. They keep their focus on what is happening right now and interpret what the navigator is saying. It’s best if the driver doesn’t focus too much on the broader design but making sure the work they are doing is high quality and error-free.
For example, while creating a new class as directed by the navigator, the driver would focus on:
- extracting variables
- extracting private methods
- variable, method, and class names
- other local refactoring and improvements.
- method level logic
- private methods
- coding style
- running the tests
Navigator
The navigator focuses on the broader scope of the problem. Generally, the navigator will set the direction the code should go. For example, they might say something like “Maybe we can pull these shared methods into another class and pass it into the constructors”. The driver will then take this guidance and implement it into the code ensuring it’s clean and error free. The navigator is responsible for keeping the pairing on track. They ensure that rabbit holes are stepped out of in a reasonable time and new approaches are tried as old ones fail to pan out. The navigator also keeps an eye out for any errors, typos, or refactoring opportunities that crop up that the driver misses. Though this is not their primary role it’s still important. The best way to think of the navigator: they keep the plan, and keep to the plan. Some examples of how this plays out:
- keeping a list of tasks to be worked on
- prioritizing that list
- adding tangential work that is discovered to the task list
- ensuring the pair doesn’t deviate too much from the task at hand
- thinking strategically about the design
- identifying code smells or design problems
- adjust the plan/list to address the new code smells
- reviewing code as it’s written
- reminding the driver to test first
- choosing what test to write
- helping with naming
Dialogue
It’s important to note that the driver isn’t just implementing what the navigator says, they are part of a dialogue. The idea here is that the driver brings in the “low level” perspective from the code that’s in front of them and what will actually work here. Compared to the navigator, who brings in a more “bird’s eye view” and tries to imagine how what is being written now will fit in with the greater design. By switching roles with some frequency, the pair can ensure that they have a good handle on both perspectives.
Switching Roles
Switching roles while pairing is essential to the process—it’s also one of the trickiest things to do correctly. The navigator and driver have very different frames of reference. Switching roles is a massive context change when the roles are followed effectively. As such, there needs to be some care involved.
The Wrong Way
Pairing is about working together. Anything that impedes one of the pairers from contributing or breaks their flow is bad. Two of the more obvious wrong ways are to “grab the keyboard” or “push the keyboard”.
Grabbing the keyboard: Sometimes when working as the navigator it's oh so tempting to just take the keyboard control away to quickly do something. This puts the current driver in a bad position. Not only are they now not contributing, but such a forceful role change is likely to lead to conflict.
Pushing the keyboard: Other times, the driver feels a strong need to direct the strategy. It’s very tempting to just “push” the keyboard to the navigator, forcing them to take the driver’s seat, and start telling them what to do. This sudden context switch can be jarring and confusing to the unsuspecting navigator. It can lead to resentment and conflict as the navigator feels invalidated or ignored.
Finally, even a consensual role switch can be jarring and confusing if done too quickly and without structure.
The Right Way
The first step to switching roles is always to ask. The navigator needs to ask if they can grab the keyboard before doing so. The driver needs to ask if the navigator is willing to drive before starting to direct them. Sometimes, switching without asking works out but these situations are the exception.
It’s important to take some time when switching as well. Both pairers need to time to acclimatizing to their new roles. This time can be reduced somewhat by having a structure around switching (e.g. Ping-pong pairing) which allows the pairers to be mentally prepared for the switch to happen.
Addressing Pitfalls in Pairing
The greatest pitfalls to pairing are:- disengagement
- watch the master
- communication breakdown
- conflict
The first two can usually be resolved by switching the driver and navigator more often. For some ways to facilitate this, take a look in the Techniques section, specifically Ping-pong pairing and Pomodoro pairing.
In a communication breakdown scenario, where the pairers aren’t able to understand one another or feel unheard, taking a break from typing and having a discussion can help. The Digging for Gold technique (more details in the Techniques section) often works very well to get the pair through a tough spot.
Conflict between the two pairers happens sometimes. Addressing this is tricky and this post won’t get into the details, but there are many conflict resolution techniques that can be helpful. More information on resolving conflict are in the other resources section.
Pair Programming Misconceptions
Here’s a brief overview of some pair programming misconceptions.
Don’t Pair on Rote Code, Only Complex
One of the things that pair programming is great at is identifying code smells and opportunities for abstraction. Rote code is often a good source of both of these opportunities so pairing can be very effective here.
Pairing is Less Productive
As Martin Fowler points out in his blog post, pairing is meant to help with the hardest parts of programming. The entire purpose is to be more productive.
But I Don’t Like Pairing
Maybe that’s true. Possibly, it’s a matter of lack of familiarity. If you’ve tried pairing and found that it didn’t work, try a different partner, this makes a huge difference. If you feel lost or it’s still not working, try some of the techniques near the end of this article.
The Pairing Station
Before starting to pair, there should be a good space available that can facilitate and improve the pairing session.
The ideal pairing station criteria:
- supports ease of screen reading for both pairers
- makes it easy to switch the driver and navigator
- makes it easy for both of the pairers to take the driver’s seat
- creates a comfortable environment for either pairer
- allows for direct communication
- allows the pairers to communicate indirectly (e.g. visual cues)
- includes a whiteboard for discussion
- allows for in-person interaction, although remote pairing is possible if the environment can meet the above criteria.
Don’t let your environment be a barrier to pairing, if you can’t make/find a good space, ad-hoc over the shoulder pairing still works great! While meeting these criteria for the ideal pairing space is awesome, you’ll still get a lot of benefits even from pairing on a laptop at a table in the lunch area.
If you find that pairing in general isn’t working, physical environment can play a significant role. Try some of the suggestions below as these station modifications can help with a lot of pairing problems.
Screens
For in-person pairs, having two monitors mirrored allows both pairers to see the work without looking over each other’s shoulders. For remote pairs, either screen sharing or live code sharing can work effectively. While live code sharing helps with switching, it makes it difficult to track non-code work, some suggestions on how to handle this are addressed in the sections related to communication.
Switching
For in-person pairs, having two keyboards and two mice works very well when combined with two mirrored monitors.
For remote pairs using some sort of live code sharing can make it simpler to switch drivers.
Making it Easier to Switch Drivers
This is the hardest part of pairing.
For in-person pairs the keyboard(s) and mouse should be comfortable to use for both pairers. For example, if one member uses left-handed mice, the mouse they are using should work for them. Likewise, The keyboards should be in a layout that is familiar to the pair using it.
Shortcuts and productivity commands should be comfortable for both pairers. The IDE, OS, and any apps installed play a big part of this. Consider especially any developer tools like the type of shell, these have a high learning curve and can impede a driver.
The bottom line is: make sure the machine being paired on can support both pairers. Any time a pairer ends up driving because switching is too difficult, check that it isn’t because of the environment.
Remote pairs need to deal with all of the same problems as in person, on top of that they have a few remote specific problems to deal with. Having the environment local to one pairer can make it harder for both to drive. If one of the pairers needs to drive on a system that is remote to them can cause processing delays. Serious connectivity problems can kill a remote pairing session outright. Remote pairing often requires quite a bit more coordination when switching roles, this introduces additional delay which can impede the flow of work. Finally, make sure that shared resources, like local documentation or a config file, can be accessed by both parties.
IDEs
These are a constant problem and can cause a lot of tension for the pair. The machine being used should always be able to accommodate the lowest common denominator. As an example, I’m not proficient in Emacs and only a little capable with Vim. If asked to pair on a machine with Emacs/Vim I would struggle to drive. Many modern IDEs like RubyMine, VSCode, Atom, etc. are much simpler to use and have a lower bar for entry. They also generally have Vim plugins, can quickly switch configurations, and have functionality lookups. It’s OK to switch IDEs when the driver switches, but it’s less than ideal because switching is less fluid.
Physically Comfortable
The area both the pairers are working in should be comfortable. When working in person, both pairers should have the same amount of physical space, especially when driving. For example, curved corner desks can create a situation where one person is uncomfortably situated or has less space available to them and a small desk that’s enough for one person is usually uncomfortable for two people to sit at. Remember to take into account all the normal considerations for comfort and accessibility in the workplace. Similarly, when remote pairing, both pairers need to be physically comfortable, for example, we can’t have one (or both) pairers cramped in a phone booth.
Direct Communication
The pair needs to be able to communicate directly, often verbally. If one or both of the pairers is a person with a disability that prevents verbal communication, modify for other forms of communication. The goal is to be able to keep a constant dialogue going.
The pairers need to be able to hear each other implying that the work environment allows for discussions and open communication, or the pair requires their own room. Especially when working remotely, both pairers need to be speaking loudly enough to hear one another.
I Don’t Like Talking
It can be intimidating to think that you’ll be having a constant dialogue with someone. There are ways to make it easier to do while pairing. The first is the structure of pairing itself, the roles help smooth communication between individuals. When taking on a role there are guidelines on what to talk about and when in both the Roles section and in specific Techniques. The second is trying some of the techniques that are useful for pairing. These give you frameworks on when to switch roles, what kind of questions to ask, and even how to get over communication blockages.
Language Barriers
Sometimes, the pairers don’t natively speak the same language. This is a pretty significant barrier to pairing and can cause some people to shy away from it. Whenever you feel that your pair hasn’t understood you, don’t forge on ahead. Spend some time clarifying what they’ve understood and defining things they don’t understand. Not only will this improve your pairing but it can help strength language skills in both pairers!
Indirect Communication
A large part of communication is not direct and triggered through subtle cues. If one or both of the pairers is visually impaired modify the recommendations for other indirect cues.
For in-person pairs they need to be able to see each other well enough to pick up on visual cues. For remote pairs, they need to be able to see each other while screen sharing.
Whiteboard
Having a whiteboard or some paper to draw on can help facilitate discussion immensely.
For in-person pairs, an actual whiteboard or some paper works well.
For remote pairs, a piece of paper with the camera trained on it, or even us a virtual whiteboard.
Pair Programming Techniques
There are different techniques that a pair can try when pairing to improve the experience or learn something new. Some of these techniques can work in tandem, while others are mutually exclusive. Picking a technique depends on who the members of the pair are and how they work together.
Perform a Prospective
Spend some time before pairing talking about things not related to the problem at hand. This can set the tone for the session and make everyone feel comfortable. You might also discuss any action items you want to address during the session that aren’t part of the task directly.
Possible Action Items
- Investigate action items from the Retrospective of the last pairing session
- Define learning goals (e.g. I want to learn TDD, I want to keep track of what refactorings we use)
- Evaluate techniques or pairing styles you may use
- Define switching cadence
- Examine the pairing station
Ping-pong Pairing
This is a pairing technique derived from Test Driven Development’s (TDD) red→green→refactor
loop. It works best if one or both of the pairers are familiar with TDD but can also be a learning opportunity in the novice-novice combination. This technique is also useful when two experts are pairing or when dealing with a particularly challenging problem. Finally, this is a great way to learn or improve TDD skills.
How Does it Work?
We’ll call one pairer left and the other right. The steps to this technique:
-
Red →
left starts off driving by writing a failing test that tests just one isolatable part of the solution, right navigates by talking left through what the test should test and makes sure they follow the three rules of TDD -
Green →
right picks up the driver’s seat and writes the implementation that passes the test, left navigates them through this and makes sure they follow the three rules of TDD -
Refactor →
right continues in the driver’s seat and refactors both the production and test code, left keeps the broader picture in mind and navigates the refactor - The pair starts again but this time right is the driver and writes the test and left is navigating, they then switch so that left writes the implementation
Pomodoro Pairing
This is a technique based off of the pomodoro technique. It helps to resolve a watch the master situation or ,more generally, in an expert-novice pair by giving the novice in the pair enough time in both roles to feel comfortable and get into a flow.
What is the Pomodoro Technique?
This is a quick breakdown of the pomodoro technique, not pomodoro pairing.
- Pick a task
- Start a 25 min timer (this is a pomodoro)
- Work until the timer rings or you’ve completed the given task
- Take a 5 min break where you spend time not thinking about work (no emails or Repeat
- After your fourth pomodoro take a 35 min break
- Start again
This leads to ~2.5 hours per cycle. Along the way jot down the following:
- what task a given pomodoro is for
- “hard” interruptions (anything that completely takes your attention away from the given task) usually denoted with a -on a piece of paper
- “soft” interruptions (brief internal distractions) usually denoted with a . on a piece of paper
If there are enough interruptions, restart the pomodoro (usually without a break)
How to Apply The Pomodoro Technique in Pairing?
We’ll call one pairer left and the other right. The steps to this technique:
- Start a pomodoro
- For this pomodoro left is the driver and right is the navigator
- Take the 5 min break, step away from the pair and do something individually
- Start another pomodoro
- For this pomodoro right is the driver and left is the navigator
It’s ok to sometimes switch roles within the pomodoro but each of the pairers should stick to the given role for the majority of the pomodoro. During the pomodoros keep track of the same things mentioned in the pomodoro technique.
Strong Style
For an idea to go from your head into the computer it *must* go through someone else’s hands - Llewellyn Falco
In the Strong Style technique, the navigator has some idea how they want the solution to look. The driver drives (as described in roles) and any time the driver has an idea they want to try out, the roles switch.
Digging for Gold
Sometimes one of the pairers will have a hard time listening to the other. They might feel that the other pairer's ideas don’t have merit or are lacking expertise. In these cases it’s useful for the pairer that’s having trouble finding value in the pair to try digging for gold. This technique is also useful when the pair is stuck and can’t find a way forward.
How to Dig for Gold?
One of the pairers makes a naive or impractical suggestion for moving forward. The pair then takes this idea and looks for divergent ideas that could help solve the problem. The pair explores this solution, and divergent solutions until they’ve either found one that works or they feel they’ve found all the gold there is. If you end up in a rabbit hole, recall the problem you’re trying to solve and bring the pair’s attention back to it.
Perform a Retrospective
Spend some time reflecting on the pairing session. This can be helpful by allowing the pair to clear the air of any tension or issues that came up during the session. It can also be helpful in addressing any slow downs and improving flow, allows the pair to set a learning goal for next time, and to reflect on this session’s learning goals. Finally, it’s a good way to celebrate wins as well and leave the pair with everyone feeling a sense of forward progress.
When using the Pomodoro Technique, reflect on the number of distractions, what needs to improve?
Questions to Ask
- “Do you feel that this was a balanced pairing session?”
- “How can we improve our station?”
- “How do you feel after our session?”
- “What did you learn/teach during our session?”
- “How do you feel about the progress we made?”
- “How did you feel about the length of the session?”
- “Is there anything that stood out to you during our pairing?”
Don’t Rush
When one of the pairers moves forward too quickly, it’s good for them to check in with their pair before forging ahead. Pairing requires that both members of the pair are on the same page and understand what’s happening.
Tips
- “Do you know where I’m going with this?”
- “What do you think of moving along with this solution“
- Step back and don’t write code for a while, discuss what you’ll be doing instead.
- Don’t “just try this one thing” before explaining what you’re doing
Additional Resources
Here are some other great resources to learn more about Pair Programming!
Pairer Combinations
Communication and conflict resolution
Techniques
Other
We’re always looking for awesome people of all backgrounds and experiences to join our team. Visit our Engineering career page to find out what we’re working on.