Benji's Blog

Pair Programming

There was a thread about pair programming on the London Java Community mailing list last week. I tried to contribute to the discussion there, but the mailing list doesn’t receive my replies. So I’ll post my thoughts here instead.

I have been pair programming most days in an XP team for the past 3 years. These are some of my experiences/thoughts. Obviously I enjoy pairing or I wouldn’t still be doing it, so I am biased. This is all entirely anecdotal (based on my experience).

Why work in pairs?

Code reviews are terrible

A common “alternative” to pairing is code reviews. One of the reasons I like pairing is that it fixes the problems I have experienced with code reviews.

Code reviews are commonly implemented with flaws including

  1. The feedback cycle is long

    A developer may work on a change for a day or two before submitting code for a review.

    This means they have invested a considerable amount of time and effort into a particular approach, which makes it hard not to take criticism personally.

    It can also waste a lot of time re-doing changes, or worse – leads to the temptation to let design issues slip through the code review because going back and re-doing the work would be too costly.

  2. Focus on micro code quality

    Sometimes only a diff is reviewed. This seems to promote nitpicking about formatting, naming conventions, guard clauses vs indentation and so on.

    These issues may be important, but I feel they’re less so than the affect of the changes on the design of the system as a whole. Does the changeset introduce more complexity into the model, or simplify it? Does it provide more insight into the model that suggests any significant refactorings?

    I find that pairing – when implemented well, can avoid these problems. The feedback loop couldn’t be any tighter, as your pair is right there with you as you write the code. The navigator is free to consider the bigger picture affect of the changes.

It’s social

Programming can be isolating. You sit in a room all day staring at a computer screen. With pair programming you get to write code all day and still talk to people at the same time.

It is faster

It can often seem slower than working alone, but in my experience timing tasks it actually ends up taking less time when pairing. Its easy to underestimate how long you can be blocked on small problems when working alone which doesn’t happen as often when pairing. Pairing also keeps you focused and stops you getting distracted by IRC or news sites.

It produces higher quality code

A lot of defects get noticed by the navigator that would have slipped through to a later stage. The temptation to take shortcuts or not bother with a refactoring is reduced because you’re immediately accountable to your pair. The caveat to this is that conceptual purity can be reduced by rotation.

How to pair well

Share the roles, swap regularly and be flexible

No-one likes to sit and watch while someone else types for hours on end. If you hog the keyboard, then your pair may lose concentration or not follow what is going on. Swapping roles helps to remain focused, and provides a change. It’s sometimes easier to swap roles when the navigator has an idea they want to explore or a suggestion that’s quicker to communicate through code than verbally.

Use with TDD.

TDD provides a natural rhythm that helps pairing. If you find that one person is driving too much then one way of restoring the natural rhythm is for one half of the pair to write a test, and the other to implement, and swap again for each refactoring stage. Its best to be flexible, not stick to this rigidly. Sometimes it makes sense to write two or three testcases at once rather than limiting yourself to one, while you’re discussing possible states/inputs.

TDD also helps to do just enough generalisation. When working in a pair it can be easy to talk yourself into doing unnecessary and unhelpful work to make an implementation ever more general and abstract. I find that often, when someone suggests a more general interface to enable potential future re-use, it turns out to never be used again. Abstraction for the sake of abstraction can also make the intent of the code less clear.

TDD’s Red/Green/Refactor stages help to refactor for immediately valuable re-use within the existing codebase, but the act of writing tests for features you don’t actually need helps you to consider carefully whether it really is worthwhile.

Communicate constantly

You need to be constantly talking about what you’re doing. Questioning and validating your approach, considering corner cases etc.

Rotate regularly

Swapping pairing partners regularly helps to share the knowledge of how things are implemented around the team. Rotation also often provides further incentive to improve the implementation, as a fresh set of eyes will see new issues, that the pair had been blind to. It also means you’re less likely to get fed up with working so closely with the same person for an extended period of time.

On more complex and or longer tasks, it can be useful for one person to remain working on the same task for 2 or 3 days, to ensure there is some continuity despite the rotation.

Use with shared ownership

Pairing enforces shared ownership as there’s never just one person who has worked on a particular feature. In order to rotate pairing partners, everyone needs to be free to work on any part of the codebase, regardless of who it was written by.

When not to pair

When spiking a solution

Pairing works well to ensure that a feature is implemented to a high standard, when both people have a reasonable idea how to go about implementing it. It is not good for exploring ways to implement something that is unfamiliar. It’s easier to find a solution to an unknown problem when working alone, where you can concentrate intensely and have uninterrupted thought. This does mean you need to break down tasks into an initial spike step, and a second implementation step.

When trying out new things

It’s important to have time when not pairing to allow for innovation and explore unconstrained ideas. Otherwise you can end up with groupthink, and constantly play it safe, using techniques that everyone has used before, and know work.

On trivial changes

Having two people work on making copy changes is probably a waste of resources. Deciding where to draw the line is tricky. I think if the change needs more than a couple of tests it is a good idea to pair on it.

If it’s unworkable for your team

There are lots of contexts in which pairing is simply not possible. e.g. Distributed teams in different timezones. Open source projects with sporadic contribution from a large number of people.

If you don’t enjoy it

Pairing is hard work, it’s certainly not for everyone.

It’s tiring

You have to be alert for long periods of time. You can’t drift off or distract yourself in the middle of a pairing session in the same way that you would when working alone.

It requires patience

It can often feel like progress is slower than it would be when working alone. If you’re not driving, it can be frustrating seeing people failing to use keyboard shortcuts or type slowly. If you are driving then you have to slow yourself down to constantly discuss what you’re doing and why.

It can reduce conceptual purity

This is more rotation than pairing itself – when one person has implemented a feature, you can often see a single vision for that feature when reading the code. Some of this seems to be lost with regular rotation. Just like a novel would be slightly odd if each chapter was written by a different author.

It can stop you doing things you want to do

It can be enjoyable having freedom to divert and work on things you feel important that aren’t really relevant to the task at hand. This tends to happen less when pairing because you’d both have to see the diversion as important.

There can be personality clashes

Is pairing worthwhile?

This comes up in any discussion on pairing. Having two developers working on a problem doubles the cost. Wouldn’t they have to work at double the speed in order for pairing to make sense?

Well, no.

Most of the cost of a feature occurs after it has been developed. In support/maintenance/resistance to future change etc. Any improvements you can make at the point of development to reduce defects, and make it easier to maintain the software in the future should yield big benefits in the future.

Then there’s other benefits to the team.

Summary