Why overusing NULL is a bad idea

The best and first approach to Software Engineering should be critical thinking. Critical Thinking means “the objective analysis and evaluation of an issue”. The objective analysis in this article is about the NULL references, a concept, created by Tony Hoare, that is present in almost all programming languages.

In this article we want to explain why the NULL reference concept, usually adds needless complexity, and how it represents a meaningless state which can’t even be representable, in a real world context.

As publicly disclosed by the creator itself of the NULL reference, Tony Hoare, the concept is a “Billion-dollar mistake”.


Let’s see some examples

<?php
namespace WebEngVox\Dublin\Pub;
class BurgerRepository {
public function getById($id) {
$burger = $this->db->query('SELECT * FROM ...');
if (!$burger) {
return NULL;
}
return new Burger($burger);
}
}
$burger = $burgerRepository->getById(10);
// I know, should check the NULL burger, maybe ...
$customer->eat($burger);

As you can guess, I love pubs, beers and burgers. What is better, to approach a scenario that I’m comfortable with, rather than using theoretical examples.

Look at the context, does it really make sense to return null? Will the customer ever eat a null Burger? Even that, in languages like PHP (Yes I use PHP !!1!!), if you’re not type-hinting the Burger, it will cause issues inside the Customer class, (maybe it will, we don’t know). So it’s not rather a Fail Fast approach, which means, there is a failure, but it won’t be caught as soon as it occurs, but will flow in the system for a while. If you’re using type-hinting you’ve to check anyway the null Burger before passing it to the customer, adding needless complexity and increasing the cyclomatic complexity of our codebase.

Let’s see how I’d address this issue in the first place

<?php
namespace WebEngVox\Dublin\Pub;
class BurgerRepository {
public function getById($id) {
$burger = $this->db->query('SELECT * FROM ...');
if (!$burger) {
throw new BurgerOutOfStockException;
}
return new Burger($burger);
}
}

So following also the “Throw early, catch late” mantra, we want to throw an Exception as soon as the error occurs, or in this case, when we ran out of Burgers.

We can see that in this case, we’re far from machine thinking and closer to real world thinking. We can run out of Burgers, but a Burger can’t be NULL, it doesn’t make sense.


<?php
namespace WebEngVox\Dublin\Pub;
class BeerProviderRepository {
public function getById($id) {
$provider = $this->db->query('SELECT * FROM ...');
if (!$provider) {
return BeerProvider::NOBODY;
}
return new BeerProvider($provider);
}
}

Yet, we added another silly, but simple example. We want to order a new stock of beer bundles, we need to retrieve a BeerProvider to do so.

Here we’ve the same issue as before, instead of returning a NULL reference, we use the Null Object Pattern and we return a default value for the BeerProvider object. The idea is that, that Null Object should have a common interface with the object itself and so we don’t need particular logical checks on the returned value.

It’s always up to you and based on your context to choose the right approach, let’s recap on why a NULL reference is bad

  • It means “machine thinking”, over “Object Thinking”
  • Needless complexity
  • Meaningless state
  • It’s not a Fail Fast approach

Why then many languages admit NULL?

In my opinion because, when first languages were being implemented in the 60’s/70’s there were not much rigor and importance to focus on Object Orientation and there were many other problems to solve, whereas NULL was not seen as dangerous as it’d be.

Still, there are different languages that don’t use NULL or implement it in a different way, like the Maybe type in Haskell for instance


Thanks for reading!