DEV Community

loading...
Cover image for Code Smell 12 - Null

Code Smell 12 - Null

Maxi Contieri
Learn something new every day. - I am a senior software engineer working in industry, teaching and writing on software design, SOLID principles, DDD and TDD.
Originally published at maximilianocontieri.com Updated on ・2 min read

Programmers use Null as different flags. It can hint an absence, an undefined value, en error etc.
Multiple semantics lead to coupling and errors.

TL;DR: Null is schizofrenic and does not exist in real world. His creator regreted and programmers around the world suffer it. Don't be a part of it.

Problems

  • Coupling among the callers and the senders.

  • Mismatch among the callers and the senders.

  • If/Switch/Case Polluting.

  • Null is not polymorphic with real objects. Hence, Null Pointer Exception

  • Null does not exist on real world. Thus, it violates Bijection Principle

Solutions

Exceptions

  • APIs, Databases and external systems where NULL does exist.

Sample Code

Wrong

class CartItem{
  constructor(price) {
     this.price = price;
  }
}

class DiscountCoupon {
  constructor(rate){
    this.rate = rate;
  } 
}

class Cart{        
    constructor(selecteditems, discountCoupon){
        this.items = selecteditems;
        this.discountCoupon = discountCoupon;
    }     
    subtotal(){    
        return this.items.reduce((previous, current) => previous + current.price, 0);      
    }  
    total(){    
        if (this.discountCoupon == null)
          return this.subtotal();
        else
          return this.subtotal() * (1 - this.discountCoupon.rate);      
    }
}

cart = new Cart([new CartItem(1), new CartItem(2), new CartItem(7)], new DiscountCoupon(0.15));
//10 - 1.5 = 8.5

cart = new Cart([new CartItem(1), new CartItem(2), new CartItem(7)], null);
//10 - null  = 10
Enter fullscreen mode Exit fullscreen mode

Right

class CartItem{
  constructor(price) {
     this.price = price;
  }
}

class DiscountCoupon {
  constructor(rate){
    this.rate = rate;
  } 
  discount(subtotal){
    return subtotal * (1 - this.rate);    
  }
}

class NullCoupon {    
  discount(subtotal){
    return subtotal;    
  }
}

class Cart{        
    constructor(selecteditems, discountCoupon){
        this.items = selecteditems;
        this.discountCoupon = discountCoupon;
    }     
    subtotal(){    
        return this.items.reduce((previous, current) => previous + current.price, 0);      
    }  
    total(){    
        return this.discountCoupon.discount(this.subtotal());      
    }
}

cart = new Cart([new CartItem(1), new CartItem(2), new CartItem(7)], new DiscountCoupon(0.15));
//10 - 1.5 = 8.5

cart = new Cart([new CartItem(1), new CartItem(2), new CartItem(7)], new NullCoupon());
//10 - nullObject  = 10
Enter fullscreen mode Exit fullscreen mode

Detection

Most Linters can show null usages and warn us.

Tags

  • Null

Conclusion

  • Null is the billion-dollar mistake. Yet, most program languages support them and libraries suggest its usage.

More info

Credits

Photo by Kurt Cotoaga on Unsplash


I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

Tony Hoare


This article is part of the CodeSmell Series.

Last update: 2021/06/16

Discussion (2)

Collapse
jayjeckel profile image
Jay Jeckel

The ridiculous cargo cult hate that null has developed in recent years is one of my pet peeves, but I'll try to avoid a full blown rant and stick to one incorrect premise of this article: "Null does not exist [in the] real world."

Null absolutely exists in the real world. You know what I'm holding in my hand right now? Nothing, ie null. I'm not holding an object that represents nothing, I'm holding nothing, no thing, not anything. There is no better code representation of that state than null. What smells is this modern demand that we all pretend an object can represent no object.

You know what doesn't exist in real life? Anything resembling a NullCoupon. Besides that, you are now instancing yet one more object that has to be tracked and garbage collected, all because of some irrational dislike of null. So in addition to being a less accurate representation of the real world, this pattern is also less efficient.

Tony Hoare is wrong, he did not make a mistake by including null, because null is a valid state, both in programming and the real world, and coders making mistakes like not checking for null isn't a problem with null any more than not checking for 0 before division is a problem with 0 itself.

Collapse
mcsee profile image
Maxi Contieri Author
  • you hold "nothing"
  • a baby has 0 years
  • The space has vaccuum
  • My wallet has no money

Different things with different behaviors.

I keep thinking Tony Hoare is right :)

I will stick to this Besides that, you are now instancing yet one more object that has to be tracked and garbage collected. and the answer is 'who cares about GCs?' We are talking about good models, no premature optimization leading to early and tight coupling.