Art of Unit Testing: Part 2

William Tanksley wtanksle at dolphin.openprojects.net
Tue Sep 4 19:02:39 EDT 2001


On Mon, 27 Aug 2001 20:14:05 -0700, Jesse F. W wrote:
>Dear Billy,
>	Thank you again; this discussion is really making XP and 
>related subjects much clearer to me.  Thank you.

My pleasure.  For more info, you really should go to
comp.software.extreme-programming.  Be sure you've read XP Installed
(available online) first (or at least be reading it), and check out
http://www.xprogramming.com and http://www.extremeprogramming.org/.

The questions you're asking are very good, but I can't answer them without
taking far too much time.  I'm going to give you general principles and
hints rather than answers -- especially since by the nature of things, you
have to find the answers for yourself anyhow.

>William Tanksley wrote:
>> On Sun, 26 Aug 2001 21:26:34 -0700, Jesse W wrote:

>> >By the way, I use the self.app object mainly as a central storehouse
>> >of links to the various subparts of the total program.  The app
>> >object does not really know or do much.

>> Ah.  I would consider the app object unworthy of existance, then. 
>> Every object should have a meaning of its own.  However, if you
>> absolutely cannot find a way to give it a meaning, you must violate
>> the law of demeter every time you use it.
>How do I connect the various parts of my program, then? (I will say 
>more about this below)

Redesign.  Let's look below for detail; for now, just note that in a good
design, every object has a clear purpose of its own, and all of that
object's methods and members serve that one purpose.  This is called
/cohesion/.  A good design has very high cohesion.

Another word you'll hear in design is /coupling/.  Coupling is what
happens when two modules or objects depend on each other's internal
details; in other words, a single object isn't enough to serve a single
purpose.

Your current design has bad cohesion, because the app object serves
multiple poorly-defined purposes; it also has bad coupling, because the
player object needs to know the internal details of the objects it
contains.

>Now, thinking about your suggestions about the existence of the 
>app(lication) object, I searched through my Player class for uses of 
>the app object.

It's interesting that your Player class uses the app object; in other
words, the entire game is contained in the player.  Does this fit your
mental model of how a game's played?

My analysis is a little different:

A game contains a number of Players, one Draw deck, and one Discard deck.
There's one Current player, who is offered the chance to play; the game
passes to him some PlayerViews and the game's two decks.  A PlayerView can
report total mileage, invulnerabilities, speed limits, and battle status.

There's some elaboration to be done here; but it matters little.  You see
the basic idea of how I arrange the game.  Note that Player and PlayerView
are two seperate objects!  This is because the task of showing people your
cards is different from the task of playing the game.

>I found I mainly used the app object to:
>	* access basic data(e.g. the number of cards in a hand, the 
>number of miles necessary to win, etc.)

This seems intuitively global to the game at hand.  If your application
serves no purpose but to play MB, then this is sufficient.  If not, you
may have to do some more design -- some ideas occur to me, but time
prevents.

>	* tell the graphics object to do various things

Sounds like a good job for a Graphics object.

>	* ask the game object for various things

Sounds like a good job for the Game object.

>I had to use the app object for this because it included references to 
>the player objects, the game object and the graphics object.  
>Without the app object, I don't know how I would do these things.

The Players in my design are part of the Game.  Where, do you ask, can the
Display object go?  The best place, IMO, for it is in the HumanPlayer
object, which is one of the Players.  The Display object shows only what
the Game allows every Player to see.

>There were also some changes I thought I should make after learning about
>the LofD, etc.  I wanted to change the code for drawing a card to use a
>method of the game, instead of just accessing the deck list, and I wanted
>to have another game method to answer the question, whoIsShutout used when
>calculating scores.

>How would I do the above tasks without a app object?

Does my little analysis provide the beginning of an answer to you?

>I just now realized another reason for all the methods.  They allow fake
>testing methods to be simpler and easier to program, because they only
>need to fake answers to questions, or sometimes provide objects, not
>actually _do_ anything. Neat.

Yes!  Exactly.  Now you're discovering a new type of test-first
programming, called "test-first by intention." When you write test-first
by intention, not only do you write your tests before you write your code;
you also design your tests in the way that seems easiest, almost
regardless of how much it might take to code.

For examples of this (and a rationale), please read XP Installed.

>	Thank you very very much,

My pleasure!  Teaching is the best way to learn.

>		Jesse W

-- 
-William "Billy" Tanksley



More information about the Python-list mailing list