This slideshow covers how one might implement the Null Object Pattern, that is, a system for handling potentially null objects in your code in a way that allows for more maintainability.
2. How nils are often handled
@account.most_recent_event.nil ? 'no event' : @account.most_recent_event.name
3. How nils are often handled
@account.most_recent_event.nil ? 'no event' : @account.most_recent_event.name
Not so good
4. Step 1 - DRY It Up
class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.nil? 'no event' : most_recent_event.name
end
!
end
!
!
5. Step 1 - DRY It Up
class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.nil? 'no event' : most_recent_event.name
end
!
end
!
!
Still have ‘type-checking’ duplication
6. Step 1 - DRY It Up
class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.nil? 'no event' : most_recent_event.name
end
!
def most_recent_event_date
most_recent_event.nil? 'no event' : most_recent_event.date
end
end
!
!
Still have ‘type-checking’ duplication
7. Step 1 - DRY It Up
class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.nil? 'no event' : most_recent_event.name
end
!
def most_recent_event_date
most_recent_event.nil? 'no event' : most_recent_event.date
end
end
!
!
Tell, Don’t Ask
8. Step 2 - Tell Don’t Ask
class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.name
end
!
end
!
!
9. Step 2 - Tell Don’t Ask
class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.name
end
!
end
!
!
#=> NoMethodError: undefined method `name' for nil:NilClass
10. Step 2 - Tell Don’t Ask
class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.name
end
!
end
!
!
#=> NoMethodError: undefined method `name' for nil:NilClass
11. class Account < ActiveRecord::Base
!
belongs_to :account
!
def most_recent_event
events.last
end
!
end
!
!
12. class Account < ActiveRecord::Base
!
belongs_to :account
!
def self.most_recent_event
events.last || <SOMETHING WHICH RESPONDS TO #name>
!
end
!
end
!
!
13. Step 3 - Create an Interface
class NullEvent
!
def name
'no event'
end
!
end
14. class Event < ActiveRecord::Base
!
belongs_to :account
!
def self.most_recent
events.last || <SOMETHING WHICH RESPONDS TO #name>
end
!
end
!
!
15. class Event < ActiveRecord::Base
!
belongs_to :account
!
def self.most_recent
events.last || NullEvent.new
end
!
end
!
!
16. class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.nil? 'no event' : @account.most_recent_event.name
end
!
end
!
!
Before
17. class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.name
end
!
end
!
!
After
18. class Account < ActiveRecord::Base
!
has_many :events
!
def most_recent_event_name
most_recent_event.name
end
!
def most_recent_event_date
most_recent_event.date
end
end
!
!
After
19. Step 3 - Create an Interface
class NullEvent
!
def name
'no name'
end
!
def date
'no date'
end
!
end
20. Already Used at PP
!
class DummyGuest
def state
'initialized'
end
!
def total_guests_allowed
1
end
!
...etc.
end