Wrap Null
Don't let null infest your code, wrap it into Optionals.
Should your code break because it lied ?
Because where you expected a value, you got a null ?
No, it should not.
Null is a disease. In the worst situations, it can pretend to be an object but really isn't. Java is a notorious example.
This code looks fine, but the devil is lurking in the shadows.
Because Java will happily let anyone pass null to that add function.
Fortunately, there's a cure. Sort of.
Except it doesn't really work. It's, at best, a hint, at worst, just wasted text. The compiler won't prevent you from passing null to that method.
Now that the infection is spread, we have to resort to runtime checks.
And now these checks must spread through the code base, everywhere, again and again.
The gods are punishing our stupidity and we deserve it.
Is there any solution ? Sort of.
We can conventionally refuses Null to appear at some layer of our code.
Airlocking
You see, every program has a consistent structure : a layered structure.
There's the entry point of the program, the one users of the program use directly : the Presentation Layer.
There's the core of the program, dealing with business logic and manipulating our rich objects : the Domain Layer.
And there's a bridge connecting the two. In the Pragmatic Objects approach, we call it the Service Layer. Some also call it the UseCase Layer.
That Service layer contains what I like to call an airlocking mechanism. Whatever comes inside that layer is syntactically valid, and nulls are explicit. Thus, once we are in this layer, we can be assured that not a single undeclared null will appear.
That airlocking mechanism can be a simple function call before entering the service, or an automated middleware system using annotations.
In NestJS, I would use the following for example.
By the time the command enter the handler's execute method, the input is sanitized.
So our Duration class shouldn't have to consider the case where the values given are nulls. We just have to assume they won't ever be and let our Airlocking system protect it.
However, some code inside that Service layer may (will) call other services from the outside world such as a database or an external API, which can give us nullables.
The best way to deal with these nullables is to acknowledge their existence and transform them into an actually useful construct : Optionals.
Optional
The concept is directly borrowed (shamelessly stolen) from the functional programming concept of Maybe monad.
It's a simple object : either it has a value, or it doesn't.
In practice, we rarely have the occasion of wrapping inputs into Optionals. If we receive JSON, for example, we can directly receive nulls, so we can make null checks directly.
But when fetching an entity from the database, it's useful to have a type that allows us to return a value if it exists, or the absence of value if it doesn't. But we shouldn't trick the client of that function call into believing they will always receive a value.
So we should make it explicit by using an Optional.
This way, clients can either directly throw an error in the absence of the value, or take specific actions. But in both case, it's made explicit.
And the bonus : we get a proper "absence of value" mechanism. One that doesn't throw unexpectedly.
Last updated