The consequences are bug fixing which checks if:
- input is null
- if interface calls return null
- if method calls return null
- if properties and collections are null
So this original pizza ordering method:
public void orderPizza(PizzaOrder pizzaOrder){
for( Pizza pizza : pizzaOrder.getPizzas()){
kitchen.makePizza(pizza);
}
}
Morphs into this:
public void orderPizza(PizzaOrder pizzaOrder){
if( pizzaOrder != null) {
if( pizzaOrder.getPizzas() != null ||
Collection.isEmpty(pizzaOrder.getPizzas())) {
if( kitchen != null) {
for( Pizza pizza : pizzaOrder.getPizzas()){
if( pizza != null) {
kitchen.makePizza(pizza);
} else {
throw PizzeriaTechnicalException(“No pizza!!!”);
}
}
} else {
throw PizzeriaTechnicalException(“No kitchen!!!”);
}
} else {
throw PizzeriaTechnicalException(“No pizzas in order!!!”);
}
} else {
throw PizzeriaTechnicalException(“No pizza order!!!”);
}
}
(Or alternativly many “assert pizzaOrder != null” that are useless in production)
Madness, and very messy.
Blinkered coding standard:
This happens when code ownership is not clear, when desire for clean code is not existant, when fixing bugs with blinkers on.
When developers are time constrained or scared of changing code.
When development is outsourced but authority and knowledge is not, so refactoring is avoided or not part of SLA.
Why are we so afraid of NullPointerExceptions?
What is wrong with null?
Null is okay. Null is exactly that. Don't avoid it like the plague, but try to not pass the problem to others. Tidy up your gateway interfaces, trust internally null does not happen. If it does then don't hide the problem.
Do not check for null inside you application. Check for null on your edges:
Validate user interface inputs. “Users” are always causing trouble, but we can not live without customers. Validate the essentials, but remember duck walking, don’t scare your customers with perfection validation.
Validate external 3rd party api interfaces. Probably validate internal api interfaces. Remember duck walking. If an internal system quite close to your application erroneously passes null values, fix that system instead. It is a gray zone however so some null pointer validation is fine. Just don’t complicate your system because of the laziness of another within your team/company.
Do not validate calls between your applications layers. Trust the edges has validated the data. Use unit tests to ensure integrity.
Dealing with NPE/Null?
If you encounter a Null or anything resembling empty when not possible etc: throw a NullPointerException. Don’t sugar coat and masquerade it as something else. An NPE is an NPE! It says what it is on the tin! It is easily understood by all developers, and easily traced. Obviously don’t show that to the end user, but don’t catch it too far down your stack.
If you get bug report about an NPE. Fix the edge validation, factory generation or inside the api call. Do not add a “== null“ condition inside your application.
It is easier to avoid internal NPE by not passing external DTO and domain objects through your own application. If you act on it, it should be your applications objects, not an external one. This avoids complicated null pointer validation.
“Clean Code” book suggest “specific case object” for method calls that may previously return null. I am not a big fan, but it may solve internal api NPEs. I definitely support the pattern of returning empty collections in find* calls instead of null when nothing was found.
How would I deal with Null in the Pizza Order scenario?
PizzaOrder object should be validated beforehand in the interface layer. It is not the responsibility of this method.
Same layer before this method should call a factory method that sets pizzas collection to an empty collection if no pizzas.
Kitchen is always injected or constructed externally to this method and not its responsibility.
Factories in mapping/creating the PizzaOrder before this method call should also ensure no Pizza objects are Null.
The one possible valid check is if there are any pizzas in the order. The
Collection.isEmpty(pizzaOrder.getPizzas())
But it is not a null pointer check, as previous interfaces/factories will ensure a collection object exists. However the interface or application before this method call should probably have validated the actual order, to ensure an order contains pizzas!
So Null is okay and NullPointerException can be your friend.
No comments:
Post a Comment