Wednesday, April 13, 2011

Quality Starts Small: Removing Null Checks

This is a good example of how to remove null checks in your code. Null checks make your code harder to understand and add little value. Don't misunderstand me, for code to have any quality at all it must handle null values well. However, to make your code more maintainable and reliable it can be advantageous to code in a style that doesn't litter your code with null checks. Refactoring the source of your null to it's own function is one way to handle this issue and I've illustrated this technique below.

Null checks may also represent code that is trying to do too much (SRP). Quality is hard to ensure if a function has multiple responsibilities. Checking for null in the middle of your function probably represents defensive coding to protect against a reference which was given to you as null and not a proper instance of whatever type you were expecting. If you move responsibility for dealing with the null to it's own function your code will become cleaner. Cleaner code is easier to understand and maintain.

The code below uses the excellent .Net XElement utility class. This class rocks. When you ask for a sub XElement, the design is to return null and not throw an exception if the sub XElement you've requested can't be found. This is a reasonable choice for a utility, but it may not be what we want to live with in our code.

The code below is part of a an .Net XElement wrapper for parsing XML and it requests a sub XElement called "Deployments." This is the source of the null value that we want to get out of our code.

There are many ways to handle a null value and this example shows just one.  The context for this example is that we are calling an API which is returning null and we are forced to defensively code around the null value but null itself has no meaning to us - we would prefer an empty element.   This may not always the case and you would probably need another solution.  In our case, we want to perform the same functions whether the node is a fully populated XElement or an empty one.
We need to refactor the following code with a null check:

private IEnumerable GetDeployments()
{
    var deployments =  new List();
    var deploymentsElement = Node.Element( Namespace + "Deployments" );
    if( deploymentsElement != null )
    {
        var deploymentsNode = new DeploymentsNode( deploymentsElement, Namespace );
        return deploymentsNode.ExportAsDeployments();
    }
    return deployments;
}

The reason for the null check is that Node.Element(Namespace + "Deployments" ); can return null.

If you factor that code out into a function like this and instead of having it return null we return an empty "Deployments" XElement that we create, our original code can use it without concern for null checking:

private XElement GetDeploymentsNode()
{
    var deploymentsElement = Node.Element( Namespace + "Deployments" );
    return deploymentsElement ?? new XElement( "Deployments" );
}
 
You can then update the original function to remove the null check and it looks like this:

private IEnumerable GetDeployments()
{
    var deploymentsNode = new DeploymentsNode( GetDeploymentsNode(), Namespace );
    return deploymentsNode.ExportAsDeployments();
}
 
The refactored code, with null handling hidden inside a method looks like this:

private IEnumerable GetDeployments()
{
    var deploymentsNode = new DeploymentsNode( GetDeploymentsNode(), Namespace );
    return deploymentsNode.ExportAsDeployments();
}  

private XElement GetDeploymentsNode()
{
    var deploymentsElement = Node.Element( Namespace + "Deployments" );
    return deploymentsElement ?? new XElement( "Deployments" );
}
 
Which is much easier to understand and maintain than the original code.

(Obviously this is sample code: You wouldn't want the hard coded strings in your final code and it would all need to be wrapped in a try/catch. This example illustrates a specific technique for removing null checks and does not represent production quality code. Thanks)