A guide to pair programming: a top software development method

Pair programming is a software development technique where two programmers work together at one workstation. It’s a dialogue between two people simultaneously programming (as well as analyzing, designing and testing) while trying to program better. One programmer, known as the "driver," writes the code, while the other, the "observer" or "navigator," reviews each line of code as it is written. The two programmers switch roles frequently for the most effective collaboration. As studies show, this approach leads to improved code quality, accelerated learning among team members, and better problem-solving.

The concept of two (or more) programmers working together on a single problem dates back to the 1950s, to the times of punch card computers where the cost of error in a program was ridiculously high. At the time, two or more engineers often worked together on writing one program which was then punched into the cards and fed to the machine. Later in the 1980s, computers started becoming more and more affordable, and an individualistic approach to problem solving evolved.

However, some engineers still saw the benefits of working together. One such engineer was Kent Beck. In the 1990s, the software developer and author introduced the concept of pair programming as part of Extreme Programming (XP) in his book, Extreme Programming Explained. Extreme Programming emphasizes customer satisfaction and promotes engineering practices that improve the quality of software. Pair programming was one of the original 12 practices of XP, and it has since been adopted in various forms by many software development teams.

Later on, studies proving the efficiency of pair programming began to emerge. In 1998, a study by Temple University professor John Nosek showed that while the pair programmers spent 60% more time on the task, the work was completed in 40% less time compared to individuals. Working in tandem was not only more efficient, it also produced higher quality algorithms and code.

Since then, pair programming has become more and more prominent in teams with engineering-centric culture.

Table of contents

How does pair programming work?

Driver-navigator system

In the driver-navigator system of pair programming, the driver is responsible for actively writing the code, while the navigator reviews the code, thinks strategically, and suggests changes or improvements. The navigator may also look up documentation or consider the broader architecture of the application. The roles are not rigid and are often switched between the pair programmers to keep the session engaging and to balance the workload.

Let's say Alice and Bob are working on implementing a new feature that involves sorting a list of items based on user preferences. Alice starts as the driver and begins writing the sorting function. Bob, as the navigator, reviews each line of code and suggests using a more efficient sorting algorithm that he recently read about. After implementing the sorting function, they switch roles. Now, Bob writes the code to integrate this function into the user interface, while Alice navigates, ensuring that the function is called correctly and that the sorted list is displayed to the user.

Ping-pong style

Ping-pong pair programming is a more structured approach where roles are switched in a rhythmic manner, often triggered by specific events. For example, one programmer writes a failing unit test, and then the other must write the code to make the test pass. Once the test passes, they switch roles, and the cycle continues. This approach encourages both programmers to engage equally and keeps the session dynamic. It also ensures that both the testing and coding aspects are given due attention.

Unstructured style

In contrast, the unstructured style of pair programming is more fluid, with no set rules for when to switch roles. Programmers change roles whenever they feel it's necessary or when one person has a particular insight into the current task. This approach offers more flexibility but may lead to one programmer dominating the session, especially when pairing junior developers with more senior teammates.

Each of these styles has its own set of advantages and disadvantages, and the best approach often depends on the team's dynamics, the complexity of the task, and the experience levels of the programmers involved.

Remote pair programming

With the rise of remote work and distributed teams, especially accelerated by events like the COVID-19 pandemic, remote pair programming has gained prominence. It allows developers to collaborate in real-time, from anywhere with an internet connection, thereby expanding the pool of available talent and expertise. Remote pair programming aims to emulate the benefits of traditional, co-located pair programming but requires additional tools and practices to bridge the physical gap between participants.

Tools and methods for remote pair programming

  • Shared desktops and remote desktop control: Unlike basic screen sharing which only provides view-access, software like TeamViewer or AnyDesk allows one programmer to control their teammate’s desktop remotely. This is particularly useful for switching roles between the driver and the navigator without having to transfer files or change settings.
  • Code sharing plugins: Integrated Development Environment (IDE) plugins like Live Share for Visual Studio Code or Code With Me for IntelliJ IDEA enable multiple developers to work on the same codebase simultaneously. These plugins often come with features like shared debugging and terminals.
  • Version control systems: Tools like Git can be used in conjunction with branching strategies to allow both programmers to work on separate tasks and then merge their changes seamlessly during the paired session.
  • Communication tools: High-quality audio and video conferencing tools are essential for effective communication. Some teams also use chat applications for quick text-based interactions.
  • Timers: When using styles like ping-pong programming, timers can be useful to signal when it's time to switch roles. Some pair programming-specific tools even have built-in timers for this purpose.
  • Documentation tools: Shared documents or wikis can be useful for keeping track of decisions made, problems encountered, or ideas for future implementation.
  • Virtual whiteboards: For brainstorming and high-level design, virtual whiteboards like Miro or MURAL can be invaluable.
  • VPN and security tools: When working remotely, secure connections are essential. VPNs and other security tools can help ensure that the codebase remains secure.

