In order to demonstrate XP (ExtremeProgramming
) practices, Bob Koss (RSK) and Bob Martin (RCM) will pair program a simple application while you watch like a fly on the wall. We will use test first design and a lot of refactoring to create our application. What follows is a faithful re-enactment of a programming episode that the two Bob's actually did.
Martin & Koss wrote the program to illustrate PairProgramming
. I decided to repeat their work only this time as a programming spike. A spike is written for the experience. A spike doesn't produce production code and is therefore exempt from ExtremeProgramming
requirement. I spiked the bowling score calculator to see how it would code up as a series of transformations applied to all the data at once.
Wiki'ers who can't read the description without implementing it can post their solutions on BowlingGameSpikes
SALEM, Ore. (AP) - A 28-year-old construction worker from Keizer, Ore., has been credited with bowling just the fifth perfect 900 series in the 106-year history of the sport's national governing body.
After Bob and Bob paired the bowling game, Koss showed me the write-up. I was a bit "thrown" (no pun intended) by the fact that there wasn't anything resembling a frame class in the code. So, I set to work using their test cases to see if I would end up in the same place. I didn't. But, I'm not sure whose solution I like better. In mine, I aimed towards small communicative objects, so I refactored the hell out of it, but it might be over-engineered Here's the story of the system..
Whenever you throw a ball, you give the score (ball) to the game. It takes that ball and add it to the current frame, creating a new frame as needed. To calculate the score, you sum all of the frames. Each frame knows how to calculate its score. If you are a spare frame, you need the first ball after you to calculate your score. If you are a strike frame, you need the first and second ball after you to calculate your score. Frames can ask the Game for those balls. If they don't exist yet, the game serves up an object which returns zero for those balls.
Here is the code for S
public class SpareFrame extends Frame
public SpareFrame(int frameNumber, Game game, int firstBall)
this.firstBall = firstBall;
public int getScore()
return 10 + afterFrame().getFirstBall();
public int getFirstBall()
public int getSecondBall()
return 10 - firstBall;
private int firstBall = 0;
afterFrame is a method in Frame which allows you to get the first and second ball after this frame. It returns a frame. The odd contortion is that you get balls one at a time, so on the first ball of a frame, you may add a regular frame to the list of frames, only to yank it and replace it with a spare frame if the second ball makes a spare.
Doing this was kind of fun. I spend a good deal of time telling people that you don't have to use domain objects when you code, but sometimes they are the best way to communicate everything you want to communicate.
The "selling point" for our solution is the algorithm for scoring a game is just so sweet and clear. That trumped the domain objects. -- YoungBob?
That's fascinating. Bowling, and the scoring thereof is a mystery to me, but the point is clear: one solution does not represent a well-known domain entity, another, that passes the same tests, does represent that entity. Are you talking about just functional tests here? Or unit tests as well? Are your unit tests strictly a super-set of the Bobs'? -- KeithBraithwaite
They are the same tests. I just uncommented them one at a time. I think the Bobs' version has one test case class covering two classes, one extracted from the other. I used that same test case class (against a class named Game) and ended up with several more classes. I should have applied RefactorIntoTest
. -- MichaelFeathers
Bowling might be an interesting domain in which to compare paradigms and languages; however, some of us don't bowl well enough to know some of the more advanced rules where prior turns are factored into the current turn if one hits enough pins. Thus, perhaps the rules of bowling should be clarified somewhere that developers can relate to. I would also note that the rules are static so that it may be difficult to explore ChangePattern
s to designs, which is usually where the "good fights" are. --top
- One game is a series of 10 frames.
- A frame is (usually) 2 balls.
- The score of each ball is the number of pins it knocks down.
- A strike is when you get all 10 pins on the first ball.
- If you get a strike, you do not roll a second ball for that frame but rather go immediately to the next frame.
- A spare is when you get all 10 pins between the two balls of one frame.
- The score of a strike frame is 10 plus the score of the next two balls (not frames!).
- The score of a spare frame is 10 plus the score of the next one ball (not frame).
- If you get a spare or a strike on the last frame, you get to roll one or two extra balls, respectively, but no more than that.
It's not as complicated as it sounds, especially if you look at a scorecard.
has a short tutorial.
Some of the things that make doing it programmatically interesting are allowing for the extra balls at the end of a game, and the fact that you can't calculate the score of a strike or spare frame until the balls after it are thrown.