Pairing Smells

Tim Ottinger and I are working on a new project, an agile agile reference guide. (Yes, that’s supposed to be two “agile”s in a row.) One of the things we’re debating is a list of pairing smells. Here’s what we have so far:

  • Unequal access to keyboard and/or screen
  • Keyboard domination
  • Pair marriages / no switching during story
  • Worker/rester pairing
  • Second computer
  • “Everyone does their own work”
  • 90% of stories 90% done
  • Reluctant pairings
  • Debates lasting longer than 10 minutes with no new code

Thoughts welcome, and incorporated ideas will be rightly attributed. What might we remove from or add to this list? What could be worded better?

Request for a Blog Pair

I encountered a bit of code recently that screams out for refactoring. Problem is, I’m not sure of the most effective way to do this.

The context: this is a tic-tac-toe game that Paul Nelson and I paired on, in order to explore mobile device programming (Paul has an iPhone, I have a BlackBerry). Paul’s not here right now to pair, unfortunately, hence the blog request (a really slow way of virtual pairing).

Here’s the relevant code:

private boolean isRowWinner(int row) {
   for (int column = 0; column < SIZE; column++)
      if (grid[row]
!= currentPlayer) return false; return true; } private boolean isColumnWinner(int column) { for (int row = 0; row < SIZE; row++) if (grid[row]
!= currentPlayer) return false; return true; } private boolean isDescendingDiagonalWinner() { for (int i = 0; i < SIZE; i++) if (grid[i][i] != currentPlayer) return false; return true; } private boolean isAscendingDiagonalWinner() { for (int i = 0; i < SIZE; i++) if (grid[i][SIZE - 1 - i] != currentPlayer) return false; return true; }

The field grid is simply a 3×3 matrix of Player references; Player is an enum; currentPlayer is a Player reference.

What’s the most effective way to simplify these four methods, seemingly rampant with duplication? I’m not looking for a “clever” solution; I’m looking for one that still retains high levels of expressiveness.

Original Comments:

No test??? :-p

Here’s my refactoring. It removes duplications, but I’m not sure if it is more expressive.

private boolean isMarkedByCurrentPlayer(int row, int column) {
return grid[row]

== currentPlayer;
}

private boolean isWinner(int a, int b, int bb) {
for (int i = 0; i < SIZE; i++) {
if (!isMarkedByCurrentPlayer(i * a, i * b + bb))
return false;
}
return true;
}

private boolean isWinner(int a, int b) {
return isWinner(a, b);
}

private boolean isRowWinner(int row) {
return isWinner(0, 1);
}

private boolean isColumnWinner(int column) {
return isWinner(1, 0);
}

private boolean isDescendingDiagonalWinner() {
return isWinner(1, 1);
}

private boolean isAscendingDiagonalWinner() {
return isWinner(1, -1, SIZE – 1);
}

One mistake. Should be:

private boolean isWinner(int a, int b) {
return isWinner(a, b, 0);
}

Ah yes, tests… Of course there are tests. 🙂 But now you’ll probably want *all* of the code. I’ll post a zip file tonight, but here are the tests in raw form (this comment mechanism doesn’t allow pre tags):

package domain;

import org.junit.*;
import static org.junit.Assert.*;
import static domain.Player.*;

public class GameTest {
private Game game;

@Before
public void initialize() {
game = new Game();
}

@Test
public void create() {
assertGrid0(” “); // using this form,
assertGrid1(” “); // source can be formatted,
assertGrid2(” “); // but still retain visual usefulness
assertFalse(game.isOver());
}

@Test
public void firstMoveAlwaysX() {
game.makeAMove(1, 1);

assertGrid0(” “);
assertGrid1(” X “);
assertGrid2(” “);
}

@Test
public void secondMoveMadeByY() {
game.makeAMove(1, 1);
game.makeAMove(1, 0);

assertGrid0(” “);
assertGrid1(“OX “);
assertGrid2(” “);
}

@Test
public void movesAlternateXandY() {
game.makeAMove(1, 1);
game.makeAMove(1, 0);
game.makeAMove(2, 0);

assertGrid0(” “);
assertGrid1(“OX “);
assertGrid2(“X “);
}

@Test
public void movesToTakenSquaresDisallowed() {
try {
game.makeAMove(1, 1);
game.makeAMove(1, 1);
} catch (IllegalMoveException expected) {
assertTrue(expected.getMessage().contains(“[1, 1]”));
assertGrid0(” “);
assertGrid1(” X “);
assertGrid2(” “);
}
}

@Test
public void xWinsByFillingTopRow() {
assertNonWinningMove(X, 0, 0);
assertNonWinningMove(O, 1, 0);
assertNonWinningMove(X, 0, 1);
assertNonWinningMove(O, 1, 1);
assertWinningMove(X, 0, 2);

assertGrid0(“XXX”);
assertGrid1(“OO “);
assertGrid2(” “);
}

@Test
public void oWinsByFillingTopRow() {
assertNonWinningMove(X, 1, 0);
assertNonWinningMove(O, 0, 0);
assertNonWinningMove(X, 1, 1);
assertNonWinningMove(O, 0, 1);
assertNonWinningMove(X, 2, 2);
assertWinningMove(O, 0, 2);

assertGrid0(“OOO”);
assertGrid1(“XX “);
assertGrid2(” X”);
}

@Test
public void oWinsByFillingAnyRow() {
assertNonWinningMove(X, 1, 0);
assertNonWinningMove(O, 2, 0);
assertNonWinningMove(X, 1, 1);
assertNonWinningMove(O, 2, 1);
assertNonWinningMove(X, 0, 2);
assertWinningMove(O, 2, 2);

assertGrid0(” X”);
assertGrid1(“XX “);
assertGrid2(“OOO”);
}

@Test
public void completedMixedRowNotAWin() {
assertNonWinningMove(X, 0, 0);
assertNonWinningMove(O, 0, 1);
assertNonWinningMove(X, 0, 2);
}

@Test
public void xWinsByFillingFirstColumn() {
assertNonWinningMove(X, 0, 0);
assertNonWinningMove(O, 2, 1);
assertNonWinningMove(X, 1, 0);
assertNonWinningMove(O, 2, 2);
assertWinningMove(X, 2, 0);

assertGrid0(“X “);
assertGrid1(“X “);
assertGrid2(“XOO”);
}

@Test
public void oWinsByFillingAnyColumn() {
assertNonWinningMove(X, 0, 0);
assertNonWinningMove(O, 2, 1);
assertNonWinningMove(X, 1, 0);
assertNonWinningMove(O, 1, 1);
assertNonWinningMove(X, 1, 2);
assertWinningMove(O, 0, 1);

assertGrid0(“XO “);
assertGrid1(“XOX”);
assertGrid2(” O “);
}

@Test
public void xWinsByFillingDescendingDiagonal() {
assertNonWinningMove(X, 0, 0);
assertNonWinningMove(O, 0, 1);
assertNonWinningMove(X, 1, 1);
assertNonWinningMove(O, 0, 2);

assertGrid0(“XOO”);
assertGrid1(” X “);
assertGrid2(” “);

assertWinningMove(X, 2, 2);
}

@Test
public void yWinsByFillingAscendingDiagonal() {
assertNonWinningMove(X, 0, 0);
assertNonWinningMove(O, 0, 2);
assertNonWinningMove(X, 0, 1);
assertNonWinningMove(O, 1, 1);
assertNonWinningMove(X, 1, 0);

assertGrid0(“XXO”);
assertGrid1(“XO “);
assertGrid2(” “);

assertWinningMove(O, 2, 0);
}

@Test
public void draw() {
assertNonWinningMove(X, 0, 0);
assertNonWinningMove(O, 0, 2);
assertNonWinningMove(X, 1, 2);
assertNonWinningMove(O, 1, 1);
assertNonWinningMove(X, 0, 1);
assertNonWinningMove(O, 2, 1);
assertNonWinningMove(X, 2, 0);
assertNonWinningMove(O, 1, 0);

assertGrid0(“XXO”);
assertGrid1(“OOX”);
assertGrid2(“XO “);

game.makeAMove(2, 2);
assertTrue(game.isOver());
assertEquals(Player.NO_ONE, game.winner());
}

private void assertNonWinningMove(Player player, int row, int col) {
assertEquals(player, game.currentPlayer());
game.makeAMove(row, col);
assertFalse(moveString(row, col) + ” unexpectedly completed game”, game.isOver());
}

private void assertWinningMove(Player winner, int row, int col) {
assertEquals(winner, game.currentPlayer());
game.makeAMove(row, col);
assertTrue(moveString(row, col) + ” unexpectedly did not win game”, game.isOver());
assertEquals(winner, game.winner());
}

private void assertGrid0(String row) {
assertRow(row, 0);
}

private void assertGrid1(String row) {
assertRow(row, 1);
}

private void assertGrid2(String row) {
assertRow(row, 2);
}

private void assertRow(String row, int rowIndex) {
for (int colIndex = 0; colIndex < row.length(); colIndex++) {
Player player = Player.toEnum(row.charAt(colIndex));
assertEquals(moveString(rowIndex, colIndex), player, game.square(rowIndex, colIndex));
}
}

private String moveString(int rowIndex, int colIndex) {
return “move at [” + rowIndex + “,” + colIndex + “]”;
}
}

Bartosz–I have two failing tests after applying your code. Email me and I’ll send the code back. I like where it’s headed but it needs better names for the variables, and some of the magic numbers need explanation.

So, it’s the next proof of refactoring without tests being a bad idea (or refactoring with tests written after, because that is what I did).

private static final int[] COLUMN = new int[] { 1, 0, 0 };

private static final int[] ROW = new int[] { 0, 1, 0 };

private static final int[] ASC_DIAGONAL = new int[] { 1, -1, SIZE – 1 };

private static final int[] DESC_DIAGONAL = new int[] { 1, 1, 0 };

private boolean isMarkedByCurrentPlayer(int row, int column) {
return grid[row]

== currentPlayer;
}

private boolean isWinner(int row, int column, int[] corr) {
for (int i = 0; i < SIZE; i++) {
if (!isMarkedByCurrentPlayer(row + i * corr[0], column + i * corr[1] + corr[2]))
return false;
}
return true;
}

public boolean isRowWinner(int row) {
return isWinner(row, 0, ROW);
}

public boolean isColumnWinner(int column) {
return isWinner(0, column, COLUMN);
}

public boolean isDescendingDiagonalWinner() {
return isWinner(0, 0, DESC_DIAGONAL);
}

public boolean isAscendingDiagonalWinner() {
return isWinner(0, 0, ASC_DIAGONAL);
}

Still, some magic numbers could be removed.

Jeff, I couldn’t figure out how to leave a trackback, but I posted my solution at http://blog.gdinwiddie.com/2008/07/29/tictactoe/ rather than put into a comment here. I went for a table-driven design.

Ah, it appears that the trackback is automatic.

+1 for Adam’s solution
-1 for Adam’s variable naming
-1 for Jeff’s obscure test
===
Bunny–I think that’s Bartosz’s nice solution, not Adams.

Talk about the obscurity of the tests. What would make for less obscure tests? My pair and I thought it was about the easiest way possible to follow the tests–a number of one-liners to represent each move, and a visual set of assertions to show the resulting board.

George–I think Paul and I had discussed a couple similar solutions. For tic-tac-toe, that one’s a nice idea. What if it’s a game like connect 4?

Jeff, for larger boards like Connect 4, I don’t think I would use the table lookup, as it would be rather large. Even with automated generation of the table, there would be significant penalty from overlapping winning patterns.

I’ve not tried it, but it occurs to me that it might be worthy to have a table of straight-line paths, and then traverse those paths counting the consecutive squares of the same player. These straight-line paths could be arrays of Positions.

I think a contributing factor to the need for refactoring in the isXyzWinner() methods is that the concept of Position is implicit, rather than explicit. It’s made of separate row and column values. This requires the code that deals with positions to know how they connect with each other. By pushing these details out, the code is required to handle the variations in the way rows and columns are traversed. By expressing the locations as Positions, the code just needs to deal with sequences of positions.

The straight-line paths I describe above for Connect 4 are really the same thing as the winning paths used in my Tic Tac Toe solution.

It also occurs to me that Path could be a class, itself. It could be initialized with a starting Position and x and y increments for a step along the path. It could also provide an iterator to allow walking through the Positions of the path checking it against the win criteria.

This is another possible implementation of separating the navigation across the board from the evaluation of the winning condition.

I didn’t look at the other solutions, so this might be a duplicate, but I would probably do this:

1. Unroll the loops in each of the four methods.
2. Inline the four methods.
3. Tease apart the duplication in the resulting mess.

In my experience, a more incremental approach, like inlining two of the methods then removing duplication, leads me down ratholes, so I prefer the break-it-all-down-then-build-it-back-up approach.

Open Source Pairing Scheduler

Rather than whine about not having enough good pairing experiences, I’ve decided to do something about it. Recently I’ve had a few pairing sessions online, and I decided that the software to build would start around the simple notion of scheduling online pairing sessions.

The idea is to slowly start building an online pairing community. I imagine there are many kinds of participants, people who want to:

  • build quality software via pairing and TDD
  • promote their services and ability to mentor via pairing
  • get some work done on a real product
  • get in touch with other members of the agile community
  • learn about either pairing or TDD
  • learn about the effectiveness of distributed pairing
  • learn a specific technology (Java, Rails, JMock, RSpec, etc.)
  • improve their Ward number for bragging purposes

I hope that the scheduler software will be all that and many more. Initially, I created a wiki as a scratch pad area, to help set up sessions, to hold an initial backlog of stories around the scheduler itself, and to record experiences.

I chose Java, but only because of interests in my pairing partner. I’m not sure that the pairing scheduler should be Java, but for now it is. If Java, what represents the best choice for front end (web) technologies?

Please feel welcome to join up and post your recommendations and experiences at the wiki site. Interested developers should send me an email with their intents, and I’ll set up their SourceForge account to have appropriate access.

Pair Programming Withdrawal

Once again, I find myself without peers. I’ll spare the details, but I used to work with some great agile technical mentors. I had some (never enough) opportunities to just sit and pair on a solution, not as a mentor, but as a peer on a programming effort. Unfortunately they’ve all disappeared, one way or another.

I’m reminded of my feelings when I left a 7-month programming gig a few years ago. During that seven months, I paired almost continually. I looked forward to going to work every morning. There’s a significant social aspect to pairing, but mostly I looked forward to learning new things.

Some of my favorite pairing sessions in the past half-year were with Tim O.**, and more recently with a guy named Rick. I learned, and I think they may have learned too. I improved in capability and thus effectiveness on vi while working with Tim. With vi, a very powerful editor, I think there are a number of rungs: 1, where it just beeps at you, 2, where you’ve figured out how to survive, 3, where you’re reasonably proficient, 4, where you know quite a bit and are very effective, and 5, a true master that knows everything in there. Tim is certainly at 4 and approaching 5 (there were a few things he had to look up). The nice thing about our pairing sessions is that Tim helped me to step up from rung 2 to 3.

Now, I’m all alone (*sob*). Sympathy cards are welcome, but smacks upside the head for my whining are also welcome. The way I look at it is that every day that I’m not pairing, there are many, many things that I could be learning that I’m not. That’s a shame. I now second-guess my work. “This sucks. There has to be a better way. Is there a better way?” I’m pretty sure that I also develop more slowly.

As an aside, I’ve heard suggestions that expert-to-expert pairings are a waste of time. That’s absolutely not true. A good tennis player and friend once told me that the best way to hone your game and take it to the next level is to play with someone as good as you or better. It works in programming, too.

**Tim is an Object Mentor consultant who coaches agile teams in just about everything. I think he’d like it that I added this information.

 

Comments:

I love to play Enemy Territory, online objective based first person perspective shooter.
Sometimes it happened there are only few people left on a server at early morning. The most exiting moment for me is, when I face enemy much better than I’m. That’s the unique time when I’m given a chance to improve my: aiming, decision making, orientation and coordination skills.
Although I don’t consider myself an expert, I’m not a total lame as I was few times recruited for medium skill clans.

Apparently, those who consider expert-to-expert paring to be a wast of time, are ashamed to admit they are not as good as they thought.

 

A Case for Pairing: Open Workspaces and Distractions

I currently work as part of an agile mentoring team in a large organization. Up until recently, we shared a project room. At any given point in time, there might have been one of four to six or seven team members (including a manager), plus one to three people that we were working with. On average there were four people in the room at any given time.

Up until this experience, I had always had positive sentiments about open workspaces and team rooms. In this current setting, I did benefit significantly from getting to converse frequently with all of the other people in the room. I learned things I probably would never have learned otherwise. And, I had a grand old social time.

But I also found that I wasn’t getting much work done when I had things I need to concentrate on. It seemed like I could be guaranteed a distraction at least every five minutes. Either someone was asking a question, or I was overhearing something that I felt compelled to respond to. It got to the point where if I had to find a couple hours to work on something (such as preparing training material), I ended up leaving the open workspace to find somewhere quiet.

The problem wasn’t the open workspace, it was the fact that none of us were really working on the same thing. The other mentors were usually working on a different project than I was. And my manager, well, you know how managers are, there’s always something they want you to pay attention to right away.

Escaping the room on occasion was an adequate solution, but the better solution ended up being pairing. I noted that as soon as I found a partner to help build a solution, or someone that I was mentoring, the distractions disappeared. I surmise two reasons: first, as a pair we were focusing on a problem. That meant I was no longer listening to any external conversations. Second, people are more reluctant to interrupt two people that they see obviously engaged in a conversation or task.

As I’ve paired more and have worked with teams employing pairing, I’ve grown a long list of benefits that I’ve seen accrue from the practice. My experience here adds a new bullet item: pairing minimizes distractions.

If You’re Not Pair Programming…

… what do you call it? “Solo programming,” I’ve heard. My preferred term is “isolation-based programming.” So, sure, pairing up seems like a dumb idea. So does programming in isolation. Yeah yeah, it’s not really isolation. May as well be.

Code Comprehension and Test Paraphrasing

Individuals are good at writing code that only they understand, and even then only at that moment. I’ve returned to code I wrote the day before, only to scratch my head in befuddlement: “What in the world is this code doing?” Or, “What was I thinking?”

This tendency of code to look like hieroglyphics is a common problem, and it’s not insignificant or trivial. Code that isn’t clear can take orders of magnitude more time to comprehend, raising our maintenance costs through the roof. I’ve spent whole afternoons trying to decipher overly complex code. In contrast, my comprehension times on a comparable amount of well-factored code have been as low as five to ten minutes.

Developers have come up with many ways to try and fix this problem. The art of refactoring is about improving the design and readability of code. Instead of settling with something that “just” works, programmers look to rephrase code to make it more readable. However, I’m not sure that code can ever be completely self-documenting.

Other maintainability mechanisms include comments, design documents, and review processes. Out of these, I’ve found review processes to be the most valuable. The very act of reviewing requires that someone other than the author understand the code. All the refactoring, comments, and external documents are a waste of time if they too are inscrutable. At least if two people can understand the code, it’s probably reasonably readable.

Some developers use pair programming as an active, continual form of software review. Done properly (see Pair Programming Dos and Don’ts), pair programming can result in much higher system quality. One of the main reasons is that two heads are usually better than one. Two people working together tend to spot the flaws that someone working on their own might not notice.

More importantly, two people working together have to agree, and read the same things from the code as the other. Meeting this requirement, a requirement that pairing creates by definition, elevates communication to be the most important element of development. It’s no longer good enough that the code works–more than one person must be able to understand it.

Even using pairing as a tactic, meeting the goal of readable tests and code is a significant challenge.

One specific area of code comprehension is something I’ll refer to as “client comprehension:” given a specific class, how does a developer use it in client code? Interacting properly with a class requires answering many questions. A sampling of the things that often require answers:

  • What is the right sequencing of method calls?
  • What arguments should be passed?
  • What happens if an argument is null?
  • What state is the system in after methods are called?
  • What happens if an exception is thrown?

Some developers prefer annotating the code with comments to help answer these questions. The trouble is, no guarantee exists that these comments are going to be readable or even accurate. Maybe unit tests can help answer some of these questions with more accuracy.

Unit Testing vs. Test-Driven Development

Many developers are now in the habit of writing unit tests against their code. Unit tests are small bits of code that verify whether or not chunks of production logic work properly. Most typically, programmers write their code first, then come back and write unit tests against the completed code.

In general, the more unit tests that programmers write, the more likely that they find or prevent defects. However, coding and maintaining unit tests requires a significant investment. So significant, in fact, that it doesn’t make sense to me to “just” get better test coverage, and thus hopefully fewer defects, out of it.

If I’m going to put all that effort into coding unit tests, I believe that I need to get more things out of doing so. One thing I hope for is that the unit tests can act as some level of comprehensive documentation against class capabilities.

In fact, I have been able to get this return on investment from unit tests, through practicing test-driven development (TDD). TDD is a form of unit testing where developers code in a brief cycle:

  • write a unit test, or even a piece of a unit test
  • verifying its failure using a simple tool (the code doesn’t exist yet)
  • write code to meet the specifications of the unit test
  • verify the code’s correctness using the tool
  • refactor the code, eliminating any code quality problems that were just introduced
  • verify the code’s correctness to demonstrate that refactoring broke nothing.

I’ve gotten some other important benefits out of doing TDD, including obtaining a better, more maintainable design. My debugging cycles have been shorter, not just fewer, a benefit I have gotten out of doing “just” unit testing. Since doing TDD generally results in higher level of test coverage, it’s brought me the ability to refactor code with high levels of confidence that I’m not breaking anything. TDD also allows me to develop with a consistent rhythm, something that trickles up to help improve my estimating ability.

In contrast, I’ve gotten few of these benefits out of doing just unit testing (aka “test-after development,” or “TAD,” as in “a TAD too late”). In fact, I’ve sometimes questioned the value of doing TAD at all, given the much lower return on value and high cost of maintaining the tests.

One of the significant mindsets that goes along with doing TDD is thinking about how they drive and define what a class does. For every feature, every use of a class that is needed, a programmer drives the implementation of this feature by adding a unit test. The unit test is named appropriately. An example of a concisely-named unit test might be “testAccountDebitedOnWithdrawal,” or “testAccountFrozenWhenFundsInsufficient.” These features are expressed and developed from the perspective of the client. In fact, the tests are technically the first client of the class under test.

The ability of tests to act as documentation is an important consideration in TDD. TDD-style unit testing forces programmers to continually think about how the code should be used in order to accomplish a task. Contrast that to the mindset of unit testing, which is, “does the code work as written?”

Still, it’s possible to write unit tests that read poorly. As with code, I’ve written unit tests that made little sense the next day. In fact, it’s fairly easy to write tests that correctly verify code, but provide no answers to a future maintainer.

Paraphrasing Tests

As mentioned earlier, a review process can help improve the quality of tests and product code considerably. If someone else can read my code, chances are it’s probably ok.

One technique that I’ve found extremely valuable is the idea of paraphrasing your tests. You can use this technique regardless of whether you have a formal review process. Even if you are pairing, it can be worthwhile to involve a third party.

The idea of paraphrasing is that someone not involved in the creation of the code reads the test out loud. “OK, in testFreeServiceWithinWarrantyPeriod, first it looks like you’re creating a customer object. You populate it with some basic data, then you set the installation date to a year ago plus a day. Then you call the warrantyService method on it. Finally you prove that the customer charge is $0. Makes sense!”

Often, the paraphraser will say something like, “I’m not sure why you get a charge of $100, based on the input data.” Someone reading a test shouldn’t have to ask these kinds of “why” questions. Any such questions indicate that the test needs to be refactored. Perhaps the name of the test needs to be revisited. Often, magic numbers (string or numeric literals embedded directly in the code) need to be replaced with appropriately-named constants. Variables might need to be renamed, the code might need to be decomposed better, and so on.

Paraphrasing is a great technique that developers can employ easily and cheaply. Even a solo developer can read the test out loud, listening to how it sounds. I’ve employed this technique on my own, and found it has improved the quality of my tests dramatically. I highly recommend test paraphrasing as a step to introduce prior to code check-in.

Pairing and Other Office Battles

A poster at JavaRanch complained about loss of worker productivity when his cubemate started pair programming. His work was suffering due to the amount of constant conversation. I dropped a subsequent posting, suggesting that perhaps his neighbors weren’t that good at pairing yet. Pairing done effectively requires only a small amount of verbal communication.

That aside, I’m reminded of other battles in shops. Lights vs. no lights, for example. Some cultures like to work in the relative dark and turn off the fluorescent lights. This can make it very difficult for some people, perhaps even emotionally. Others claim that fluorescent lights cause them similar distress, and they’re unable to work as effectively as possible.

The best we can do is learn to show some respect and consideration for others. This doesn’t mean, however, that we cater to everyone’s whims. I happen to work best shirtless (not a pretty sight) and with obnoxious music playing. I’ve found that I need some noise level, otherwise I’m unable to concentrate. (It’s probably a side-effect of my wife using a white noise device to sleep at night.) But my personal preferences aren’t going to fly in most places.

I’ve gotten to the point where I just don’t give a hoot. After doing this long enough, I’ve learned to adapt to wacky coding styles, ignorant management, fluorescent lights, unworkable processes, shirts, and silence or excessive noise. I’ve worked in a Coke room, an open room with 60 people (on 3+ projects), in a rickety shack of a building, in lots of horrid cube farms, in an office with a physically abusive coworker, and in an office with two heavy smokers (back when you could still smoke in the office). I still managed to always get the job done.

I note that my most successful projects were when I worked in a collaborative environment, i.e. not in isolated cubes or offices. The best efforts I’ve ever been on were with a bunch of developers circled around a group of monitors, pairing or no pairing and XP or no XP.

If something is particularly bothersome to me, I first find a way to change it. I’ve taken out fluorescent light bulbs, I’ve brought in Allen wrenches and dismantled cubes, I’ve put my headphones on, I’ve requested a different cube, I’ve talked to my coworkers and management. If I can’t change it, I learn to cope. If I can’t cope, I just leave. When the time comes that none of these is an option, it’s time to move to my second career.

Pair Programming Observations

Pair programming is one of the most contentious practices of extreme programming (XP). The basic concept of pair programming, or “pairing,” is two developers actively working together to build code. In XP, the rule is that you must produce all production code by virtue of pairing. The chief benefit touted by pairing proponents is improved code quality. Two heads are better than one. Note that pairing is a practice that you can use exclusively of XP.

However, a large number of developers despise the notion of having to sit next to someone for the better part of their work day. Reasons for resistance can include:

  • the belief that pairing is a waste of time and ineffective
  • the belief that pairing should only be used occasionally
  • fear of exposing personal weaknesses
  • personality issues, including introversion

Pairing is not for everybody. But too many people resist pairing based on a knee-jerk reaction to what they understand it to be. Usually, the practice and its benefits are not fully understood.

Pairing Technique

There are only a few simple rules to follow if you choose to do pair programming. First and foremost is that all production code must be developed by a pair. Conversely, this means that are plenty of other activities that you can undertake in the absence of a pair:

  • work on any non-production code: the acceptance test framework, other tools, build scripts, etc. In most shops, these are in dire need of attention.
  • work on documentation
  • work on spikes for future stories
  • learn how to use a new third-party product; learn a new coding technique; and so on
  • identify problem spots in the production code that need refactoring
  • refactor tests
  • improve the existing test coverage if necessary

Any of the above could be done better if a pair were available, but they are usually lower risk activities. If time is absolutely a factor, the non-pairing developer can work on production code, but with the insistence that such code is peer-reviewed after the fact.

Having a non-pairing developer work on production code should be the exception, not the rule. As such, it should be justified and treated as a high risk activity.

The second pairing rule: it’s not one person doing all the work and another watching. During a good pairing session, the keyboard should be moving back and forth between the two participants several times an hour. The person without the keyboard should be thinking about the bigger picture and should be providing strategic direction. They should also be helping to ensure maximal code quality and minimal defects.

Third, don’t pair more than 75% of your work day. A good, productive run of 6 hours of software development is mentally exhausting. Make sure you take breaks! Get up and walk around for a few minutes at least once an hour.

Finally, you need to switch pairs frequently. Working with any one person for any extended duration will not only drive you nuts, but you will begin to lose the benefit of getting fresh outlook on problems. Minimally, switch pairs at least once a day. In fact, I promote switching pairs once in the morning and once in the afternoon. In addition to getting new insight on solving a problem, there is another, less obvious, benefit to frequent pair switching.

Context Switching

When you sit down to work with a new pair, you must switch mental contexts from the task you were working on to a whole new problem. Context-switching is difficult. Work for only 55 minutes then switch tasks? Seems outrageous. One might think, “It’ll take almost that amount of time for me to come up to speed on what you’ve just developed!”

An XP rule of thumb is: when something is difficult or painful, do it more often until it becomes easier. If integrating is a royal pain, do it more often until you learn how to do it better, or at least until it’s apparent you’ve hit the point of diminishing returns.

If context-switching takes too much time, do it more often. In theory, what this should do is force developers to write better code. By “better” I mean code that accommodates cheap maintenance without adverse impacts on the system.

If it takes me thirty or even ten minutes to come up to speed on a task, yes, there is a thrashing problem. If instead the other developer has followed good design/coding guidelines (small, composed methods, no duplication, appropriate naming, and basic OO design principles go a long way), context switching should take only a couple minutes. Couple that with a test-driven approach, and I can quickly focus on a small amount of detail.

The Numbers

So how many people actively resist pairing? At a large shop of ~300 developers (divided among several teams), about fifteen (5%) developers actively resisted pairing when they embarked upon XP. The rest of the people fell into one of three groups: skeptics, interested adopters, and cows, divided fairly evenly in terms of numbers. After pairing for a few iterations, perhaps five of the fifteen resisters learned to enjoy it. Another five didn’t mind it enough to complain any more, and another five hated it even more than before.

Having consulted in a good number of XP shops, my personal experience shows these percentages to be pretty consistent. Based on what I’ve seen, you’ll end up with from one to five percent of developers who can’t or won’t pair. For most shops, that’s one or two people.

Obviously there are always people who don’t voice their objection and just go along with whatever is tossed their way. You do want to ensure everyone has a forum for feedback. I’ve solicited feedback via anonymous 3×5 cards, email, public forums, one-on-one discussions, however I could. Beyond that, if someone isn’t going to be honest enough to complain, I suspect it says something about the caliber of that employee.

What To Do With These People

Any shop embarking on XP, RUP, Scrum, or whatever, needs a coach to steer people in the right directions. Engaging in a new process without a coach is worse than trying to play a football game without a coach–at least the football players have done it all before and know some of the things to watch for.

It’s a coaching failure if I’m unable to turn some of the pairing resisters around. And usually I can, by working directly with them, by demonstrating the benefits firsthand, and by ensuring that the process otherwise goes smoothly. From my own exposure to pairing, I initially thought it was a bad idea. After practicing it a bit, I didn’t necessarily love it, but recognized the benefits and was willing to do it. Shortly thereafter, I began to love what I was able to get out of it.

Most sizeable shops have small adjunct efforts. For valuable resources, one-offs are a great place. There’s also the possibility of working on non-production code, such as tools for internal use.

Resisters might still be able to work within a team, as long as they put up with their end of the bargain. Remember that pairing is initially a way of doing continuous review. In lieu of pairing, the resister must initiate Fagan inspections or some other sort of formal review. One way or another, the code must be reviewed–otherwise you’ll get pricy consultants (like myself) or unguided novices, producing unmaintainable garbage. Often, people find that the evil of pairing is preferable to the evil of group review.

Ultimately the rules should be up to the team, as long as the rules satisfy the requirement that code is reviewed. If the entire team revolts and insists upon no pairing, then they can all do inspections or whatever review form acts as a second-best choice. If 95% of the team insists upon pairing, and the sole remaining developer can’t deal with it at all, the organization should help them find something else to work on.

While this may sound intolerant, remember that software development is a team effort. Suppose I go to your shop and find out that you value RAD. You sit in a board room with 25 other people for two days and hash out every detail of the project. You then produce 200 pages of design documents. But I have a personality disorder that prevents me from contributing in such an environment. I can’t stand sitting in a room for days on end slogging through stuff, 95% of which is useless to my role. And I also have a disorder that prevents me from understanding design document doublespeak.

Do I belong in this organization? Probably not. If the organization is successful with this culture, why should they waste time and money trying to accommodate my obstinance?

I’m not trying to be clever or obtuse here. The point is that organizations should grow the cultures that they value, and that those cultures may not be appropriate for everyone. Anyone who says every shop should do XP or RUP or whatever is insane. The reality is that there are always other shops to choose from.

Other Pairing Benefits

The book Pair Programming Illuminated goes into much further depth on the costs and benefits of pair programming, in addition to many other related topics. I highly recommend it. Over the years, I’ve built my own brief list of pairing benefits.

General benefits:

  • Produces better code coverage. By switching pairs, developers understand more of the system. Many benefits can result from this increased knowledge.
  • Minimizes dependencies upon personnel. Everyone worries less about buses and trucks.
  • Results in a more evenly paced, sustainable development rhythm.
  • Can produce solutions more rapidly.
  • Moves all team members to a higher level of skills and system understanding.
  • Helps build a true team.

Specific benefits from a management standpoint:

  • Reduces risk
  • Shorter learning curve for new hires
  • Can be used as interviewing criteria (“can we work with this guy?”)
  • Problems are far less hidden
  • Helps ensure adherence to standards
  • Cross-pollination/resource fluidity. Allows you to swap members from two or more teams on occasion, with minimal downtime. Usually each person will bring immediate value to the new team (“you guys should use this utility class that we built here…”).

Specific benefits from an employee perspective:

  • Awareness of other parts of the system
  • Resume building
  • Decreases time spent in review meetings
  • Continuous education. As someone who thinks he is a pretty hot programmer, I still learn new things every day from even the most junior programmers.
  • Provides the ability to move between teams. (“this team is boring,” “I can’t stand working with him,” “that stuff they’re doing looks cool.”). Since this can be a benefit for management as well, they don’t have to clamp down on their resources.
  • More rapid learning as a new hire. You don’t sit and read out-of-date manuals for a week, or worry that you’re going to be fired because the system looks indecipherable.

These benefits come about from monitoring the process, making sure the technique is executed well, and fixing problems. Don’t forget a coach!

Skill Level Gaps

An experienced developer can outperform an inexperienced developer by two, three, five, ten or even twenty times. Sitting with a novice can be excruciatingly painful. But I’d rather burn a little time bringing other guys up to speed as soon as possible. It pays off in spades.

Pairing allows me to keep tabs on their work and make sure they are not producing junk that will have to be rewritten. It also prevents them from holding up the project. Several years ago I was on a project that ultimately got cancelled, largely due to a schmuck that couldn’t get his work done in time, and when it did get done, it was garbage. With a pair, incompetence that can destroy a project surfaces far more quickly.

I still learn some very interesting things from working with novice developers. And they learn a wealth of things that they would never learn were they to be left to their own devices.

Leaving an inexperienced developer alone to suffer through the system and other issues presents them with a steep learning curve. Through pairing, this learning curve begins to flatten more early on in the project. The more time I spend up front with a novice developer, the more we can depend upon their contributions later in the project–when it matters far more.

Of course, the novice must be capable of growing. Pairing lets you find out quickly who’s worth keeping versus who will always be a drag on the team. Management can get involved in the first month or so of a project, as opposed to late in the project when it’s crisis time.

Final Comments

I’ve been in the position of promoting XP and hence pairing as a consultant for a while now. Until I did a longer, six-month consulting stint, my pairing experience was more sporadic. Sure, I saw the benefits and the negatives, and did it enough to know how to make it work. Plus I learned plenty more about it from other sources. But until I sat there and actively paired for a longer duration, some of its nuances weren’t as evident.

In fact, pairing seemed to me like a nice thing to promote, but maybe pairing wasn’t something that I needed to worry so much about. Not drinking my own kool-aid!

What I realized is that pairing after a while becomes a dependency, in both a good way and a bad way. I learned to look forward to most pairing sessions (there are always some difficult people). I also felt naked when not pairing, and begin to question more what I produced by my lonesome self. Pairing became assuring and thus relaxing.

Before, I would be overly confident that I was a great programmer and that I produced code that was just fine. Maybe not! A few pairings with some sharp people and I learned a few cool new techniques. I took on more humility.

Dependencies in code can be bad, as can dependencies in life. The secret is in managing these dependencies well. Learn to use pairing as a tool to help you do better the next time you aren’t

What Can Go Wrong With XP

Extreme programming (XP), on the surface, is a hot, trendy way of developing software. Its name appeals to the reckless and annoys the cautious (“anything extreme can’t be good!”). A recent article in Wired magazine attests to its popularity amongst the cool set, who believe that XP is a silver bullet. The article also talks about some of XP’s severest detractors, who view XP as dangerous hype. The truth lies somewhere between. XP alone will not save your project. Applied properly, XP will allow your team to become very successful at deploying quality software. Applied poorly, XP will allow your team to use a process as an excuse for delivering–or not delivering–low quality software.

Applying XP

XP is a highly disciplined process that requires constant care. It consists of a dozen or so core disciplines that must all be followed in order for XP to work. The practices bolster one another, and each exists for not one but for many reasons. For example, test-driven development and constant code refactoring are critical to ensuring that the system retains a high quality. High code quality is required in order to be able to sustain iterative, incremental development. And without constant peer review, many developers would quickly lapse from doing these critical practices. XP provides this review through the discipline of pair programming.

Yet many shops shun pairing, viewing it unnecessary for developers to pair all the time. Not pairing is not necessarily a bad thing, but in lieu of pairing, some other form of peer review must take place. (Fagan inspections are an OK second choice.) Without the peer review, code quality quickly degrades, and you now may have a huge liability that no one is aware of. The lesson is that if you choose not to do an XP practice, you must understand what you have just taken out. You must then find another way to provide what the practice brought to the table.

Good software development will always require these things:

  • planning
  • requirements gathering and analysis
  • design/coding
  • testing
  • deployment
  • documentation
  • review
  • adherence to standards

Contrary to popular misconception, XP says that you should be doing all of these things, all of the time.

Common Traps

The most common mistakes I’ve seen in the application of XP include: not creating a dedicated customer team, not doing fixed iterations, misunderstanding test-driven development, not refactoring continuously, not doing design, and not pairing properly.

Not Creating a Dedicated Customer Team

If you read earlier literature on XP, you will be told that there is one customer for an XP team. The practice was called “On-site Customer.” Since then, Beck and others have clarified this practice and renamed it “Whole Team.” The whole team aspect is that we (developers and non-developers) are all in this together.

The customer side of the fence has been expanded to include all people responsible for understanding what needs to be built by the developers. In most organizations this includes the following roles.

Customer / Customer Proxy In most cases, the true customer (the person buying and using the system) is not available. Product companies have a marketing representative that understands what the market is looking for. The customer or proxy is the person that understands what the functionality needs to be in the system being built.
Subject Matter Experts Used on an as-needed basis.
Human Factors Experts Developers are good at building GUIs or web applications that look like they were built by… developers. The user experience of a system should be designed and presented to the development team as details to stories presented at iteration planning.
Testers Most customers have neither the background nor the time to define acceptance tests (ATs), which is the responsibility of the customer team. Testers work closely with the customer to build specific test cases that will be presented to the development team.
Project Managers While a well-functioning XP team has little need for hands-on project management, project managers in a larger organization play a key role in coordinating efforts between multiple projects. They can also be responsible for reporting project status to management.
Business/Systems Analysts Customers, given free reign, will throw story after story to the development team that represents addition of new functionality. The development team will respond well and rapidly produce a large amount of functionality. Unfortunately, other facets of requirements will often be missed: usability, reliability, performance, and supportability (the URPS in FURPS).

In an XP project, it is debatable as to whether these types of requirements should be explicitly presented as stories, or should be accommodated by functionality stories. I’ve seen the disastrous results of not ensuring that these requirements were met, so I recommend not trusting that your development team will meet them.

The business or systems analyst in an XP team becomes the person who understands what it takes to build a complete, robust system. The analyst works closely with the customer and/or testers to define acceptance tests, and knows to introduce tests representing the URPS requirements.

Note that these are roles, not necessarily full-time positions. Members of the development team will often be able to provide these skills. Just remember that the related work comes at a cost that must be factored into iteration planning.

Not Doing Fixed Iterations

Part of the value of short-cycle iterative development is the ability to gather feedback on many things, including rate of development, success of development, happiness of the customer, and effectiveness of the process. Without fixed-length iterations (i.e. in an environment where iterations are over when the current batch of stories is completed), there is no basis for consistent measurement of the data produced in a given iteration. This means there is also no basis for comparison of work done between any two iterations.

Most importantly, not having fixed iterations means that estimates will move closer to the meaningless side of the fence. Estimating anything with any real accuracy is extremely difficult. The best way to improve estimates is to make them more frequently, basing them on past work patterns and experiences, and to make them at a smaller, more fixed-size granularity.

Putting short deadlines on developers is painful at first. Without fixed deadlines, though, customers and management are always being told, “we just need another day.” Another day usually turns into another few days, another few weeks. Courage is needed by all parties involved. Yes, it is painful to not finish work by a deadline. But after a few iterations of education, developers learn the right amount of work to target for the next two weeks. I’ll take a few failures in the small over a failed project any day.

Misunderstanding Test-Driven Development

Small steps.
Small steps.
Small steps.

I can’t repeat this enough. Most developers that learn TDD from a book take far larger steps than intended. TDD is about tiny steps. A full cycle of test-code-refactor takes on average a few minutes. If you don’t see a green bar from passing tests within ten minutes, you’re taking too large steps.

When you are stuck on a problem with your code, stand up and take a short break. Then sit down, toss the most recent test and associated code, and start over again with even smaller steps. If you are doing TDD properly, this means you’ve spent up to ten minutes struggling; I guarantee that you’ll save gobs more struggling time by making a fresh attempt.

Tests are specs. If you do test-driven development correctly, there is no code in the system that can’t be traced back to a spec (test). That means that you don’t write any code without a test. Never mind “test everything that can possibly break.” Test everything. It’s much harder to get into trouble.

As an example of a naive misunderstanding of TDD, I’ve seen tests that look like this:

public void testFunction() {
   SomeClass thing = new SomeClass();
   boolean result = thing.doSomething();
   assertTrue(result);
}

In the production class, the method doSomething is long, does lots of things, and ends by returning a boolean result.

class SomeClass {
   boolean doSomething() {
      boolean result = true;
      // lots and lots of functionality
      // in lots and lots of lines of code
      // ...
      return result;
   }
}

Of course, the test passes just fine. Never mind that it tests none of the functionality in the doSomething method. The most accurate thing you could do with this code is reduce the doSomething method to a single statement:

boolean doSomething() {
   return true;
}

That’s all the test says it does. Ship it! 😉

Test everything until you can’t stand it. Test getters and setters, constructors, and exceptions. Everything in the code should have a reason for being, and that reason should be documented in the tests.

Not Refactoring Continuously

Understanding how to approach refactoring and do it properly is probably the most misunderstood aspect of XP. Not refactoring well is also the quickest way to destroy a codebase, XP or not.

Refactoring is best viewed as the practice of being constantly vigilant about your code. It fits best as part of the test-driven development cycle: write a test (spec), write the code, make the code right. Don’t let another minute go by without ensuring you haven’t introduced junk into the system. Done in this fashion, refactoring just becomes an engrained part of your every-minute every-day way of building software.

As soon as you aren’t on top of it, however, code turns to mush, even with a great design.

XP purists will insist that constant, extreme refactoring allows your design to emerge constantly, meaning that the cost of change remains low. This is absolutely true, as long as your system always retains the optimal design for the functionality implemented to date. Getting there and staying there is a daunting task, and it requires everyone to be refactoring zealots.

Many shops experimenting with XP, however, understand neither what it means to be a refactoring Nazi nor what optimal design is. Kent Beck’s concept of simple design can be used as a set of rules. The rules are straightforward; adhering to them takes lots of peer pressure.

Not Doing Design

I’ve heard far too many people saying that “you don’t do design in XP.” Hogwash (and I’m being nice).

As with everything else in XP, the “extreme” means that you do design all the time. You are designing at all sorts of levels. Until you get very good at following all the XP disciplines, the iteration planning meeting should be your primary avenue for design.

Iteration planning consists of task breakdowns. The best way to do task breakdowns is to start by sketching out a design. UML models should come into play here. Class diagrams, sequence diagrams, state models, and whatever other models are needed should be drawn out and debated. The level of detail on these models should be low–the goal is to solve the problem of general direction, not specify all the minute details.

For a typical two-week iteration, a planning session should last no longer than half a day (how much new stuff that needs to be designed can possibly fit into two weeks?). But if you’re just getting started, and the design skills on the team are lacking, there is no reason you can’t spend more time in the iteration planning meeting. The goal should be that you spend less time next iteration.

Design should also be viewed as a minute-to-minute part of development. With each task tackled, a pair should sketch out and agree on general direction. With each new unit test, the pair should review the code produced and determine if the design can be improved. This is the refactoring step. Ideally you’re not seeing large refactorings that significantly alter the design at this point, but things like commonality being factored out into a Template Method design pattern will happen frequently.

At any given time, all members of the development team should have a clear picture of the design of the system. Given today’s tools, there is no reason that a detailed design snapshot can’t be produced at a moment’s notice. In fact, I highly recommend taking a snapshot of the existing system into the iteration planning meeting to be used as a basis for design discussions.

In XP, design is still up-front; it’s just that the increments are much smaller, and less of it is written down. In a classic, more waterfall-oriented process, more design is finalized and written down up front. The downside in XP is that there is some rework based on changing requirements. The downside in the classic process is that there is no such thing as a perfect design, and following an idealistic model results in overdesigned and inflexible systems. There are always new requirements, and a process that teaches how to be prepared to accommodate them is better than one that does not.

Not Pairing Properly

Part of pairing is to ensure knowledge sharing across the team, not just amongst two people. Ensure that your pairs switch frequently–at least once per day if not more often. Otherwise you will get pockets of ability and knowledge. Corners of your system will turn into junk, and you will have dependencies on a small number of knowledgeable people.

Developers will resist switching pairs frequently. It is a context switch, and context switches are expensive. If you are in the middle of a task, and the person you were working with leaves only to be replaced by someone else, you must take the time to get that person up to speed. Frequent pair switching forces you to get good at context switching, which forces you to improve your code maintainability. If your code is poorly written and difficult to understand, the newly arrived pair will waste far more time getting up to speed. Ideally, the new pair should balk and insist upon more code clarity before proceeding.

The ability to quickly understand code and associated unit tests is what makes software maintenance costs cheap and consistent. Maintainable code is what allows you to be able to sustain the quality of your system over time.

Atom