By combining these tools and methods, remote pair programming can be as effective as its traditional, co-located counterpart. However, it's crucial to remember that the most important element in making remote pair programming work is clear and open communication between the participants. To achieve this, both pair programmers need to be active, open to feedback, and supportive of their teammate. Above all, pair programmers must trust each other and be able to listen without interrupting their partner.

Types of pair programming pairs

Pair programming isn't a one-size-fits-all approach; the effectiveness of the practice can vary depending on the pairing of developers. Here are some common types of pairings and scenarios where each might be beneficial:

Expert/expert pairs

Expert/expert pairs are beneficial for tackling complex, high-stakes programming tasks that require deep domain knowledge or expertise in a particular technology. These could include performance optimizations, architectural decisions, or implementing critical algorithms.

Tasks well-suited to expert/expert pairs include:

  • Designing the architecture for a new system or feature
  • Debugging complex issues that have stumped other team members
  • Performance tuning and optimization

Novice/novice pairs

Novice/novice pairs are beneficial for onboarding new team members or when the task at hand is relatively straightforward but still offers a learning opportunity. This pairing allows novices to learn together and share knowledge, reducing the intimidation factor and encouraging open discussion.

Tasks well-suited to novice/novice pairs include:

  • Implementing well-defined, smaller features
  • Writing unit tests for existing code
  • Bug fixes that don't require deep domain knowledge

Expert/novice Pairs

Expert/novice pairings are beneficial for knowledge transfer and mentorship. The novice gains hands-on experience and learns best practices, while the expert can gain new perspectives and the satisfaction of teaching.

Tasks well-suited to expert/novice pairs include:

  • Refactoring code
  • Implementing features that require domain-specific knowledge
  • Code reviews for educational purposes

To determine the idea type of pair for programming tasks, consider the complexity, learning opportunities, time sensitivity, team dynamics, and project phase.

  1. Complexity: For complex tasks requiring deep expertise, an expert/expert pair is often the best choice.
  2. Learning opportunities: If the primary goal is education and onboarding, a novice/novice or expert/novice pair would be more appropriate.
  3. Time sensitivity: If a task is time-sensitive, pairing two experts may expedite the process, but the trade-off could be a missed educational opportunity for less experienced team members.
  4. Team dynamics: Consider the personalities and communication styles of the individuals. Some people may work better in certain pairings than others.
  5. Project phase: Early stages of a project may benefit from expert/expert pairs for architectural decisions, while later stages might be more about feature implementation and bug fixing, which could be well-suited for novice/novice or expert/novice pairs.

By carefully considering the type of task and the goals of the pairing, teams can make more informed decisions about which pairing would be most effective for a given situation.

Benefits of pair programming

Pair programming offers a range of benefits that go beyond simply producing code. Here are some of the top advantages.

Knowledge sharing

One of the most immediate benefits is the sharing of knowledge between team members. Whether it's domain expertise, coding best practices, or familiarity with a particular technology stack, pair programming facilitates a direct transfer of knowledge that might otherwise require formal training or take much longer to disseminate through a team.

Better code quality

Pair programming often results in higher-quality code. Having two sets of eyes on each line of code minimizes the chances of errors and encourages best practices. Studies, such as the one by Alistair Cockburn and Laurie Williams, have shown that the code produced by pair programming has fewer defects.

Improved team connection

Pair programming fosters better communication and collaboration among team members. It breaks down silos of knowledge and responsibility, making the team more cohesive and aligned. This improved connection can lead to a more positive work environment and better team dynamics.

Mentoring opportunities

Pair programming naturally creates a setting for mentoring, especially in expert/novice pairs. More experienced developers can guide less experienced ones, providing real-time feedback and hands-on training. This can be particularly beneficial for onboarding new hires or helping team members grow in their roles.

Faster problem solving

Two heads are often better than one when it comes to problem solving. Pair programming allows for real-time code reviews and brainstorming, which can lead to more efficient solutions. It also minimizes the chances of getting stuck on a problem, as the pair can bounce ideas off each other.

Enhanced focus

Having a partner can help maintain focus and discipline. It's easier to avoid distractions like social media or irrelevant tasks when someone else is relying on you for their productivity as well.

Psychological safety

Working in pairs can create a sense of psychological safety, as developers know they have someone to rely on for immediate feedback and assistance. This can lead to a more open exchange of ideas and a willingness to take calculated risks, which can be beneficial for innovation.

Skill diversification

Pair programming exposes developers to different approaches and techniques, helping them become more versatile. For example, a backend developer paired with a frontend developer may gain insights into user experience considerations that they might not encounter otherwise.

By understanding and leveraging these benefits, teams can make the most out of their pair programming efforts, leading to not only better code but also a more engaged, skilled, and cohesive team.

Pair programming challenges

While pair programming offers numerous benefits, it's not without its challenges. Here are some common pitfalls and how they can impact the effectiveness of pair programming.

Mismatched pairs

Two common mismatch mistakes are assigning a novice/novice pair to a complex problem or creating expert/novice pairs without first establishing a foundation of trust.

