Builders should use objects, not their IDs

I realised something this week, that is pretty obvious, but still I hadn’t managed to think about it until now.

Sometimes I’m writing tests that store data to database, retrieve it and perform calculations on it (and usually store even more data in database as a result). Business objects can be complex to construct, so various builders are used to take care of that. And to link those created business objects together, I pass values of one business object to a builder, in order to construct something else:

Dim racer = RacerBuilder.Create() _
                        .with_name('Rosberg') _
                        .build()

Dim race = RaceBuilder.Create() _
                      .with_name('Monaco') _
                      .with_racer(racer.id) _
                      .build()

Ok, seems to work (well, it does work), but it has couple problems.

First problem is that now racer.id has been exposed to the reader of the test. If test doesn’t have anything to do with the id, it really shouldn’t be visible there. Only thing it manages to do is to confuse the reader.

Second, more subtle problem is that maybe creation of racer is really slow and developer decides to cut corners and just uses data that already is in the database. He skips creation of racer and creates race, using pre-existing data. It might work until database gets a total clean up or racer gets deleted for what-ever reason. After the racer doesn’t exists anymore, test starts failing and somebody has to fix it by entering that racer back to database. Now imagine that there are hundreds of tests like that and database gets erased or system needs to be moved to a completely new database system.

Better approach would have been to forbid linking of race and racer to begin with and used following code:

Dim racer = RacerBuilder.Create() _
                        .with_name('Rosberg') _
                        .build()

Dim race = RaceBuilder.Create() _
                      .with_name('Monaco') _
                      .with_racer(racer) _
                      .build()

Now the racer has to exists before it can be linked to a race. Also, the test now hides the fact that racer has id. It’s irrelevant in this imaginary test. In some other context it might be relevant. Next week I’m probably going to realise at least dozen exceptions to this rule.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s