Code Smell 126 - Fake Null Object

Maxi Contieri - Apr 2 '22 - - Dev Community

Null Objects are great alternatives to The Billion Dollar Mistake. Sometimes we don't need them

TL;DR: Don't abuse patterns. Even NullObject.

Problems

  • Empty Classes

  • Namespace Polluting

  • Duplicated Behavior

Solutions

  1. Create Null Objects instantiating real-object classes.

Context

Null Object pattern is a great alternative to Nulls and IFs (Both are code smells).

The structure of the pattern tells us to create a hierarchy.

This is not really necessary, we need real objects to be polymorphic to null objects.

Inheritance is not a proper way to achieve polymorphism.

A simple solution is to create a real object behaving like a null one.

For example: '0' is numbers' null object.

'' (or "") is String's null object

An empty collection is collection's null object.

Sample Code

Wrong

abstract class Address {
    public abstract String getCity();
    public abstract String getState();
    public abstract String getZipCode();
}

//Using inheritance for null objects is a mistake
//We should use interfaces (when available)
public class NullAddress extends Address {

    public NullAddress() { }

    public String getCity() {
        return Constants.EMPTY_STRING;
    }

    public String getState() {
        return Constants.EMPTY_STRING;
    }

    public String getZipCode() {
        return Constants.EMPTY_STRING;
    }

}

public class RealAddress extends Address {

    private String zipCode;
    private String city;
    private String state;

    public RealAddress(String city, String state, String zipCode) {
        this.city = city;
        this.state = state;
        this.zipCode = zipCode;
    }

    public String getZipCode() {
        return zipCode;
    }

    public String getCity() {
        return city;
    }

    public String getState() {
        return state;
    }

}
Enter fullscreen mode Exit fullscreen mode

Right

//There are just "addresses"
public class Address {

    private String zipCode;
    private String city;
    private String state;

    public Address(String city, String state, String zipCode) {
    //Looks anemic :(
        this.city = city;
        this.state = state;
        this.zipCode = zipCode;
    }

    public String zipCode() {
        return zipCode;
    }

    public String city() {
        return city;
    }

    public String state() {
        return state;
    }

}

Address nullAddress = new Address(Constants.EMPTY_STRING, Constants.EMPTY_STRING, Constants.EMPTY_STRING);
//we have our null object
//we should NOT assign it to a singleton, static or global
//It behaves like a null object. That's enough
//No premature optimizations

Enter fullscreen mode Exit fullscreen mode

Detection

[X] Manual

This is a semantic smell.

Tags

  • Null

Conclusion

Creating Null Object classes is sometimes overdesign.

We need to create a real object.

This real object should never be global, singleton, or static.

Too many smells to avoid.

Relations

More Info

Credits

Photo by Juan Davila on Unsplash

Thanks to Hernan Wilkinson for this idea on his course Diseño a la Gorra (in Spanish)


All models are wrong but some models are useful

George Box


This article is part of the CodeSmell Series.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .