Monday, 28 February, 2005
I'm currently re-reading Martin Fowler's "Refactoring" and I saw an interesting design pattern in there.
It's called the Null Object and it's a really, really cool idea. You see most of the bug in our code base at work come from code that doesn't exist; that is, failure to test if the object we've requested returned null or not. Null objects obliterate this type of bug by effectively creating a "do nothing" class.
Here's how it works. Imagine we have an Account and Order class, there will be various properties and methods associated with both of these objects but for the sake of this discussion let's just distill it down to a couple of simple properties and methods.
With this in mind consider the following:
private void RandomMethod() { Account someBodysAccount = Account.Retrieve(100); Order someBodysLastOrder = someBodysAccount.GetLastOrder(); // Refund the Order someBodysLastOrder.Refund(); }
Spot the potential for the bug? If GetLastOrder returns a null the code will explode when you try to invoke the Refund method. The standard way of dealing with this is to check that the Order isn't null before invoking the Refund method but programmers have bad memories and some of these checks invariably get missed. Null Objects are sexy because they allow you to demolish these types of bug with greatest of ease.
With Null objects, you modify the program so that instead of GetLastOrder returning NULL if there's no order it returns a special version NULL version of the Order class. All the properties and methods are the same but the object itself doesn't do anything. In our case, the Refund method wouldn't do a thing: it'd consist of a simple return true. That way, if there is no last order the code still proceeds fine without the need for checking for nulls everywhere.
The same goes for the Account class too. We can have a NULL version of that class. Suppose that an account with the ID of one hundred didn't exist. The Retrieve method could return a NULL Account class. When the GetLastOrder method is invoked against that instance NULL Account instance it returns a NULL order object. Code execution then proceeds to the Refund line and that method simply returns true. I now give permission for you to cry for a moment or two, with excitement, as you ponder the number of if statements you can cull from your program using this technique.
Of course, like any technique it has to be used wisely. You have to be careful not to report success on methods that change the state of the system where in fact no change of state took place. In our example, I said our Refund method on a NULL Order object returned true - perhaps a more appropriate course of action would have been to throw a custom exception like "RefundAttemptedFromNullOrderException"
Even so, throwing exceptions like this is a far more informative than default c-sharp "Object reference not set to an instance of an object" exception. Plus, you can stick this exception in your NULL order class and you'll catch that error one hundred percent of the time regardless of the piece of code that attempts to do a refund.
I think all in all this is a powerful technique that has potential to remove a lot of boiler-plate code. I, for one, welcome our new NULL Object overlords!
Simon.