Programmer and (aspiring) software craftsman. Interested in FP, Clojure, OOP, software design and programming in general.
52 stories
·
0 followers

Avoid Null Checks by Replacing Finders with Tellers

1 Share

One of my pet peeves in programming is null checks.  Many codebases are littered with them and, as a result they are often very hard to understand.

 It's easy enough to complain about null checks, but it's harder to root out all of the places they occur and find alternatives.  The typical advice is to move your code toward using the null object pattern or to just check for null immediately and make sure that you don't pass nulls along in your program.  After all, we do often need to retrieve objects and sometimes they aren't there. 

Let's re-examine that.

Do we really need to retrieve or find objects in our programs?

The other day, I saw this example on StackOverflow:

    Person person = dataSource.getPersonById(personId);
    if (person != null) {
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }

This looks like a typical case where we need a null check.  We attempt to find a person from a datasource we could get a null return value.  We could change the code to return a null object, a person object that simply does nothing and that could solve the problem.  The could would look exactly the same except that it would be missing the null check.  The setPhoneNumber function would simply to nothing, and the updatePerson function would have the good sense not to add the null object to the database.

Yes, would could do that, but it is a bit of work. There is an alternative that we can use if we get ourselves out of the mindset of asking for objects.

Consider this bit of Ruby code:

    data_source.person(id) do |person|
      person.phone_number = phone_number
      data_source.update_person person
    end

The person method accepts an id for a person and a block.  If the person is found the block is called with the person.  Otherwise it isn't. Elegant, eh?  And, there are no nulls.

Lots of luck doing this in a language without blocks or lambdas.  I think that when the history of computing is finally written, one of the chapters will be about how much insanity thrived in the era before blocks were considered mainstream.  In fact, I think we can argue that null checks became common precisely because most languages haven't had blocks until recently.

Imagine doing this in Java without lambdas:

    dataSource.person(id, new Action<Person>() {
        public void act(Person person) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        }
    });

My eyes bleed. My soul too. It's no wonder why null-littered code is common in today's Java.

This "teller method" pattern may seem like a special case, but it isn't.  One of the core ideas in object-orientation is that it is better to tell than to ask. When we tell someone to give someone else a thing, it either does it doesn't. There's no need to check for an error.

So, whenever you receive null from an API you've written, don't complain.  After all, you asked for it. Consider telling the result to someone instead.

 

Read the whole story
manuelp
2487 days ago
reply
Universe
Share this story
Delete