November 1, 2003 12:00 AM

A serial killer in the space-time continuum

serial_parallel.jpg

I had to simulate how weather affected the the race cars in the motor racing simulation I wrote about earlier. Weather is randomly chosen: there is a probability of rain for each race, each rain shower and dry period has a random duration, the rate of rainfall is randomised, there is a random temperature that affects tyre wear and the rate at which the track dries off, and so on.

I started with a Weather object that had a probability of rain and a random temperature, within some bounds. The Weather object randomised itself by reading random numbers between 0 and 1 from a Random object. This was easy to test: I used a mock random number generator that expected a sequence of two calls to nextDouble, the first of which was used to decide if it was raining and the second to calculate temperature.

I then extended the class to randomise the heaviness of rainfall. This broke my existing tests. Obviously, where the Weather object had asked for two random numbers it was now asking for three random numbers. Easy to fix, but my tests were still failing! Why?

It turned out that while adding random heaviness I had reordered the randomisation of the temperature and probability of rain to make the code easier to read. Lesson 1: I should not have been refactoring while adding functionality. But the goof made me realise something much more interesting. The true problem was not that I had mixed refactoring and implementation, but that the Weather object was making a sequence of calls to the same method of another object without there actually being a true temporal relationship between those calls. Each random number returned by the generator was, as far as the Weather object was concerned, completely independent of any other — that's the very definition of random, after all.

So, I changed the Weather object to hold multiple references to random number generators, one for each aspect of its state that it wanted to randomise. In tests it was passed multiple mock random number generators, so I could control each aspect of its state. In the production system it was passed multiple references to the same random number generator through a convenient constructor.

class Weather {
    public Weather( Random temperatureRandom, 
                    Random isRainingRandom, 
                    Random rainfallRandom )
    {
        ...
    }

    public Weather( Random randomness ) {
        this( randomness, randomness, randomness );
    }
}

But that gave me the uncomfortable feeling between my shoulder-blades that I always get when looking at bad code. All those Random parameters were an obvious code smell: too many parameters indicate that a new object should be factored out. And I could see that every time I added functionality to the Weather class I would need to add more random number generators, making the first constructor signature really awkward and, worse, I would break all existing code that uses that constructor.

So, I pulled the random number generators into a Weather-specific source of randomness with an abstract interface:

interface WeatherRandom {
    double nextTemperature();
    double nextChanceOfRain();
    double nextRainfall();
}

Now I could easily mock that interface in my tests and use a simple adapter in the running system that delegated to a Random object. This had the advantage that I when added functionality to the Weather class I only needed to add methods to the WeatherRandom interface, but didn't need to change any test code that tests existing random behaviour.

It is often the case that, as in this example, one object will make multiple calls to a single method of another. Such a design can lead to brittle tests if there is no true temporal relationship between those calls. That is, if the order of outgoing calls is not important to the functionality of the object under test, the tests should not place constraints on that order. If they do, changes to the object's internals might break unrelated tests. The solution is to refactor a sequence of calls to the same method into calls to different methods that can occur in any order.

One way to view these refactorings is that I replaced a serial interface with a parallel interface between the Weather and object and random number generator. Another viewpoint is that I used a spatial construct to describe a temporal aspect of my program's behaviour. The relationship between time and space in programming is something that James Coplien has written much about [1,2,3].

Posted on November 25, 2003 [ Permalink | Comments ]

The value of factories

I will not reason and compare: my business is to create. — William Blake

At Geek Night Joe Walnes, Steve Freeman and myself tried to come up with an example to use in live demos of using test-first programming with mock objects to drive iterative, top-down design. Our example was a fruit shopping application where the user could ask a directory to find the shop with a fruit at the lowest price, the nearest shop with a fruit at an affordable price, and so on, and then buy the fruit from the shop that was found. Our demo would be to pair-program the search functionality in front of a live audience.

Our design evolved well. The ShopFinder would search a list of shops by calling through an interface, ShopList. The ShopFinder would search the ShopList using an Internal Iterator as familiar to users of Ruby, Smalltalk or functional languages: the ShopFinder would create a "collector" object and pass it to the forEach method of the ShopList, which would call back to the collector and allow it to ask each shop for an offer on the fruit the user wanted.

I was pretty happy with this design. It follows the "Tell, Don't Ask" principle, which makes testing easy with mock objects. However, it required us to introduce an advanced feature of the jMock API too early in the demo — specifically, how to mock the side effect of the forEach method of the ShopList. So we abandoned that approach and instead tried others that were not very good, eventually giving up due to post-workday tiredness and general brain fade.

