Hi
I am assuming that most people are familiar with the use of the
Bowling Game to illustrate TDD.
If not there was a recent article on
http://www.xprogramming.com/xpmag/ and discussions in comp.object
etc. Another example is
http://www.objectmentor.com/resources/articles/xpepisode.htm
Whenever people start discussing the solution that TDD arrives at,
one of the areas that provides disagreement is the lack of a Frame
object.
Now I cannot imagine a discussion with a bowling expert about how to
play and score bowling that would not have the concept of a Frame in
it?
But does necessarily mean that we will have a Frame class?
I am wondering how you guys would begin modelling the bowling game
domain model and how that would influence the design of your code?
Regards
ShaneMingins
"Yes you could implement an OO model in C or assembler, even in pure
binary if you wanted to. And you could also paint your house with a
toothbrush. I just hope that you have better and more enjoyable
things to do with your time." - Rod Davison
I would probably have started with the Game class, having it compute
just the current score. When it came time to add frame-by-frame scoring,
I might add a Frame class, but what I really needed is just a
"scoreA
sO
fFrame(n)" method, which could reasonably belong to Game. At
that point, Game is perhaps really Scorer. Then I might consider an
engine for tracking a multi-player game, either for match play or team
v. team match play (both are common in organized bowling), at which
point I'd likely have a GameEngine that uses Scorer. GameEngine would be
responsible for managing who's turn it is and when the game ends.
I don't know that I'd ever have a Frame class, though.
When I coded a bowling game, though, I took a different approach,
resulting in a Frame class that listened to the Game class. Each Frame
listened to a maximum of three throws (I bowl 5-pin) and stopped
listening after counting three throws. The nice part of this design is
that the game score is then just the sum of the frame scores, with each
frame scoring its own three throws. Since in 5-pin each frame counts
three throws (even the 10th frame), there's no need for polymorphism on
the Frame class, as other OO solutions (like Ron's) have.
JBRainsberger
I must admit that I've only bowled about twice in my life and don't actually
know the rules, so I'll have to rely on the domain domain experts we
undoubtedly have here.
> From: J. B. Rainsberger [
mailto:jbrains@r...]
>
> I would probably have started with the Game class, having it compute
> just the current score. When it came time to add frame-by-frame scoring,
> I might add a Frame class, but what I really needed is just a
> "scoreAsOfFrame(n)" method, which could reasonably belong to Game. At
> that point, Game is perhaps really Scorer. Then I might consider an
What I want to point out is that the relationship between model concepts and
code is not just 1 object = 1 concept. In this case, it seems clear that
"frame" is part of the ubiquitous language. Therefore it is part of the
model, and it seems to be hard to explain the rules of bowling without it.
But that doesn't mean it has to be a class. Look at the design J.B. decided
to start with: class "Game" with method "scoreAsOfFrame(n)". I see three
model elements, all clearly part of the ubiquitous language, and all
expressed in the design:
game, an entire sequence of play, usually accumulating a score
score, an increment in a game
frame, some subdivision of a bowling game that has a scoring rules of its
own (which I don't fully understand)
So, "aGame.scoreAsOfFrame(n)" is a meaningful statement in this language.
Then, J.B. considers other designs. But notice that many of them are
expressing little variations in the model and the language. "Scorer" changes
a verb to a noun and shifts the emphasis from the game overall to the
process of keeping score.
>resulting in a Frame class that listened to the Game class. Each Frame
>listened to a maximum of three throws (I bowl 5-pin) and stopped
>listening after counting three throws. The nice part of this design is
>that the game score is then just the sum of the frame scores, with each
>frame scoring its own three throws. Since in 5-pin each frame counts
This time the "frame" becomes an object, but the model concept (and the
usage in the language) has not changed at all. What this design allows is
the explicit expression of more of the rules of bowling. The meaning of a
"frame", which was always there in the model in people's heads, is now
expressed in the code of the Frame class.
The GameEngine design, also mentioned, is a very different direction.
GameEngine is not a model term; it is a mechanism. Depending on how it was
designed. It creates a mechanism that might hide the essential workings of
the game. It would all depend on what the input to the engine is. If it
takes data about game play and computes results, it is essentially hiding
the model, making the design less expressive and more mechanistic. But if it
takes as an input a declarative description of the game rules, then it might
allow an expression of the model of bowling that is even more direct and
distilled than the object model.
EricEvans
> ... the solution that TDD arrives at ...
I'm still amazed how TDD lets the design evolve "magically", without
any need of a domain model, not even an informal one. ;-P
I was thinking that TDD:ers could make a neural network program for
them. Just write the test and let the neural network fix the rest. It
will be guided by compiler errors and green/red lights. Without any
domain model, programming is pure text manipulation anyway, right?
(Sorry, Shane, for not addressing your question)
JohanNilsson
>I was thinking that TDD:ers could make a neural network program ...
If the text convey semantics, like DNA does, definitely yes.
As always, I may be wrong
FedericoSpinazzi
> I was thinking that TDD:ers could make a neural network program for
Given a sufficiently good test suite, yes.
In a lot of ways, the logical conclusion of TDD is to write a provably
correct program. If you look at languages that support true
correctness, a common feature is an accurate description of
preconditions, postconditions, and invariants. These concepts can be
emulated pretty neatly by test cases.
In my experience, however, it is rare for even the most die-hard of
TDDers to really achieve that level of testing in a language like Java,
especially when you start incorporating the J2EE stack and all of its
complexities.
PatrickLinskey
> I was thinking that TDD:ers could make a neural network program for
I am amazed that people took this comment seriously. It was clearly
a joke. He was poking fun at TDD. The fact that people took it
seriously indicates that someone (me) should make a more direct
attack on TDD.
First, I think TDD is a great idea, and my programming has improved
a lot since I started it. However, it is not the end-all and be-all
of programming, and the people who advocate it (i.e., the XP crowd)
over-sell it. It needs to be over-sold, because the state of the
practice of testing is so wretched. The vast majority of programmers
do no systematic testing. If they get convinced that TDD is a magic
elixer that will radically change their life, they might start testing.
But TDD is not a magic elixer. You are not going to get good programs
by using a neural net to make the tests pass. The reason that TDD
works is because programmers are intelligent and creative, and because
they eventually develop a domain model. When programmers are stupid
and lazy, TDD will fail, like anything else.
Developing good software is hard. It requires knowing about programming
languages, algorithms, the problem domain, testing, design, documentation
(at the very least, how to name things), how to communicate with other
people, how to get along with other people. Any statement of the form
"follow this practice and you will be successful" is wrong. Sometimes
I can look at what someone is doing and tell them "if you follow this
practice you will be more successful", but no advice is universally
applicable, and no practice, even TDD, is a silver bullet.
This applies to domain modeling, of course. Most groups that decide
to model their domain fail miserably. That is because they think that
a domain model is a UML diagram, not a language. They don't follow
the advice of DDD to start with a language that is shared by developers
and customers, and then to figure out how to make the program reflect
that language. They think that they will produce the domain model,
and then others, less enlightened, will use it.
We are more likely to be successful when we do not underestimate
the problem.
RalphJohnson
> I am amazed that people took this comment seriously. It was clearly
> a joke. He was poking fun at TDD.
I was maybe a little serious after all. TDD in a simplified
environment has the prerequisites for applying neural networks.
What I react against is the blind faith in TDD driving the design.
You can never find elements in your domain by writing fake
implementations, nor by triangulating. Maybe you can reach a position
where you see the shortcomings of your model. That could also be done
with use-case realization. TDD is nothing new, in that respect.
To write a test you need some initial theory. That theory could be a
domain model. Once this stage has been set, my experience is that TDD
works well for the decoration work.
>
> First, I think TDD is a great idea, and my programming has improved
> a lot since I started it. However, it is not the end-all and be-all
> of programming, and the people who advocate it (i.e., the XP crowd)
> over-sell it.
I use TDD on daily basis. Otherwise it feels as if my progress is not
secured. For trivial tasks where components will play a non-critical
role, I don't have the patience to practice TDD.
> I can look at what someone is doing and tell them "if you follow
this
> practice you will be more successful", but no advice is universally
> applicable, and no practice, even TDD, is a silver bullet.
As software developers, we should learn never to get excited about
anything.
In computer science, phrases
like "probably", "sometimes", "occasionally" are *probably* used more
than anywhere else, and rightly so!
JohanNilsson
To even write an expressive test, you must have some model. The tests should
reflect the same ubiquitous language as speech, UML, code, etc.
...
...
assertEquals(3, game.scoreAsOfFrame(2));
EricEvans
> I use TDD on daily basis. Otherwise it feels as if my progress is not
> secured. For trivial tasks where components will play a non-critical
> role, I don't have the patience to practice TDD.
And this is why you can't realistically treat a TDD system as something
that could feed an automated development process -- as soon as we start
putting untested assumptions about, well, anything into our programs,
they fail to be provably correct, and hence the need for intelligent
programmers etc.
However, if we do write sufficiently accurate descriptions of our
programs such that a program can guarantee that it can create a program
that meets the description, then the description of the program
(amazingly detailed tests, or rich pre- and post-conditions, etc.)
becomes the program itself, and the TDD process / program description
process becomes the thing that the intelligent and creative programmers
are creating.
You can see this type of programming in environments like Matlab, where
a developer writes mathematical formulas that describe an outcome,
rather than writing algorithms in a general-purpose computing language
to perform the calculation of the formulas. Now, as I said before, this
is something of an extension of TDD -- the TDD folks don't claim that
you'll end up with a correct program if you use TDD, so in the more
typical case, TDD is more of an aid to a more traditional
general-purpose computing process than anything else.
Regardless, I wholeheartedly agree that there is no silver bullet, and
if there were, I don't think that TDD would be it. If my ruminations
about TDD made you think otherwise, I apologize for any confusion.
PatrickLinskey
It's possible to get the joke and take it seriously.
There have been useful results produced by programs that automatically generate programs that pass a test suite. Four examples come to mind: finding fast sequences of machine instructions to perform a given task, finding fast parallel sorting algorithms, finding compiler optimization settings, and finding perfect hashing functions.
I'm no expert on the subject of automatic program generation, but all the examples I'm aware of have short precise problem descriptions and long memory-intensive search computations. The resulting programs tend to be relatively incomprehensible, but if you really trust your test suite to be correct and complete, maybe comprehensibility isn't important.
Here are some links:
http://www.cs.brandeis.edu/~hugues/sorting_networks.html - evolved fast sorting algorithms, improved on Danny Hillis' work. One cute thing Hillis did was to evolve better test cases in parallel with evolving better sorting algorithms.
http://www.vanemden.com/books/neals/jipi.html - a hillarious short story about simulated evolution taken to extreme by Neal Stephenson.
http://www.longnow.org/about/articles/ArtPunctEq.html - some analysis of simulated evolution by Danny Hillis.
JohnDCorbett
I just want to add that when we consider our professional responsibility to
our customers, TDD should probably be on top the list. TDD is humanistic in
nature, that is it helps us to avoid 'human errors' while allowing us to
practice our craft of modeling and design with increased confidence.
From the business point of view, if I am a manager who understands the
importance of a good domain model, of course I will mandate TDD, but I will
also try very hard to find a developer who has done good models before, has
studied DDD, and hopefully apprenticed to Eric.
DavidVydra
www.testdriven.com
> I must admit that I've only bowled about twice in my life and don't
actually know the rules
I thought it was practically a national US pastime ;-)
> ...But that doesn't mean it has to be a class. Look at the design J.B. decided
> to start with: class "Game" with method "scoreAsOfFrame(n)". I see three
> model elements, all clearly part of the ubiquitous language, and all
> expressed in the design:
>
> game, an entire sequence of play, usually accumulating a score
>
> score, an increment in a game
>
> frame, some subdivision of a bowling game that has a scoring rules
> of its own (which I don't fully understand)
So that means that implementations that do not have a Frame Class but
represent Frame in some other manner still express this model.
Correct?
The other example link I posted has no Frame Class, but a method
scoreF
orFrame on a Scorer Class, which sounds similar to
J.B's "scoreA
sO
fFrame(n)" method, which could reasonably belong to
Game".
If conversations with your domain expert generated the model elements
above as part of the ubiquitous language is it possible that a first
cut UML diagram may show a Frame class?
But then as you move forward, writing code using TDD, you get a
deeper understanding of the model, and so an intial Frame class is
refactored to a method on a Game or Scorer class.
If the meaning of Frame has not changed then the model has not
changed. The UML diagram has changed though (but then it was only
sketched on a napkin to begin with *grin*).
How does that sound as by way of clarifying my understanding?
Thanks
ShaneMingins
> do no systematic testing. If they get convinced that TDD is a magic
> elixer that will radically change their life, they might start testing.
My impression is that the XP crowd have over-sold TDD but I would
credit them with also cautioning that it is no silver bullet. That
is just my experience. I also agree that it needs to be over-sold.
But they do not sell it as a testing technique but as a design
technique. Within XP my understanding is that you write just enough
tests to get the code working (and that is a judgement call on what
is "just enough"). I would imagine that this is stating something
that you already know but as you mentioning testing I just wanted to
clarify that I have not seen it is not sold as a testing-technique.
> But TDD is not a magic elixer. You are not going to get good programs
> by using a neural net to make the tests pass. The reason that TDD
> works is because programmers are intelligent and creative, and because
> they eventually develop a domain model. When programmers are stupid
> and lazy, TDD will fail, like anything else.
My impression of late has been that the importance of people have
been lost in the push of the process?
<snipped>
> This applies to domain modeling, of course. Most groups that decide
> to model their domain fail miserably. That is because they think that
> a domain model is a UML diagram, not a language. They don't follow
> the advice of DDD to start with a language that is shared by developers
> and customers, and then to figure out how to make the program reflect
> that language. They think that they will produce the domain model,
> and then others, less enlightened, will use it.
So when Ron Jeffries says "To me, TDD is a way of getting a domain
model, not a way of using a domain model."
http://groups.yahoo.com/group/testdrivendevelopment/message/6056
How does that sit and fit with your thoughts of DDD and TDD?
For example in another message on that thread Johan asked "When
writing a test for a new feature, where do you find the class that
will implement the feature? Where did Bank come from?"
Ron replied "I asked my customer what he would do with the "dollars"
he got at the coffee shop, and he told me he would take them to
the "bank". And continues with conversation to find out what a bank
is.
Now that seems like developing a Ubiquitous Lanaguage. The
Ubiquitous Lanaguage is part of the domain model so then TDD is
actually *using* a domain-model as well as getting (or I would have
said evolving) it.
Regards
ShaneMingins
>I am assuming that most people are familiar with the use of the
>Bowling Game to illustrate TDD.
I'm among those who found the Bowling Game example confusing, hard to
follow, and generally a bad example of TDD. I know several others
who feel the same way.
>I am wondering how you guys would begin modelling the bowling game
>domain model and how that would influence the design of your code?
I don't see a conflict between TDD and DDD. Both are useful
practices in isolation, but much more powerful when used together.
Extreme programming mandates both. People get confused about this
because XP calls the DDD part "System Metaphor", and because it's
never been explained well in the XP literature.
I think the perceived conflict comes from the examples used to teach
TDD. They focus on the TDD aspect of development, because that's
what they're teaching. It's like when Obi-Wan Kenobi had Luke
Skywalker try lightsaber dueling with a blast helmet on. He wasn't
recommending that Luke go into combat blind; he was just trying to
get Luke to work on one specific set of skills in his Jedi repertoire.
John Brewer
I liked the way Bob presented the bowling game example at XP Universe 1
conference. I think it is a good example of getting to "the simplest working
implementation", but it may violate the "simple, but no simpler rule". I
think the context for that example was to teach people not to overengineer,
not necessarily to find the appropriate SUPPLE design.
DavidVydra
What I envision is that G
ameEngine now handles a multi-player or team
game, which means essentially scoring for multiple players
simultaneously, and allowing their frame-by-frame scores to be entered
on a round-robin basis. An alternate name might be R
oundR
obinGame, or
even M
ultiP
layerGame. The latter expresses intent without revealing
implementation details. Perhaps M
ultiP
layerGame depends on
R
oundR
obinT
urnPolicy, a policy that says "each player plays a frame in
turn". Then there are two different scoring policies:
T
eamG
ameS
coringP
olicy and S
inglesM
atchP
layS
coringPolicy. The two
policies look at the M
ultiP
layerGame and interpret the scores either as
individual match play (head to head competition) or team match player (a
combination of head-to-head and team-vs-team).
Now that I think of it, there's also an I
ndividualM
atchP
layT
urnPolicy
which operates differently: player A bowls one frame; player B bowls
two; A bowls two; B bowls two....; then finally A finishes with his last
frame.
So now we have
M
ultiP
layerGame ---uses---> <<interface>>T
urnPolicy
M
ultiP
layerGame ---uses---> <<interface>>S
coringPolicy
each policy is passed into the game on construction
M
ultiP
layerGame.score(frame, bowler)
M
ultiP
layerGame.nextBowler()
M
ultiP
layerGame.currentF
rameNumber()
M
ultiP
layerGame.enterThrow(pointsO
nThrow)
...and whatever else we need to really finish the job.
Maybe I need to actually build this and write about it... the design is
richer than I'd expected.
JBRainsberger
> Now that seems like developing a Ubiquitous Language. The
> Ubiquitous Language is part of the domain model so then TDD is
> actually *using* a domain-model as well as getting (or I would have
> said evolving) it.
Thanks for that observation. That was obviously the ubiquitous
language.
What I think caused the heat on the TDD forum was that the XP people
react instinctively when they see some sign of a non-coding artifact
(like Hermann Göring said: Whenever I hear the word culture, I reach
for my revolver).
JohanNilsson
BowlingGameDomainModel is mentioned on: ThreadView