Archive

We’re running a “Software Craftsmanship Study Group” in our office. There we are currently going through Robert C. Martin’s book Clean Code. In our meeting this week, we talked about the chapter of error handling (written by Michael Feathers) and came into a discussion about null objects.

The book advises that you should have a policy of never returning null and, even more importantly, never accepting null as an argument to your methods.

Most people agreed on the latter principle (though there were some debate), as accepting null as an argument

is really a hidden overload of the method

requires the caller to know something about the internal of the method called (that null is a possible option)

reads no better than boolean flag when reading the code

But we had some debate about never returning null. In the case where your method return a collection, it is easy. Just return an empty collection. But what about the other cases?

One pattern that came up was returning “null objects”. A null object is an object that has the same interface as the object you’re expecting from the method, but with no real data behind. A mock, if you wish. The problem with null objects is that they don’t really help much when used. You will often end up writing tests like

if (!result.IsNull())
// do something...

which isn’t really much better than

if (result != null)
// do something...

In fact, it’s possibly a bit worse, since programmers tends to be unsure if they should do the one or the other, and then end up doing both

if (result != null && !result.IsNull())
// do something...

I’ve seen an API that tried to help the users with this by overloading the == operator for the null object to return true when it is compared with null. But as this was in C#, we got a new problem since this overload was not used by the ?? operator. So now, in the following code:

a and b would no longer have the same value. And since refactoring tools like JetBrain’s ReSharper often will suggest replacing the second form with the first, there is a potential for bugs sneaking in.

Another issue with the null objects is that they may be used for a while, but then they are used in a call that causes an exception. It then becomes harder to debug and figure out where the error originated, since the real problem is not where the exception is thrown.

So more often than not, it would better to just throw an exception if there is nothing to return, and add an extra query method that can be called before asking for the result to check if any result is ready (Is… or Has…).