Our mistake was to hide the creation of a collector object within the ShopFinder that used it. This meant that we couldn't intercept the creation of the collector and replace it with a mock. By replacing a real collector with a mock we could have tested that the ShopFinder passed it to the ShopList by setting expectations on the ShopList and returned data to the ShopFinder by stubbing the collector instead of making the mock ShopList call back to the collector it received.

How could we have replaced a real collector with a mock? By giving the ShopFinder a factory with which it could create collectors and mocking the factory to return the mock collector(s) we needed in our tests. Even ignoring the needs of our demo, this change would have made our tests more readable. The factory would also act as a "flex point" which, experience has taught me, will make it easier to evolve the code in the future.

But it is very common for one object to create another. So common that one cannot practically replace every object instantiation with a call to a factory. Which object instantiations should be replaced by factories?

My initial conclusion is that value objects can be instantiated directly without causing problems because a test doesn't care about the value of a reference to a value object: the identity of a value object is defined by its state, not its reference. Neither does a test need to mock a value object because it doesn't care how it changes over time; after all value objects should be immutable. Behavioural objects (a.k.a. reference objects) are different: a test case need to compare references to test that the object is passed around correctly, and a test needs to mock the object in order to test that it is modified correctly while being passed around. So direct instantiations of behavioural objects should be replaced by the use of factory.

I have no idea whether this is useful, general design rule. And I don't really care! If my code needs a factory, the TDD process with mock objects soon drives that factory into existence — ignoring the need for a factory makes testing too painful otherwise. If my code doesn't need a factory the issue doesn't come up. TDD seems like magic sometimes; it's rather scary.

Posted on November 24, 2003 [ Permalink | Comments ]

Confounded by configuration

Sweet love, I see, changing his property, Turns to the sourest and most deadly hate. — William Shakespeare.

I recently wrote a simulation game as a Java applet for the website of a well known motor racing team. The configuration of the game — track, car performance, local weather and even the GUI layout and branding — was read from property files when the game started up.

The way I designed it, any object that needs to be configured implements the Configurable interface:

public interface Configurable {
    public void configure( PropertySet properties )
        throws ConfigureException;
}

Configurable objects construct themselves into some neutral, initial state which is then overridden by the values read from the property set (a set of name-value pairs) passed to the configure method.

The init method of the applet loads the properties, creates the objects it needs and configures them (or catches and records errors). Then the start method checks that everything is properly configured and ready to go and kicks off the animation thread.

A nice, simple mechanism? No. Another sodding mistake!

This architecture makes it much too hard to write unit tests. Any configurable object that needs to be used in a test must be configured, but that can only be done indirectly by creating a property set for it. There are several ways of creating property sets, but all of them have drawbacks. I can build property sets explicitly in the set-up phase of each test, but that makes the tests very verbose. I could load propertys set from files, but that splits test suites into separate code and data files, which makes editing tests a real pain. I could load a property set from a string constant is has the same drawback as building a property set explicitly, except with a worse syntax and more throws clauses. The problem is only compounded by composite configurable objects that must create and configure their sub-objects as directed by their own configuration.

As a work around, I could expose configurable properties of the objects as getters and setters, but methods that are only used for testing make me feel uncomfortable; they are a definite sign of a bad design.

The problem is with the architecture itself. The mistake was to hide configuration within the objects being configured. I should have pulled it out into one or more objects that interpret configuration data by creating objects with the appropriate state. I would no longer need the Configurable interface, because configurable properties would be passed to the objects' constructors. Tests could use the same constructors to create objects. The configuration interpreter would be easy to test by using a factory to create objects and using a mock factory object in tests. The mock factory would also make the configuration of composite objects trivial to test: creating a composite object would involve asking the factory to create a sub-object multiple times.

This is basically the GoF Builder pattern.

Oh well, I learn from my mistakes. Thank goodness.

Posted on November 17, 2003 [ Permalink | Comments ]

Buried under a sugar coating

scorpion-lollipop.jpg

Tim Mackinnon and I recently did a pair programming session to redesign the guts of the Java Dynamic Mock Objects implementation. One outcome of the session was a lot of methods that provided convenient "syntactic sugar" for setting up common expectations. Those sugar methods just delegated to lower level methods that let you define any kind of expectation in a long winded but extensible manner.

Unfortunately we forgot to make the lower level methods public. The flexible, extensible core was inaccessible to users of the API, who soon started asking awkward questions on the mailing list.

Memo to self: syntactic sugar is layered above an API as a sweetener. Implement the powerful, low level API first. Any kind of sugary syntax can be implemented afterwards.

Posted on November 15, 2003 [ Permalink | Comments ]