While novice/novice pairs can be beneficial for simpler tasks, placing two inexperienced developers on a complex problem can lead to poor solutions and a lot of wasted time.

Expert/novice pairs are a great way to help junior developers learn from senior developers. However, if the expert does not trust the novice’s capabilities or vice versa, the pair may struggle with effective collaboration. This can result in one person dominating the session, defeating the purpose of pair programming.

Remote work challenges

Technical Issues like poor internet connectivity, software glitches, or hardware issues can disrupt the flow of a remote pair programming session. Time zones can also be a significant hurdle for distributed teams as differing time zones can make scheduling pair programming sessions a logistical challenge.

Cost and time

Due to the initial slowdown when implementing pair programming, the practice often appears to be twice as expensive because it involves two developers working on the same task. While the long-term benefits often outweigh the costs, the initial investment can be a concern for some stakeholders.

Overhead costs are a related concern as switching roles, setting up the environment, and other administrative tasks can add overhead time to the development process.

Communication barriers

Language and cultural differences, especially in remote or diverse teams, can impede effective communication. For example, in some cultures it may be difficult for a junior developer to feel comfortable providing negative feedback to an elder or senior developer.

Personality conflicts are a potential issue as well. Personality clashes or differing communication styles can make pair programming less effective and may even lead to conflicts within the team.

Fatigue and burnout

The constant interaction and need for focus in pair programming can be mentally exhausting, leading to quicker burnout if not managed carefully. Most programmers can’t pair for more than a few hours a day. In fact, a Microsoft study revealed that stress levels start rising after two hours in video meetings.

Lack of alone time is a concern because some developers thrive in solitude and may find the constant interaction of pair programming draining.

Skill stagnation

There's a risk that less experienced developers may become too reliant on their more experienced partners, leading to skill stagnation.

Understanding these challenges allows teams to take proactive steps to mitigate them, such as setting clear guidelines, choosing pairs wisely, and providing the necessary tools and training to facilitate effective pair programming.

Pair programming best practices

Social dynamics

  • Be an active observer: When in the navigator role, stay engaged. Provide continuous feedback and think ahead about the next steps.
  • Don't Get Distracted: Avoid distractions like your phone or other tasks. Your focus should be on the code and your partner. One useful technique I've used a lot is Pomodoro which involves breaking work into intervals of focused time, usually 25 minutes, separated by short breaks. It is easy to focus for a short period of time, and then have a planned break.
  • Build rapport: Take some time to get to know your partner. A good working relationship makes for a more effective pair programming session.
  • Don't ignore social cues: Pay attention to your partner's body language and verbal cues. If they seem confused or disengaged, address it openly.
  • Celebrate wins together: Successfully debugging a tricky issue or implementing a complex feature is a win for both of you. Take a moment to celebrate these achievements.
  • Don't blame each other for mistakes: Mistakes are an inevitable part of the development process. Use them as learning opportunities rather than assigning blame. Studies prove that blaming for mistakes inhibits learning.
  • Avoid micromanaging: Offer valuable insights and suggestions rather than dictating every mouse click and keyboard stroke.
  • Don't be overbearing: There's a fine line between being a good navigator and being an unwelcome backseat driver. Offer guidance, not commands.

Tools and process

  • Use version control: Always use a version control system like Git to manage your codebase. This makes it easier to collaborate and resolve conflicts.
  • Don't ignore branching strategies: Avoid working directly on the main branch. Use feature branches or other branching strategies to keep the codebase clean and manageable.
  • Set up a shared environment: Use tools like Live Share for Visual Studio Code or Code With Me for IntelliJ IDEA to create a shared coding environment.
  • Don't neglect audio/video tools: If you're working remotely, don't rely solely on text-based communication. Use high-quality audio and video tools to facilitate better interaction.
  • Use timers for role switching: If you're following a structured approach like ping-pong programming, use timers to remind you when to switch roles.
  • Don't stick to one role: Avoid getting stuck in one role for too long. Regularly switch between driver and navigator to keep the session dynamic and engaging.

When done thoughtfully, pair programming is a useful practice

Pair programming has proven to be a valuable approach for software development teams. By fostering real-time collaboration, it offers a multitude of benefits ranging from improved code quality and knowledge sharing to enhanced team dynamics and mentoring opportunities. While the practice comes with its own set of challenges, such as mismatched pairs and the complexities of remote work, these can often be mitigated through careful planning and open communication.

Whether you're an expert looking to share your knowledge, a novice eager to learn, or somewhere in between, pair programming offers a framework for mutual growth and improved code quality. By adhering to best practices and being mindful of the potential pitfalls, teams can harness the full potential of pair programming to create better software and stronger developers.

So, the next time you're faced with a challenging task or a learning opportunity, consider pairing up. The benefits of pair programming are likely to extend far beyond the immediate code at hand, enriching both your team's capabilities and your own professional development.

If you work remotely and want to start pair programming with a good book, read Practical Remote Pair Programming: Best practices, tips, and techniques for collaborating productively with distributed development teams.

References: