Here's an example of how pair programming works. This example actually involved three people, over a few days, on comp.lang.smalltalk, but the exchanges are amazingly typical of what happens all the time in pair programming. The original authors:
I'm leaving the code as it happened, cleaning up and adding a little dialog. Names changed to protect the innocent.
Boy, is my face red! When the three of us were batting the examples around, we were too much in sketch mode, and the final examples don't work. I'll fix the code ASAP. Meanwhile, the human exchanges are very typical of good pair programming; come back later for the code.
Thanks to Sames Shuster for the catch. In real life, we would have been compiling the code, and running our unit tests, and this wouldn't have happened to us. A real-life proof of what happens when you don't follow your own process!
Pair Programming
A screenplay in one act.Jack has found some ugly code in the system. He has played with an improvement, but isn't satisfied with the result. Deciding he needs another pair of eyes, he has asked Jill to join him for a moment.
JACK
How's this for nasty code. I found it in production code. And people wonder why their UI isn't responsive.
He grins as Jill looks at the code.
widgetIDs | compNames | compNames := Set new. self builder namedComponents keysAndValuesDo: [:compName :comp | | wid | wid := comp widget. (wid isKindOf: VisualRegion) | (wid isKindOf: SliderView) | (wid isKindOf: NoteBookComposite) | (wid isMemberOf: View) | (wid isKindOf: SubCanvas) | (comp spec isKindOf: DividerSpec) | (wid isKindOf: GroupBox) ifFalse: [ compNames add: compName ]]. ^compNames asArrayJill sees right away that the code needed special formatting to be readable at all. This tells her that Jack is right, something needs to be done. The #isKindOf: is first on Jack's list.
JACK
(continuing)
It would be better to extend several classes to add the method #isSpecial, or whatever a better name would be, to simply answer a Boolean. The new method using polymorphism might look like this:
He clicks on another window, to show Jill his new version.
widgetIDs | compNames | compNames := Set new. self builder namedComponents keysAndValuesDo: [:compName :comp | (comp widget isSpecial or: [ comp spec isSpecial ]) ifTrue: [ compNames add: compName ]]. ^compNamesJill sees the #isSpecial and the resulting procedural code. After a little thought she gets an idea. She takes the keyboard.
JILL
(musingly, grabbing the keyboard)
Let me drive a second. I wonder if we could get rid of the #isSpecial by doing something like this --
Jill types a new version of the method.
widgetIDs ^self builder namedComponents inject: Set new into: [ :sum :each | widget specialAdd: sum]
JILL
(continuing, on a roll)
- with, of course, the implementations:
SpecialWidget>>specialAdd: aSet ^aSet add: self name OtherWidget>>specialAdd: aSet ^aSet
Jill has glimpsed an improvement, and grabbed the keyboard to put it in. In her leap to the core of a good solution, she has missed some details. Fortunately, Jack is with her.
JACK
You need a #yourself on that specialAdd,
JILL
Right, good catch.
SpecialWidget>>specialAdd:aSet ^aSet add: self name; yourself
JACK
and a better selector choice would be #specialAddTo:.
JILL
Right again.
SpecialWidget>>specialAddTo: aSet ^aSet add: self name; yourself OtherWidget>>specialAddTo: aSet ^aSet
She changes the code immediately. The whole thing takes place in a couple of minutes. Notice how the roles switch back and forth dynamically. Jack starts an approach, and Jill picks up on it. When Jill is sketching code, Jack backs her up with syntax support and style guidelines. The partners are working smoothly together, the one in backup mode supporting, the typist setting down specific code.
There's no conflict: they are two people cooperating on one mission, with the lead switching from moment to moment. Pair programming at its best.