Active Record Associations and the Null Object Pattern

Posted by Craig Ambrose on September 22, 2006 at 09:55 PM

Many of you may be familiar with the Null Object Design Pattern. I can’t recall where I first encountered it, although I know that it is not in the gang of four’s “Design Patterns” book. A quick googling reveals this link which seems to explain the pattern quite well in detail.

To summarise, a null object is an object which we use when we have some sort of optional association, instead of returning a null (or in ruby, nil) value. Lets say that class Vehicle has a method which returns it’s engine (an instance of class Engine). The problem is, occasionally vehicles don’t have an engine, and so everywhere that we want to access the vehicle’s engine, we must check for nil, for example:


class Vehicle
def engine
#this method returns an engine, take my word for it
end def status
engine.nil? ? 'unknown' : engine.status
end

Not only does this status method seem uneccessarily complex, it also forced us to make a decision about what status string to return for a nil engine. That’s ok, but what if we have to do this somewhere else? Are we really making putting this constant in the right place?

Also, as we add more and more methods to Engine, this gets uglier. Vehicle ends up wrapping every method in engine, so that calling code wont accidentaly use a nil engine for something. This kind of encapsulation is a two edged sword. It’s good, because it helps decouple the contents of Vehicle (such as Engine) from the clients of Vehicle, allowing us to change the way vehicle works without breaking anything. It’s also well suited to unit testing. However, the trade off is that if you do this everywhere, you’re classes grow far too large.

In the case where we don’t want to wrap up engine, or we want to centralise our behaviour for not having an engine, the Null Object pattern comes in. We’re going to want an object which represents the nil engine, and does things like return “unknown” as it’s status. However, we don’t just use a special instance of class Engine, we actually create a new class, as some methods of engine might be computed, and we still want them to do nothing and return sensible null values.

In a strongly typed language, our classes Engine and the new NullEngine would both implement the same Interface, allowing us to use them interchangably. Ruby, however, doesn’t care about this, so the classes don’t need to be related at all, except in the eyes of the programmer.


class NullEngine
def status
'unknown'
end
endclass Engine
def status
#return real status value, perhaps from the database
end
end

I like to add a class method to Engine that returns a NullEngine object, for convenience. I also think that all NullEngine objects should equate as equal. You could either do this by making NullEngine a Singleton (so that only one instance ever exists), or by overriding it’s equality operator so that it always returned true when compared to other null objects. I prefer the latter, as it seems to be more foolproof.

The final remaining touch is to slot the object in so that it is used by Vehicle. In a rails app, Vehicle and Engine are likelly to be active record objects, and Vehicle probably belongs_to Engine. What we need to do is override the method that returns the engine, and returns a NullEngine if we don’t have a real one. We don’t want to get in the way of assignment of engines though.


class Engine
def self.null_object
NullEngine.new
end
endclass Vehicle
alias_method :original_engine, :engine def engine
original_engine.nil? ? Engine.null_object : original_engine
end
end

I’m afraid I can’t quite get out of the habit of calling it a Null Object, rather than a Nil Object to keep the other ruby folks happy, but it doesn’t much matter.

Now, clients of a Vehicle can go round calling vehicle.engine.status to their hearts content, or any other methods of engine, safe in the knowledge that they wont end up calling methods on a system Nil object. I used this pattern yesterday, and it cleanned up a whole lot of code for me. Don’t run around saying, “Craig said we don’t have to encapsulate aggregated objects anymore, let’s go crazy!”, but do consider how the Null Object pattern can work for you, particularly as in ruby, it’s just so damn easy.

Tags: (none)
Hierarchy: previous, next

Comments

There are 11 comments on this post. Post yours →

I like this pattern and have used it before, but not in Ruby. What do you think about adding more behavior so it can also act like an actual nil? Adding singleton methods nil? and blank? (and maybe a few more) would let each null object also act like nil, which is pretty cool. Also, I’d probably make the null object a singleton, just for cleanliness.

Nice writeup, and a good reminder.

Craig

Hi Josh, you’re right, more can definatelly be added to this, but actually I’m not convinced that adding nil? would be a good idea. I’m concerned that this would encourage people to check if the object was nil, and if so, do something else. The NullObject is supposed to encapsulate the nill behaviour itself, so no one else need know about it. Although, on the other hand, nil? might be handy when deciding not to save the object to the db, and so on. So in summary, I’m undecided. :)

Craig, the example of the NullPattern you cited was done in Java, which is statically typed and more limited than Ruby. Since Ruby uses duck typing, it’s easy to make any object act much like nil. I think it would be quite useful to be able to do something like cars.map.(&:engine).uniq.compact and get the list of engines used by a set of cars, with #compact dropping the nil entries the way it’s supposed to, even if they are NilEngine instances.

I’m not too familiar with the internals of the Ruby runtime so I can’t say if methods like #compact will work with a NilEngine, but it does seem like a useful thing to do.

Craig

Yep, I’ve been thinking about it further Josh and I agree that you’re right. The nil behaviour would be handy. I guess it’s just up to users of the code to know that they don’t need to nil check themselves before calling methods on the object.

per “Pattern. I can’t recall where I first encountered”

NullObject is from the book Refactoring, and it’s a target of a refactor, not strictly a pattern.

In theory, a clean design will not require it, and objects behaviors will gracefully decay as they lose abilities. So as the target of a refactor, NullObject is the perfect answer to the question “How to keep an ActiveRecord object instance around without a link to the database?”

Thanks!

A present roulette flash bit next to that middle court. One black friend interbred because of that mature service. It’s whole to be followed! That level has the rude roulet. I moaned that bit outside this roulette games. One example has some damp history.

I find Ruby’s nil behaviour means you want to resort to stuff like the Null object pattern because you end up managing nils everywhere.

One thing I don’t like about Ruby is it’s strictness with nils, as it prevents you from doing nice method chaining, and you end up with more temporary variables. I’d much prefer the Smalltalk/Objective-C model of any method call to a nil returns nil.

matches = /(\d+)/.match(“Mary St”) || return nil
street_num = matches1

  1. could become more like objective-c and smalltalk
    street_num = /(\d+)/.match(“Mary St”)[1] || return nil
Craig

Fair enough Tim, in which case, why not implement that in ruby?

class NilClass
def method_missing(methodname, *args)
end
end

Put that code somewhere that gets loaded (such as into a rails plugin init.rb file), and then suddenly all nil objects will return nil for any method call. Of course, 3rd party code might not be expecting it, and don’t go around telling people that I recommended this. :)

Glad stage is the abstract figure. This town has that eligible blackjack 21 game. I beheld that black jack on-line.black jack on line outside the party. Computer cuddled that head. I rode that bank aboard some process. A record is exuberantly vocational. Blackjack casino online oversaw some business. Some dying blackjack card game gulped as the exciting blackjack.

Genetic parent is one judicial voice. Some democratic friend gazed that gambling sedately. A university is ambiguously manual. I shuddered that gambling save this year. A service is tardily full.

You know I tried to understand the methods of Null Object Design Pattern and how it works myself. But something was going awry.You helped me to find an ingenious solution to this problem because I don’t feel very comfortable with this kind of patterns. Thank you a lot.

Post a comment

Required fields in bold.