It’s been almost a year, but I think I have enough perspective now to write about my experience pair programming.
The short story is that pair programming doesn’t work for me as the main way of developing software. I can pair program for a day, or maybe a week, especially if we’re focused on a particular problem. But after that? I’m done. Toast. I don’t want to see anyone, talk to anyone, and I need at least a couple of days in a cave until I’m fit for human company again.
It’s a sad story, but the funny thing is that I’m so much happier now with how it ended. I’m happily employed on a contract where I work from home or from a coffee shop, and I’ve made new friends and explored more of San Francisco than I ever thought possible. I have a bicycle and a laptop, and as long as I meet my deadlines and check in code regularly, my time is my own.
I’ll list the big problems I have with pair programming up front and give you the detail and anecdotes later.
- Split focus.
- No experimentation.
- No high notes.
- No pride in ownership.
- No escape.
My background is as a backend programmer. I’ve done inventory systems, credit card processing and fulfillment, transcoding and digital asset management. In non-agile teams, I was used to being handed the largest, hairiest problem in a project, pulling out the domain and putting something solid together inside the deadline.
So, my first day.
I was watching a man looking at a page -- what the finished product should look like. He was telling me they’d discussed what the features should be already, and we just had to bang this out inside a day.
He had opened up a text editor, and we were looking at Ruby code. The ruby class was actually a page composed of Erector methods -- ruby code that evaluated to HTML -- but it had been refactored into extremely small methods which called each other, so there was no way to ‘see’ the HTML and how that corresponded to the class -- you simply had to know it. In addition, they had tests attached to each section of UI code. If you refactored the UI, you had to rewrite all the tests.
Sitting with another man, trying to work together to produce working code. I was shocked at how unnatural and unintuitive it felt. Far from being an easy practice, it felt both clumsy and shockingly intimate; both too personal and impersonal.
If I asked a question, then work stopped.
If I asked about the background of the code or the design, then work stopped.
I understood the HTML code, but even there, I didn’t even know what to say -- did I point out the typos? The two methods that were almost exactly the same except for the innermost loop? Was I nitpicking by pointing these things out, or signalling my involvement?
And then, he was done. It was time for me to write some code. I opened up some files, looked around at the methods. Tried to figure out what was going on, and write some exploratory code to see what was happening... And then my pair started typing the method I was trying to write, handing it back for me to test. I found that this would happen if I paused too long, or seemed to be typing the wrong thing -- my pair had another keyboard, and he would type over me to try to “finish the sentence” rather than talk to me.
At the end of my first day, I had a massive headache from trying to absorb everything. I was told I’d done very well, and that it was a lot to take in on the first day. I didn’t feel like I’d been very productive, but I hoped that we could settle down into some kind of flow.
Split focus happens when I try to do two things at once. Human beings are not good at multitasking in general, and I’m worse than most. Pair programming is a balancing act between managing code and managing the pair that you’re working with. Go too far in one direction or another, and you both fall off and lose effectiveness until you restore balance again.
I found that in order to pair, I had to act as if I was in a continuous meeting. I had to not just listen to my pair, but appear to be listening; I had to nod in the right places, repeat back what my pair said in active listening fashion. I had to pick the right moment to interject. I tried to model my partner’s mental state in my head so I could see his viewpoint better.
While I was doing this, I was trying to see the code that he was writing, and the design that he was trying to make the code fit. If there was a failing test, I was trying to figure out the test and the test framework at the same time.
And if I was writing code, I found something very interesting: I don’t think in English when I write code. I think in code first, and I can translate written code to English. When I was trying to talk to people when I was writing code, I found that I’d have to write pseudocode and then talk to them about it -- and when my pair wanted me to talk about code, he wanted me to stop typing. But if I stopped typing, I couldn’t describe what I was doing. Every time I tried to write code and talk to my partner at the same time, I could feel the lurch between what I could feel -- the complex shape of it in my head -- and what I was having to say.
So pair programming split my focus not just in one way. It split it in three or four different ways, and kept it split. No wonder I had a headache.
The large part of pair programming was doing things in “The Simplest Possible Way That Could Work.” In practice, this meant doing it the way that it had been done previously, with the least possible amount of change.
The way that the Erector toolkit was used, combined with pair programming and test driven development, ensured that two Ruby programmers were required to change any and all elements of the UI. Tests were written to check for every single element in the UI, and with good reason; because elements of the UI had been abstracted out into subclasses and views, there was no clear way to see what code would do until it had been fully executed. Sometimes the simplest possible thing to do had been to hack one of the classes for a special-case logic. Then more code had been put on top, until a refactoring was just too expensive. As long as all the tests were passing, the code was in a known, "good" state -- and we had to keep it that way.
The simplest thing that could possibly work as far as I was concerned was to put together an ERB page. A straight HTML page with some embedded Ruby was a known, easy solution that would have enabled straight web designers to work on the UI without involving the full programming team, or at least have allowed us to quickly compare the mockup with a page. But that ran into another problem; there is no facility in pair programming to change tracks, or try anything different. Spikes only happen at the beginning of an iteration, and this iteration was budgeted at 8 weeks -- we were locked into our current way of doing things.
Not that it mattered; there was simply no leverage to explore the framework or try different approaches. Any code changes that weren’t immediately applicable to changing the current page were “going off track”. I couldn’t see the parameters of the current system, or feel for the fragile points if it didn’t match up with what my pair thought was important. Every single moment I was typing, I was being watched.
No high notes
When I got to the point where I understood some of the framework, I saw that there were some bugs inherent in the existing design which would make the system act unpredictably in production. In other situations, the design could improved by eliminating some classes and moving some other classes to have a single responsibility.
To me, this was “refactor mercilessly” and “once and only once.” But to my partner, this was a violation of “do the simplest thing that could possibly work.” It also went against the daily switching of partners. Whatever you start when you pair has to be finished, and checked in, by the end of the day. If you’re only looking at getting the story done by the end of the day, you’re not interested in hypothetical bugs or refactoring -- you don’t have time for them and they’re not budgeted for.
The only way I could move discussion along was if I could write a test for it. If I couldn’t write an effective test, or I described it in unfamiliar terms (usually from books or blogs), he wouldn’t hear “solves a problem that is difficult to test but is real.” He would hear “introduces needless complexity and complicates design” and point to the simplest solution that makes sense to him. If I tried writing a test and it took too long, I lost there as well.
Eventually, I realized that many of my partners had never worked outside a test driven development process: they didn’t have the same idea of design or architecture as patterns distinct from code. Trying to argue for encapsulation or adherence to SOLID principles is pointless if your partner has no background, let alone hands on experience, with what you’re saying. This goes double when you’re talking about hard-won domain expertise: the more I knew about a subject, the less I could say.
I started picking my battles.
How you pick your battles is, you plan to lose in the best way possible. You try to leave an opening so that the bug that you know, from past experience, is going to hit, is not going to result in any lost data and can be easily fixed later. It’s not great, but at least you can recover from it.
There are no high notes, no thought out design. There’s only the design that could have tests written for it, in the time you had to write the tests. The classes look reasonable at first glance, and the methods are seemingly bug free. But the cracks are there, if you know where to look.
No pride in ownership
There is no ownership in pair programming. You’re working on a different piece every day, with a different partner. Everyone owns all the code equally. No-one really has responsibility for a single piece of it. Pair programming views this as a strength.
I had no pride in ownership. The code that ended up on the ground every day wasn’t something I felt I had input into. It didn’t feel right to me. Doing a good job matters to me. My idea of a good job: years after I’d moved on from one project, someone I’d never met wrote me a thank you note for taking the time to make my code clear and easy to work with.
The part of my brain that works though code will chew through things. Impede the flow, and that part of my brain starts to itch. Block it, and it starts pounding, chewing away at anything that comes close. Without pride in ownership, there was no meaning to any of the work that I was doing. I couldn’t even identify it as mine.
It was about this time that my physical health started to pack up. Winter set in, and it started raining constantly. I got a cold that got into my lungs. I couldn’t climb the stairs without resting. I couldn’t write code. I couldn’t think. The rain beat against my window. I couldn’t sleep.
The worst part of pair programming was getting up in the morning and realizing I had to do it all over again. No matter how drained I was, no matter how much I wanted to get away from people: I couldn’t. As an introvert, I yearned to be left alone with a large problem and the freedom to slice it into pieces. But there was no escape.
Even at the best of times, there were people. First, a fifteen minute standup meeting. Then sitting down at a work station with engineers on either side of me, two to a table. Talking. An engineer sitting next to me in my personal space. Every moment I was sitting there watching him, I was trying to think of something to say. Whenever I was typing I was worried that I was too slow, or that I was taking too much time to think, wasn’t saying enough, wasn’t being clear. Was I being anti-social? Talking too much? Too much smalltalk? There was no way to know.
Even when pairing worked, it was the slow, clumsy communication of two people trying to move a large sofa down a staircase. There was no flow. There were no spots where there was no conscious movement between thinking something and having it appear on the screen. I missed it horribly. Even the small discussions: was having “as_currency” method on an ActiveRecord Model the correct thing to do? Or was it something that should belong to the UI, as a helper method? Just how much did I really care?
And then a group lunch, where there was food, small talk and team bonding experiences. I started stealing moments of solitude whenever I could.
I asked my co-workers if they saw what I saw, if I was missing something, anything -- I didn’t see how this could work, how people could keep doing this. They said I was doing fine, that it just took time to settle in and adjust. That it was hard for everyone at first.
Eventually, I retreated into myself. Between the blinding headaches, the insomnia, and the pounding, unmet need to write code, I stopped responding to input. I could stare at a screen and not see anything. Someone could talk to me unexpectedly and I wouldn’t hear them. I was fulfilling the rote requirements of my job, but I wasn’t there. I’d used up everything I had just showing up for the day. I started checking my iPhone when my other partner was typing.
Finally -- just shy of three months later, and for the first time ever -- I was fired for not being a team fit when pair programming.
I wrote this not just to understand it, but also to be able to talk about it. There’s been a presumption that pair programming works for most people and is much easier and faster than programming solo would be. This may or may not be the case, but as a long term practice, pair programming doesn’t work for me. There are many other people that pair programming doesn’t work for either. We matter too.
Mark Wilden had a similar experience at Pivotal Labs. His discussion of design rings very true.
Nick Carroll says that pair programming is not for him. He thinks peer review is more useful.
William Pietri has a list of anti-social practices, many of which I saw and/or practiced.
Software Reality has more to say about the XP approach to pair programming and design. He also has a seperate post addressing pair programming specifically.
A CodeRanch discussion also discusses issues with pair programming, including Damon Black’s experience.
More generally, Daniel Markham talks about some gaps in agile as it is practiced and has made an interesting list of the responses.
EDIT: Also, Kathy Sierra writes about her experiences with pair programming in Pair Programming is NOT a choice, complete with pre-filled in responses.
EDIT: Another article: Nobody Expects The Agile Imposition.
EDIT: Alex Ruiz discusses his mixed feelings about pair programming.
EDIT: A story from Xebia about Chris, the tester.
EDIT: Jay Fields talks about why he doesn't pair program any more.
EDIT: Adam Logic discusses his dislike of pair programming and compares it to Design By Committee.
EDIT: Buzz Andersen: "I’ve never been more sure of my absolute distaste for anything in my professional life."
Also, it’s important to note that I still believe that Agile development can lead to better business solutions with less wasted effort. Pair programming is part of a single agile process called XP, and there are many other Agile processes such as Crystal Clear which do not mandate pair programming as a daily practice.
EDIT: I've read through the responses and replied here.