Pair Programming is a holistic endeavor. Taken in isolation it is a targeted tool for untangling hairy problems and improving code quality. But if you focus on pairing effectively and bringing in complementary processes I hope you’ll find the whole is greater than the sum of the parts. Far from being something to tolerate or use occasionally, pairing can become your default way of working and your team will produce better quality code, faster, and feel happier, than teams who do not pair.
Early in my career I was working with a small team of developers on a large commercial software project. We’d been at it for years, toiling away. We each had our own plot of land. A precious paddock we tilled, sowed and harvested year in, year out. Occasionally we’d saunter up to the boundary and have a look around, offer a helping hand. I think perhaps my neighbor used a different sort of plow? He had plenty of crops, but his rows weren’t straight. I pointed it out, but… I dunno. I guess different people have a different tolerance for that sort of thing. My plot was much more comfortable, despite the occasional rock in the field.
One day some strangers turned up. They were here to help, they said. At first we thought this was fantastic. We gave them each a small patch to tend, some seed to get started, and as much advice as we could. But they didn’t know how to work the land. They kept talking about tractors and combine harvesters. ‘Won’t work here’, we told them. ‘Too many rocks’.
To be fair, they had a good crack at it. But too much time digging out rocks maybe. Not enough time tending the crops. Pests attacked. Far too many bugs to handle. We tried to step in and help, and to their credit they did try to learn our ways. But we didn’t have time to teach them, assign them work, assess their work and tend to our own plots. It just wasn’t working out. Far from being a help, the extra hands actually made things harder.
Finally, in desperation, the land-owner called a meeting in his office. “This isn’t working,” he told us. “I want you to try pair programming.”
“Try what now?” we asked, aghast!
“Pair. Programming. Google it.”
We did. It didn’t help. There is a definite structure to most pair programming articles out there. You start by claiming the practice is controversial. Next you state the supposed benefits and perhaps quote some research, which is hard to find, so you point that out. Then you list the pros and the cons. Finally you wrap up by re-iterating that pair programming is ‘not for everyone’.
This is not that article. This is the article I wish I’d had all those years ago, when each of us was assigned a pair and sent back out onto the land to make the most of it.
The advice in this article assumes you are working in a team that can commit to at least three working pairs. A typical team might consist of six engineers, a team lead and perhaps cross-functional roles like a tester, designer or product manager.
This may work with larger teams. I haven’t personally tried. If you do, let me know how it turns out! In smaller teams it will be a strain to make it work smoothly. The limited combination of pairs will reduce some of the benefits and constrain your productivity.
As a team, agree on when you will be pairing and what you will be doing when not pairing. In many of my teams we went all-in and decided we would only write production code while pairing. This required a rigid schedule to maximize pairing time. Pairing started right after stand-up around 9:15am. At 12:00pm we all took an entire hour for lunch then resumed pairing from 1:00pm until 5:00pm. At 5:00 we considered we had put in a solid day’s effort and all went home. In other teams we were less extreme and set pairing hours between 10:00pm and 4:00pm.
You probably have heard that there are two roles when pairing — the ‘driver’ and the ‘navigator’. The driver types, the navigator keeps an eye out for issues and thinks through the design.
In order to keep both pairs engaged the driver and navigator need to swap roles frequently. One extremely effective way of achieving this, while simultaneously boosting your software quality, is to apply test-driven-development [TDD] and play ‘test ping pong’.
First I will write a test and you will make it pass. Then you write a test and I will make it pass. Not only does this achieve the goal keeping both pairs of hands continuously on the keyboard, it helps you keep each other honest when it comes to writing the tests first.
Don’t spend all your time just playing ping-pong. The discussion about which test to write next, or how to implement your current task, is critical and may take up as much time as the actual implementation, if not more. Pair Programming is also known as ‘pairing out loud’ and continuous discussion is a sign that it’s working.
Pair programming stands in for your review process, so you don’t need to raise pull-requests for the purposes of reviewing code within your team. But why stop there? I personally would recommend you drop feature branches entirely and embrace trunk-based-development. Describing how to do this safely and effectively requires an entire article of it’s own. I hope one day to share my own experiences, but for now I’ll just leave this link here.
You can pair without trunk based development. For example, by committing regularly back to a feature-branch. But continuous-integration has some fantastic benefits and a strong synchronicity with pair programming. It would be like eating cake without the frosting.
Within your team try to change up the pairs every couple of days. One person leaves the task, another joins. Try to get a good rotation across all the tasks in flight. This keeps things interesting, irons out knowledge silos, accelerates knowledge transfer and avoids people getting stuck on the same task for extended periods of time. I also cover this in my previous article on building sustainable pace.
Two days is based upon experimentation. Less than two days is disruptive to the flow of the work. More than two days and you start to lose or lessen the benefits of rotating.
“Spikes”, technical investigations, performance investigations, incident response, documentation and bathroom breaks are all examples of tasks that do not necessarily need to be paired on. If you have an odd person out, perhaps due to leave or just team numbers, these are good tasks for them to pick up.
An alternative is that you can still assign a ‘pair’ to some tasks but have them spend their time independently, checking back in two or three times a day. The benefit of this approach is that it still fits into the overall team flow without leaving another individual working solo.
Most tasks benefit from pairing, including relatively mundane tasks. It is common for experienced teams to start feeling that certain tasks such as adding a cookie-cutter REST end-point or some basic CRUD operations could be done more efficiently without pairing. This may be true if talking purely about speed of implementation but there are other benefits to pairing beside velocity, such efficient code review and sharing exposure to all parts of the code base.
Every time we broke our own rule and let a single person work through a ‘trivial’ task on their own, they invariably went on holiday shortly after finishing it. Then we found a bug (and defects hitting production were incredibly rare in our pair programming teams), and they weren’t there, and fixing the thing took far longer than it should have.
This happened every time we let someone finish a task on their own. It made me suspicious. I came to believe it was not a coincidence. Even an individual applying TDD and having their code reviewed will make more implementation mistakes, and have them slip through, than a pair.
In most of my teams, when working solo we would pull someone else over every few commits to talk through the code before pushing. We preferred the inclusiveness and immediacy of this approach over pull-requests. It does mean you are ‘bothering’ another pair quite frequently, but it is also worth noting that pairs are more immune than individuals to interruption. This is because someone can keep typing while their pair is briefly pulled aside. This approach felt like it achieved a better outcome than a pull request. The balance between not blocking the committer and not completely disrupting the reviewer worked well for us.
If you have the luxury of multiple product development teams, do consider swapping team members across them as well. If all your software teams are pairing there is very little overhead to short-term, temporary swaps between teams. The team members swapping join in the pairing and task rotation allowing them to get up to speed and contribute very quickly. If we’re baking a cake, and no-one has licked off the frosting, adding teams swaps is like mirror glaze and tempered chocolate curls. All the benefits you get pairing within your team are magnified when you occasionally pair outside it.
The ideal pairing setup is two keyboards, two mice and two mirrored monitors plugged into the same machine. This eliminates all friction swapping driver/navigator roles. If you can’t have mirrored monitors the next best solution is still two mice and two keyboards and position your single monitor directly between the pair.
GitHub has support for multiple authors, which is useful if you care about tracking individual contributions. If you do not, you can overload the git username and email configuration options. If you scratch around, there are plenty of git aliases to help you do this.
For example, at one company we had a home-grown script ‘git su’, as in switch-user. If Margaret Chan and myself were pairing we would start our session by typing ‘git su sg mc’. This would set the username to be “Margaret Chan and Simon Gerber” and the email-address as “[email protected]”
In order to reduce friction as pairs swap around, having a standardized operating environment is really helpful. Not absolutely necessary, but definitely helpful.
Try to keep the environment as minimal as possible and prefer to use tools like docker for running build dependencies such as databases. Otherwise you run the risk of a ‘runaway SOE’ that becomes the superset of every build-dependency of every project for every team. Maintaining this is overhead you probably do not want or need.
Lightweight configuration management tools like Ansible are your friend, here.
You will often find while pairing that you both get stuck. You might need to look up how something is done in a particular framework — or you’re struggling your way through a task and can’t shake the feeling that, “surely someone out there on the internet has a better solution.” For these and many other reasons you will always find it useful to keep a spare laptop nearby.
It is perfectly acceptable while pairing for someone to say, “I think there could be a better way. Do you mind if I do a spot of research?” Of course if you’re doing this all the time you’re not actually pairing, but lowering the barrier to a quick breakout without someone needing to take over the shared screen is a powerful tool.
When you pair for the bulk of your day there are things that just happen. Immediate, inescapable side-effects. Things you cannot work around. Things you will either come to terms with, or you won’t.
You do not have the opportunity to check your work email, let alone your personal email, or Slack, or your choice of social media. This is probably a Good Thing for your overall productivity even though it might hurt for a while.
You cannot work closely for any extended length of time without picking up on everyone’s little habits, peculiarities and idiosyncrasies. This does not mean that everyone opens up and shares their life stories. You can, of course, and probably will over the course of time, but it’s not a prerequisite. It’s the little things you begin to notice. The mannerisms and habits. The more you work with people, the more you learn how people work.
But also, if any of your co-workers have kids, you will learn far more about ‘gastro’ than you ever wanted to know.
The corollary of the point above is that whatever you do — someone else is watching you do it. While you are observing your colleagues’ idioms, quirks and habits, they are observing yours. You are likely to be offered feedback. You will have to learn how to accept it. You are not your code. Try not to take things personally and remember that no matter how good we are, we can always be better.
For the first few months of pairing you will be exhausted. Talking all day is exhausting. Coding all day is exhausting. Talking while you code, all day, is doubly exhausting. But you get used to it and you find ways to self-regulate. The team grows an innate sense of its own energy levels and when you hit that afternoon slump it’s common for an entire team to realize they need a break and pop out for coffee or ice-cream.
Any article on pair programming will suggest that pairing reduces defects and improves quality. It will. But that, in my opinion, is far from the most beneficial aspect of pairing.
In the seven years I spent programming and not pairing it was very common for me to be assigned a task then work through it to completion and beyond. It might take weeks. It might take months. During that time other things would be happening. Interesting things I didn’t get to work on because I was stuck on ‘my’ task. Even after it was complete I was ‘the expert’ now. The Expert can never escape. Your past tasks have a gravity well that suck you in and keep you there.
If you pair and rotate through tasks; firstly you won’t get stuck on something forever, and secondly the whole team will become experts. Both help avoid the situation above.
I would say I learnt more in my first year of pairing than I had in my whole seven years of working solo. Part of this was no doubt circumstantial. Changing jobs, changing industries and changing technology stacks. But much of it I would attribute directly to pairing.
You learn simple but non-trivial productivity boosts like clever IDE tricks and keyboard short-cuts. You learn the unwritten history of the company and the code base from those who have been around a while. You learn language idioms, new patterns and new tools. You learn new philosophies. You learn to appreciate the different ways different people approach similar tasks.
You are never on your own. You always have someone to turn to with any questions. If they don’t know the answer themselves, they’ll no doubt know who does.
Because everyone is talking to everyone else, all the time, the floodgates of communication open and information flows freely and naturally. It is possible to achieve a ‘hive mind’, where new knowledge acquired by one team member is shared with all team members.
This is perhaps the most important benefit of all. So important that it deserves it’s own article. But in short, learning to share your code with your pair is the first step towards learning to truly embrace ego-free programming. The benefits of this to yourself, your peers and company culture far exceed any reduction in defect count or improvements in quality.
“Should you worry about balancing pairs, for example not pairing juniors with juniors?”
Do not worry about balancing experience levels. It all works out in the end. Do worry about balancing new hires or new team members who haven’t paired before.
When someone new joins the company and your team, ease them in gently. Some people are naturally better teachers and explainers than others. Try to pair these people up with your new starters for the first few rotations. Try not to have more than two new starters in the same team at the same time. If you do, try not to pair them with each other for their first month or so.
Otherwise — with regular task rotation, a difference in experience levels never seemed to be a problem. Pairing evens it all out remarkably fast. Also, verbal communication is much more frequent in a team that is pairing. When everyone is talking in pairs, other pairs overhear when someone is struggling and step in.
Additionally, people seemed to feel more at ease asking questions when they were stuck. When no-one has headphones in, when everyone is already talking anyway, it feels less intrusive to ask for help.
“When do I check my email / slack?”
Before stand-up. At lunch. After hours. Other than that you work distraction free. It’s better for you, anyway. The corollary is that if you need someone’s help now — you need to walk over and tap them on the shoulder. Pairing successfully requires developing a company culture where people are open to the occasional interruption. (See ‘what about flow’, below).
“How can you maintain flow while pairing?”
This is another thing that in practice is not as much of a problem as you might imagine. You discover that as a pair and as a team you can maintain a rhythm. It might not be quite the same as a deep, trance-like flow. But on the other hand I’ve seen people flow themselves in the wrong direction for a week. You optimize for the flow of work through the team rather than the flow of work out of an individual.
A pair develops a natural rhythm that approximates flow but feels easier to transition into and maintain. It is also naturally resistant to interruption. Frequently someone would pop by to ask a quick question and I’d find myself saying out loud, “Okay, where was I?” — and my pair would say, “You were just …” and then off we go again, as if the interruption never happened.
“What if someone is working from home?”
This is not an area I have much personal experience with, but other teams experimented with this and found it wasn’t totally awful. Although the first time you go for a stroll through the office as a pair, carrying a disembodied head on a laptop, it can raise a few eyebrows.
Good tooling is of course crucial. A recent article here has a good discussion of the current state of play. In my current team we have had reasonable success with ‘Visual Studio Live Share’. I would recommend you trial the tooling inside the office before you take it outside.
When pairing works well it pulls you right in and you truly feel part of a team. If you are pairing and not enjoying it, I hope you found some useful practices to help make things better. If you are thinking about pairing, I hope this article gave you a more concrete understanding of what to expect.