ArticleS. UncleBob.
P2M2 [add child]

Pair Programming Maturity Model

Last week Tim Ottinger and I spent four days working on a new feature for FitNesse. Tim was new to FitNesse and so I was showing him some of the internals of the design, while we were adding the new feature. I think Tim found it helpful, since he has since asked to be added to the list of people who can check in changes to FitNesse.

The problem we were working on was the addition of a new navigation widget named backwards search. The backwards search widget allows you to specify a page name as follows: <SomeAncestorPage.ChildPage; where SomeAncestorPage is a parent, or grandparent, or great-grandparent, etc. of the current page. This is kind of like using .. in a unix path except that you can tell it to back up to a named directory instead of just one level.

Getting this feature to work was simple. We paired together for a few hours and had it working relatively quickly. But then we faced the more interesting issue of how this new feature affected some of the older features. Specifically, the refactoring features.

FitNesse provides gestures that allow authors to refactor the wiki. For example, you can change the names of pages, or move the pages to new locations. When you do either of these things FitNesse gives you the option to search through the entire wiki looking for references to the renamed or moved page, and adjusting those references. Clearly we'd want to adjust references that contained the backwards search feature too.

This turned out to be complicated for two reasons. First, the problem is simply complicated. Given a path to a page, one of the pages in that path may have been renamed. If so change the path to incorporate the new name. This might sound simple, but the problem is actually a bit mind bending. This wasn't helped by the fact that the original authors of the code we were looking at (er... me) had conflated it with a fair bit of accidental complexity having to do with the syntax of path names.

The upshot was that Tim and I stared at this code for the better part of two hours trying to understand it and not managing to get very far. One of the problems we faced was that pair programming, while great for working on stuff you are relatively clear on, is not necessarily great for looking at complex code and figuring it out. Indeed, the pairing quickly devolved from deliberate and disciplined coding to a turkey-shoot of random ideas, none of which was allowed to complete. Every time I would start to get some inkling of what was going on, Tim would say: "Oh! Look at this code here!" and blow my train of thought out of the water. Every time Tim started to roll on a good idea, I'd lag behind and drag him back and then sidetrack the conversation somewhere else. So, for awhile the pairing broke down.

Pairing is a wonderful tool. We made very good use of it for most of our collaboration over those four days. But sometimes pairing gets in the way. Sometimes you just have to stop and study a piece of code until you understand it. And that takes time, focus, and silence. For that kind of work, pairing just doesn't cut it.

Having said that, we actually did solve the problem while pairing. We fought through the issues and found a set of simple refactorings that started making the code easier to understand. Bit by bit, instead of grasping the entirety of the algorithm before us, we made is simpler and simpler by making very easy and obvious improvements, until the algorithm itself was easy enough to understand and change. Our primary strategy was to separate the syntax issues from the semantic issues. So we gradually moved all the syntax related code (e.g. the code that knows about dots and wiki words) into separate module; leaving the algorithm to deal with the abstraction of paths instead of lots of details text.

As a learning exercise, this was great for both of us. And I think we did the right thing by forcing ourselves through the difficulties of pairing and refactoring to a simpler solution.

Still, the issue remains. There are some modules that cannot be understood by a pair as easily as they can be understood by a focussed individual working in silence. Sometimes pairing is just not the right solution.

I have observed that mature agile teams will pair a little over half the time; perhaps as much as 70%. I think this is healthy. I'm not a proponent of 100% pairing. Instead I thinkk you should use pairing like any other tool. Use it when it works. Having said that, I also think pairing is useful in more cases than it's not, and should be aggressively pursued. However, pairing is not a religion, and, like anything else, should be used thoughtfully.

!commentForm -r
 Thu, 19 Oct 2006 14:13:35, Mark Brackett, Was the original code pair programmed?
Out of curiousity, was the original design programmed in pairs? If not, perhaps that is one reason it was allowed to grow slightly messy; it's much easier to decipher your own mess than others'.
 Thu, 19 Oct 2006 14:13:23, Mark Brackett, Was the original code pair programmed?
Out of curiousity, was the original design programmed in pairs? If not, perhaps that is one reason it was allowed to grow slightly messy; it's much easier to decipher your own mess than others'.
 Wed, 18 Oct 2006 10:51:56, Ola Ellnestam, [Slighlty OT] Possible SRP violation
Would you say that the code you where struggling with initially violated SRP and that you 'corrected' it? If so, what were the signs, if any? If not, were there any other violations that spring into mind when thinking of it in terms of design principles?

I find SRP particularly interesting since I myself have a hard time understanding heaps of code. Such as large methods and classes. When mentioning this to fellow programmers they don't find that reason enough to break down methods, classes and creating new classes.
 Tue, 17 Oct 2006 09:24:25, David Chelimsky, pair on decisions
At a former client we adopted a guideline that we should always pair at the start of a story. We definitely did not pair 100% of the time, but this guideline was very helpful to ensure that decisions about design and direction would be made in pairs.
 Tue, 17 Oct 2006 08:20:05, Brian Chiasson, Goals of pairing...
Your book, Agile Software Development, indicates that pairing has many gains, one of which being shared knowledge. This is a key aspect of pairing and involves more than just sharing domain knowledge. Pairing provides an opportunity for developers to learn from one another. Whether it is coding, debugging or trying to re-acquaint yourself with old code.

It is definitely difficult to troubleshoot problematic code with two minds working in opposite directions. But if you split up the pair to look at the problem individually, than perhaps either you or your partner is missing out on a great opportunity to learn something new.

 Mon, 16 Oct 2006 21:10:50, Ben Monro, Remote Pairing
Hey Bob,

What do you recommend for pairing on teams where most or all of the developers are remote? I find that VNC/IM/Phone is 'ok' but not nearly as good as the real thing.

 Mon, 16 Oct 2006 07:40:44, Neil Greenwood, Problem with backwards search example
The XML code for the backwards search example isn't showing up - you need to escape the angle brackets...
 Mon, 16 Oct 2006 01:30:58, Matteo Vaccari,
But, you say that working as a pair pretty much *forced you* to simplify the code before proceeding. If you were working on it by yourself, you might have gotten back your old understanding of the code, and then proceed to modify it directly. It seems to me you are much better off this way.