Null Objects to the rescue

Over the last few weeks, I rediscovered one of my favourite superheroes. It could lift up Thor's hammer in a second and would kick hulks butt with ease. I am talking about the Null Object

What is a Null object?

So what is this super powerful Null Object I am talking about? If you are a friend of the simple explanations you could just say a Null Object is just a dummy object, but that would not do it justice. To really appreciate the Null Object you have to understand what problem it solves.

The Problem that we have to solve is the existence of NULL.

NULL is a pain in the butt

Developers didn’t have to deal with NULL since the beginning of programming. NULL was introduced to the world of programming in the year 1965 by the same person who invented the quicksort algorithm Sir Charles Antony Richard Hoare(To be fair, even Sir Hoare thought that the invention of NULL was a big mistake). But why is the existence of NULL a problem? Please consider the following:

Any nullable type has two different non-matching Interfaces. We can simply show those two interfaces with the example of the String class

<!DOCTYPE html>  
<html>  
    <body>  
        <h2>JavaScriptTest</h2>  
        <p id="text"></p>  
  
        <script>  
            var str = null; 
            var pos = str.indexOf("a");  
            document.getElementById("text").innerHTML = pos;  
        </script>  
    </body>  
</html>

The script will obviously fail and result in the following error Uncaught TypeError: Cannot read property 'indexOf' of null

Such an error is very unpleasant. One of my former chief architects used to say “if you produce a NullPointerException you could as well work as a garbage collector”. I don’t know why he wasn’t keen about garbage collectors but I think you get the drift. I am not of the same opinion because NullPointerExceptions can easily happen but they are a preventable problem.

So how do you prevent the NullPointerException from happening?

  1. You could say: “Well of course by checking for NULL!” but this results in another Problem, you have to check every object you encounter for NULL to be absolutely sure that you don’t have a problem at hand.

  2. You could use only Datatypes that are not nullable but by this, you restrict yourself very hard.

The best option we as developers have is to protect our borders by NULL checks and never use NULL in our realm. What do I mean with borders and what is the realm of our program? All public methods are borders because everybody can send us their NULLs, undefines or whatever breaks our precious code. All private and internal methods, this means everything that is under our control can live without those checks. Why don’t we need these checks in our realm? Simply because we secured our borders and we commit to sticking to our Null Objects. Save from the outside by checks and save from the inside by convention. No NullPointerExceptions anymore!

How is a Null Object Built?

So let's dissect the Null Object pattern and see how a Null Object is built.

public interface Shape
{
    double GetVolume();
    bool IsNull();
}

public class Circle : Shape
{
    private double _radius;

    public Circle(double radius)
    {
        this._radius = radius;
    }

    public double GetVolume()
    {
        return 2 * Math.PI * this._radius;
    }

    public bool IsNull()
    {
        return false;
    }
}

public class Square : Shape
{
    private double _sideLength;

    public Square(double sideLengt)
    {
        this._sideLength = sideLengt;    
    }

    public double GetVolume()
    {
        return Math.Sqrt(this._sideLength);
    }
    
    public bool IsNull()
    {
        return false;
    }
}

public class NullShape : Shape
{
    public NullShape()
    {
    }

    public double GetVolume()
    {
        return 0.0;    
    }

    public bool IsNull()
    {
        return true;
    }
}

When shouldn’t you use it

Fail fast

If you like to fail hard and fast then you shouldn’t use the Null Object pattern. Debugging a NullPointerException is more or less easy. Of course, there are sometimes NULLs that are passed all around our source code and the exception does not occur on the exact spot where the NULL goes in but more often than not the NullPointerException is easy to fix with a simple check for NULL.

To be clear, I wouldn’t advocate the fail hard and fast way of coding in this particular case. No NULLs mean no NullPointerExceptions, there are of course other problems that might arise, which are logical problems but three NULL Pointers vs one logical problem is a big difference in a project with a lot of customers.

Let’s assume you write software package which is deployed once a month and the end user has to install it. A logical error might be inconvenient but a hard fail with a NullPointerException is just plain shit.

A customer in fear of a crashing system is bad. As bad as it sounds but customers find ways to trick misbehaving software but a crashing software will make them go apeshit.

Complexity

Another consideration might be, that if your Null Object is not “simple”. The more complex the objects get the more it is likely to cause errors and those errors are as said hard to find. There is a fine difference between good and too much and sometimes less is more

… but sometimes more is the answer. If your NULL Object gets too complex and this is due to too many ifs then it might be a good consideration to use multiple Null Objects. Ifs in a Null Object could mean that there are several default behaviours.

You are not in an OO Language

If you are for example in a functional language and you like this paradigm better then I guess Null Objects are a bad choice (If you have different insights then please send me an E-Mail telling me about your experience).

How about Exceptions?

As we have seen the Null Object relies on a standard behaviour but we don’t always have a default behaviour or a default state which we can pass around and be sure that our program will run flawlessly. In situations such as this, where the program state is corrupted, we have nothing left than to throw an exception(Or the prefered alternative of your choice) ourselves. You might think “great we avoided a NullPointerException just only to throw another Exception”.

At first, this sounds correct but think about REST APIs. If your Code fails with a NullPointerException this would normally mean that we send a result code of the type 5xx. The HTTP status codes beginning with a 5 state that a server error occurred and the user can’t do anything about it. Now think about sending a custom exception which results in a 4xx status code. The exception will tell the user exactly what the mistake/error was and then he can act accordingly.

Watch out for the memory usage

To reduce the memory usage we can transform our NULL Object to a singleton. Normally I wouldn’t advise singleton Objects because of their downsides(testability, threading etc.) but in a scenario where memory matters we should really consider a singleton. The downsides of singletons may be ignored here.

You could also consider a singleton if your NULL Object doesn’t have any state which it transports.

Go back
This page uses cookies: READ MORE ;