For the vast majority of my career, I rarely pair-programmed. I’d even tried it a couple of times, but it was awkward and clunky and slow. I wasn’t sold. It became something I only did if I or somebody else was really (really) stuck on something, but never in the regular course of things.
Then I worked with a client who practiced extreme programming and paired by default. That is, the expectation was that you didn’t work on code by yourself. Instead, you spent your day pairing with a partner. What this looked like was this:
- Every day at our morning huddle, everybody on the team got a buddy for the day based on:
- What was in-progress or to-be-started
- Who was holding context
- Who needed context
- Who hadn’t paired together recently
- How people’s schedules aligned
- For the rest of the day, we worked virtually side-by-side. We didn’t have virtual camera portals, but we did communicate our schedules on slack and almost immediately hop into a call using software designed for pairing, such as Pop or Tuple.
- We worked on whatever we would’ve done solo, taking time for breaks and lunch. This ranged from obvious coding tasks to configuring our monitoring tools, doing pre-deployment testing, deploying, reaching out to other teams with questions, and even attending each others’ non-personal meetings.
- Sometimes we’d even pull in another pair for more input or eyes on something.
- If we were an odd number, somebody would “solo” for that day, reaching out if we wanted another’s input.
Here is what I learned.
This was the first project I’ve been on where there simply wasn’t the same sense of individualized code or feature ownership I’ve seen and been a part of on other teams. Rather than everybody having their own section of the playground over which they ruled, it was one big playground and everybody took responsibility.
Asking for input on something became a cultural norm, and people’s egos were rarely in the picture.
In consequence, people felt safe, discussion came easily, and everybody was generally pleasant to be around.
Pairing all the time allowed people to be brought into the fold on day one and be relatively comfortable with the codebase by the time they had access, which for this client took at least a couple of weeks.
It helped to naturally share and normalize team practices, such as how we used git, without almost no friction and no real need for a “here’s how we … " document or retroactively correcting somebody.
The constant pairing and daily pair rotations made it so that everybody had at least moderate context on many parts of the codebase, features, and project as a whole.
Everybody could contribute valuably to team discussions.
The prospect of losing any one person was not that big of a deal, which isn’t to say that they wouldn’t be missed.
Indeed, even when my team loaned one of our stronger members to a different team, work went on with minimal disruption. This held true as others left, and I imagine it held true when I rolled off the project.
Working with others, even on mundane pieces of code, really helped reinforce or teach best practices, mentor on concepts, and set a platform for healthy discussion that isn’t focused on “my way” or “your way.”
This growth extended far beyond code construction into areas such as how to break down problems, ask good questions, write documentation, etc.
And as a more senior person on an unfamiliar code base, tech stack, and domain, my growth opportunities were plenty, too, in both hard and soft skills.
We almost always committed directly to
main because the code was being reviewed as it was written — all the “before code gets merged …” process I’ve seen on other teams was simply a non-issue.
By contrast, I’ve been on projects where “before code gets merged” was all some people talked about, even having team members devoted to the effort.
The overall code quality was better due to mutual accountability and raising the standard to the combined set of things people care about.
Working individually, it’s easy to just kind of be like, “eh, I know I should, but I don’t feel like doing …”; but with a pair, even if you both don’t feel like doing it, you’re more likely to do it if it’s the right thing. Or, as the case may be, you both may decide that it’s not that important in this scenario.
It was less likely that somebody would go down a rabbit hole or get stuck on something that could be easily resolved by asking somebody else.
I was able to feel more connected to my coworkers than I would have if my only other interaction with them was in meetings. This is something that I tend to undervalue, but it can be the difference between feeling isolated or not.
While some of the cons may be universal, many of them are how I personally responded and may not apply to others. Additionally, some of them might be a side-effect of the particular codebase I was working on combined with the team cycling.
A quick aside to talk about the team cycling: Above I said that Team Durability was a bonus, and it is; but over the course of four months, not counting myself, my team added three people and lost three people on a team averaging around 6 developers. Pairing-by-default helped us weather it far better than if we were working individually, but that much churn still meant that we never really coalesced around a sense of style as people rolled on and off. I call it out since it impacts the below.
Because there was no clear feature owner, sometimes the “vision/master plan/essence” for an approach got lost as it shuffled between people (a la the telephone game).
Similarly — at least on our codebase — we never ended up with a consistent pattern to follow of “here’s how we implement xyz.” I think as each pair reviewed a problem, they’d add their own combined flavor to it.
I suspect this says more about the state of the codebase and ancillary practices than it does about pairing since pairing should really result in the opposite.
Related to the above, as a feature made its way around the team, it was sometimes jarring to see code re-done several times as people applied their own sense of style and different people weighed in on different aspects of the solution.
Pro, though, it was extremely rare that a pair broke something that previously worked.
It was hard to balance my work and personal life, especially being in a different timezone from the rest of my team.
Having a pre-set schedule was very hard on me – being able to keep a flexible schedule and work outside of the standard working hours is one of the top things I look for in a job.
Pairing with somebody else requires a hightened sense of awareness and engagement that takes a lot of energy. For me, very much an introvert, I ended up so drained that I had nothing left for day-to-day tasks of living, like staying on top of dishes, putting clothes away, or cooking for myself. I ended up renegotiating my working agreement with the team to pair only half a day, which worked a lot better for me, but also made it kind of awkward.
I never really got “into the zone” when pairing, and the zen-like state of just me and the code never happened, which in turn meant that my overall satisfaction was lower.
I also had a hard time doing my own research. For example, I was weeks into the project before I found the time and energy to read up on and explore language features I wasn’t familiar with. Sure, I could have done this with a pair, but I really just wanted a couple of hours to commune with the documentation and spin up a sandbox.
Also, I tend to do my best thinking when I’m not trying to talk at the same time.
It was hard to work out and about due to external noise or due to being the one making noise.
I canceled my spot at a coworking space since I didn’t want to be the person talking all day.
I couldn’t listen to music at the same time as pairing. It’s not something I do much, but it’s nice on occasion. Maybe other people did with headphones, but I’m a no-headphone-if-I-can-avoid-it kind of person.
Some things don’t make a lot of sense to pair on, like reading documentation. My team never figured out that balance.
Because of the “thou shalt pair all day” mindset, people struggled.
Of the three people who cycled off my team, two of them quit citing the pairing expectation as part of the reason.
I heard rumor that others schedule meetings with themselves to avoid pairing.
Needless to say, both are signs that the expectations went too far.
In discussions around pair programming, especially pairing all the time, one of the things that often comes up is cost.
Do I think everything ended up costing twice as much? No. Not at all.
In my own speculation, due to the shared context, accelerated individual growth, and collective ownership (i.e., protection against team changes), I was estimating that everything may have cost like 1.2 - 1.5x as expensive, maybe less.
This study indicates that I wasn’t generous enough. They conclude “The development cost for these benefits is not the 100% that might be expected, but is approximately 15%. This is repaid in shorter and less expensive testing, quality assurance, and field support.”
As it doesn’t seem like they factor in team durability, it’s possible that the long-term cost of pairing is actually less than the cost to pay a single person when executed optimally.
If you have the opportunity to give pairing-by-default a try, I highly recommend going for it. With this experience, I’m far, far more likely to jump into a call for something mundane “just because.” And that “just because” might even be because I’m feeling more social and have nothing to do with code.
Embrace the awkwardness.
I suspect that, as with most things, a healthy balance to pairing is the best solution.
For more on pairing, check out our pairing ethos at Test Double, which goes over how to be a good pair. 💃🕺