Blog

Preferring value objects or setters and arguments

by Jim

The problem with programming can be that there are so many ways to solve a problem. For each solution there are arguments for it and arguments against it.

In recent articles I’ve written about moving responsibilities into a template object and out of the objects which use them for display.

When the template code first began, its use was extremely simple:

class Address
  def display(template)
    template.display_address(self)
  end
end

By making changes to the template to allow for shared behavior among different types of templates, the way in which our Address class used it became a bit more complex:

class Address
  def display(template)
    unless protect_privacy?
      template.street = street
      template.apartment = apartment
      template.postal_code = postal_code
    end
    template.city = city
    template.province = province
    template.display_address
  end
end

Originally the Address class knew of two features of the template, that it had a display_address method, and that the method took a single argument intended to be the address.

After some rework, the template became easier to manage and it became easier to make alternative formats, but the changes burdened the user of the object with the need for more knowledge. The Address objects now also need to know that there are setters for street=, apartment=, postal_code=, city=, and province=. It also needs to be implicitly aware that the template could render incomplete data; we know we aren’t required to set nil values for certain attributes.

Getting back to simple

We made good changes for the template, but I want that simple interface back. I want my address to act as a value object instead of needing to keep track of passing so many arguments.

While I want to go back to this:

class Address
  def display(template)
    template.display_address(self)
  end
end

I need a way to handle the case where we have sensitive data. What about that protect_privacy? method?

Here’s what we could do:

class Address
  def display(template)
    if protect_privacy?
      template.display_address(private_version)
    else
      template.display_address(self)
    end
  end

  def private_version
    self.class.new_with_attributes(city: city, province: province)
  end
end

With this change, the Address can still make a decision about displaying private data and it merely sends that version along to the template. I’m leaving the implementation of new_with_attributes up to imagination, but we’ll assume it will set the attributes we’ve provided on a new instance and return that.

Our template, when last we saw it, looked like this:

class Template
  attr_accessor :province, :postal_code, :city, :street, :apartment

  def province_and_postal_code
    # ... return the combined value or nil
  end

  def city_province_postal_code
    # ... return the combined value or nil
  end

  def address_lines
    [street, apartment, city_province_postal_code].compact
  end

  def display_address
    address_lines.join("\n")
  end
end

We’ve been shifting the method signature of display_address from originally accepting an argument, to then not accepting one, to now requiring one. That’s generally a bad thing to change since it causes a cascade of changes for any code that uses the particular method. I’d rather not switch back now, so what I can do is provide a way for the template to get the data it needs.

I’m happy to know how to use Forwardable because I can still keep my template code short and sweet. Here’s what we can do. First, lets change hte way we interact with the template:

class Address
  def display(template)
    if protect_privacy?
      template.with_address(private_version)
    else
      template.with_address(self)
    end
    template.display_address
  end
end

Next, we can alter the template by creating the with_address method:

class Template
  def with_address(address)
    @address = address
  end
end

Then, we can alter the line where we use attr_accessor to instead query for information from the address and use it as our value object:

require 'forwardable'
class Template
  extend Forwardable
  delegate [:province, :postal_code, :city, :street, :apartment] => :@address  
end

As long as we provide an object which has all of those required features, our Templates will work just fine.

Here’s the final result for our Template:

require 'forwardable'
class Template
  extend Forwardable
  delegate [:province, :postal_code, :city, :street, :apartment] => :@address

  def with_address(address)
    @address = address
  end

  def province_and_postal_code
    value = [province, postal_code].compact.join(' ')
    if value.empty?
      nil
    else
      value
    end
  end

  def city_province_postal_code
    value = [city, province_and_postal_code].compact.join(', ')
    if value.empty?
      nil
    else
      value
    end
  end

  def address_lines
    [street, apartment, city_province_postal_code].compact
  end

  def display_address
    address_lines.join("\n")
  end
end

With this change, the Template is still responsibile for only the proper display of data and will handle missing data appropriately. Our Address is responsible for the data itself; it will make decisions about what the data is, and whether or not it should be displayed with a given template.

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

Managing change using a common interface

by Jim

In a previous article I showed a way to move display code into a template object to manage missing data. Here’s what the basic template code looked like:

class Template
  def display_address(address)
    province_and_postal_code = [address.province, address.postal_code].compact.join(' ')
    province_and_postal_code = nil if province_and_postal_code.empty?

    city_province_postal_code = [address.city, province_and_postal_code].compact.join(', ')
    city_province_postal_code = nil if city_province_postal_code.empty?

    [address.street, city_province_postal_code].compact.join("\n")
  end
end

That’s relatively short and easy to read code for displaying the data for an address object.

But the display_address method contains the entire algorithm for displaying the data and stripping away any missing values. When we needed to add a new format type we created an HtmlTemplate and it contained duplicated code for the display_address. That reeks of a future bug where we might need a change to the algorithm and only remember to change one template type.

If we add new attributes to our address, we’d need to change every template so it could handle the new data. Inheritance is an easy solution for managing the way multiple types can handle the change.

And because we specifically allow for data to be missing, we can treat our template object like a partially applied function. Here’s what our main template will have…

We’ll need methods to set the values to be used for the display data, methods to handle the removal of missing values from the data to be processed, and finally the display method.

To set the data values, we can use attr_accessor:

class Template
  attr_accessor :province, :postal_code, :city, :street

  def province_and_postal_code
    value = [province, postal_code].compact.join(' ')
    if value.empty?
      nil
    else
      value
    end
  end

  def city_province_postal_code
    value = [city, province_and_postal_code].compact.join(', ')
    if value.empty?
      nil
    else
      value
    end
  end

  def address_lines
    [street, city_province_postal_code].compact
  end

  def display_address
    address_lines.join("\n")
  end
end

With that change, our additional template types can inherit from our beginning Template class and change the behavior relevant to the needs of its format:

class HtmlTemplate < Template
  def display_address
    address_lines.join("<br />")
  end
end

Eventually we’ll find that the addresses we need to handle might require a secondary bit of information like an apartment number.

class Template
  # Additional attribute
  attr_accessor :apartment

  # Updated collection of information
  def address_lines
    [street, apartment, city_province_postal_code].compact
  end
end

The way our Address objects interact with these templates would change, of course, but could allow the Address to make decisions about what may be revealed to the outside world:

class Address
  def display(template)
    unless protect_privacy?
      template.street = street
      template.apartment = apartment
      template.postal_code = postal_code
    end
    template.city = city
    template.province = province
    template.display_address
  end
end

By creating a standard set of template methods, we can treat our objects containing data separately from the objects which display them. What else could we do now that we’ve made this distiction? For example, what might a template for an IO stream look like?

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

Forwarding messages with Tell, Don't Ask

by Jim

My avid use of Forwardable helps me simplify my code to raise up the important parts. When things still end up too complicated, I can reach for null objects to ease my commands into place.

class Person
  def initialize(address)
    @address = address
  end
  def address
    @address || DefaultAddress.new
  end
end

As we’ve seen in this code, any Person object will always have an address, but what I do with that Person or address is what can cause some problems in the future.

Displaying an address can sometimes be a complicated matter.

Asking for too much

In the case of displaying the address for a particular person, we might want certain formatting depending upon the available details.

If we only have a person’s city, or just city and state, we’d probably only show that. An easy way is to just check for those attributes on the address:

class Person
  def display_address
    "".tap do |string|
      string << address.street unless address.street.nil?
      string << address.city unless address.city.nil?
      string << address.province unless address.province.nil?
      string << address.postal_code unless address.postal_code.nil?
    end
  end
end

This is easy, but introduces a problem if the display of the address ever changes. With the above code, we are asking for a lot of information from the address. It would be more flexible to move this into the address itself.

class Person
  def display_address
    address.display
  end
end

class Address
  def display
    "".tap do |string|
      string << street unless street.nil?
      string << city unless city.nil?
      string << province unless province.nil?
      string << postal_code unless postal_code.nil?
    end
  end
end

This simplifies the knowledge we store in the Person class for interacting with an address. Now all we need is to know is that the address has a display method.

As an added benefit, it’s far shorter and easier to read.

Being prepared for changes

What happens when we need to output a person’s address in both an HTML page and a text-only email? In one case we’ll need a simple line break, and in another we’ll need HTML formatting such as a <br /> element.

Here’s an example:

123 Main Street
Arlington, VA 22222

An updated version of our code which would skip missing data and create our desired output would look like this:

class Address
  def display
    province_and_postal_code = [province, postal_code].compact.join(' ')
    province_and_postal_code = nil if province_and_postal_code.empty?

    city_province_postal_code = [city, province_and_postal_code].compact.join(', ')
    city_province_postal_code = nil if city_province_postal_code.empty?

    [street, city_province_postal_code].compact.join("\n")
  end
end

With simple text a newline is all we need, but in HTML we’ll need to provide a break:

123 Main Street<br />
Arlington, VA 22222

We could add features to our Address class to handle changes like this:

class Address

 def display(line_break)
   # same code as above here ...

   [street, city_province_postal_code].compact.join(line_break)
 end

end

That seems like a simple change, but in order to use it the Person would need to know what type of line break to provide to the address. This would push the decision for how to display the address far away from the address itself.

Instead, we could keep the information for formatting inside an object whose responsibility is specifically for formatting the information. If we require a new type of format, we would then only need to create an object for that format.

For example, our standard template could handle the data with a newline character.

class Template
  def display_address(address)
    province_and_postal_code = [address.province, address.postal_code].compact.join(' ')
    province_and_postal_code = nil if province_and_postal_code.empty?

    city_province_postal_code = [address.city, province_and_postal_code].compact.join(', ')
    city_province_postal_code = nil if city_province_postal_code.empty?

    [address.street, city_province_postal_code].compact.join("\n")
  end
end

Then our HTML template could handle the data with proper line breaks for it’s format:

class HtmlTemplate
  def display_address(address)
    # same code as above here ...

    [address.street, city_province_postal_code].compact.join("<br />")
  end
end

We should move the duplicated code to a common location so that each template could share it, but this will do for now.

So how might our Person and Address objects use these templates?

All we’ll need to do is change our display_address and display methods to accept a template for the formatting.

class Person
  def display_address(template)
    address.display(template)
  end
end

class Address
  def display(template)
    template.display_address(self)
  end
end

If we add new formats, neither or Person nor our Address class will need to change. There’s still more we can do to guard against changes but I’ll write more about that next time.

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

Clean Ruby 1.0 is released!

by Jim

I’m excited to be able to call Clean Ruby “final”.

The compliments to that work have been great. Here’s just a few comments I’ve received for Clean Ruby:

“The current version of Clean Ruby is a great start on a critical topic. Learning how to keep code clear and understandable is useful for any kind of project. I’ve already applied a couple of ideas from the book to keep a project from mumbling in the shadows.” —David Richards

“I have not come across such a revelatory approach to things since first learning OOP.” —Mike Pence

“Clean Ruby from Jim Gay will change the way you design your Rails apps” —Hector Sansores

As time goes on, I’ll be updating the book with changes to Ruby and new ideas, but it’s at a point where you can get some great techniques. Self-publishing this book has been wonderful for handling updates; I’m able to make changes and get them in the hands of my customers as soon as I can. I’m not limited by a publishing house setting my schedule.

My free newsletter has helped me engage with developers from all over the world. I’ll be continuing writing there and releasing more useful tools like Casting and Surrounded. I’m eager to try screencasts and more books.

Grab a copy of Clean Ruby and help me celebrate by using the code TAKE10 for $10 off!

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

Avoiding errors when forwarding to missing objects

by Jim

The “final” update for Clean Ruby will be released soon. More on that below, but first here are some thoughts on what to do when you’ve got a missing object.

The Ruby standard library Forwardable is really useful for raising up valuable information and hiding unimportant details.

A single line of code can configure the relationship between two objects and the data they share.

delegate [:street, :city, :state] => :address

I’m often asked: what happens if that address is nil?

In this case, you’ll see an error about an undefined method on nil:

NoMethodError: undefined method `street' for nil:NilClass

You might want that, or you might not. It depends on how you want to structure your program.

When using the Forwardable library, the street method above will raise an error if address is missing.

But, it might make the most sense for your application that if there is no address, then there is obviously no street. So a method that handles this will make more sense:

def street
  if address
    address.street
  end
end

With this requirement, Forwardable seems useless. I don’t have a way to configure Forwardable to just skip the nil object and the forwarded message. ActiveSupport (and Rails) adds its own answer to this problem.

delegate :street, :to => :address, :allow_nil => true

By specifying allow_nil the call to street will silently continue returning nothing if the address is nil. This type of approach to managing nil objects is valuable when it’s what you want (of course), and can be a life-saver when you’re dealing with a large and/or unfamiliar codebase that’s throwing up errors where you don’t expect them.

A problem with this approach, however, is that the absence of a an object might be an indication that you’re missing some vaulable setup steps. Perhaps a missing address is a problem and removing the error hides the problem. You can take your error as encouragement to use a null object, an object which will stand-in for your missing address.

class Person
  def initialize(address)
    @address = address
  end
  def address
    @address || DefaultAddress.new
  end
end

You likely have a different way to initialize your objects, but with something like the above code we can use a DefaultAddress which can answer for your missing address.

class DefaultAddress
  def street
    "123 Home Base"
  end
end

By following this design you can easily change your program from displaying nothing, as you do in the case of allow_nil, to displaying a default value. But what’s great about this structure is that you can change the default behavior without any change to your Person class.

Before reaching for an option like allow_nil, consider an alternative object instead. How do you handle nil objects in your code?

Lastly, Clean Ruby is out and you can get it now! I’ll be keeping the book up to date with relevant changes to Ruby or with any good techniques for Object-oriented programming so “final” true, barring any updates that come along.

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

Shorter, simpler code with Forwardable

by Jim

I often find that visual distractions slow me down. Reading simple code with familiar concepts feels cumbersome when I have to sort through repetition to find the meaning.

Take a glance at this code to see what I mean:

class Person
  def street
    address.street
  end

  def city
    address.city
  end

  def state
    address.state
  end
end

Although the code is short, you have to think a bit before you realize that all of these methods do basically the same thing.

Ruby has a built-in way to bring the information out of this code: Forwardable.

I touched on using Forwardable in a previous article but we’ll look closer at what’s happening and why you want to use it.

The code above merely forwards the given method to another object. In this case if you try to get address details from a “Person”, it will automatically pass it along to the related “address” object.

Given that the procedure is so simple and common in the code, I’d much rather have a way to read that information faster.

require 'forwardable'
class Person
  extend Forwardable

  delegate [:street, :city, :state] => :address
end

With this code, the concept of forwarding a message to a collaborating object is so clear that it reads like configuration.

Good configuration is fast and easy to understand.

Forwardable works essentially the same way that the longform code above does. You can provide a list of methods which should be sent to a particular object. Here’s what a simplified version of what Forwardable looks like:

module Forwardable
  def delegate(hash)
    hash.each{ |methods, accessor|
      methods.each{ |method|
        instance_eval %{
          def #{method}(*args, &block)
            #{accessor}.__send__(:#{method}, *args, &block)
          end
        }
      }
    }
  end
end

The “delegate” method accepts a hash where the keys are the method names to forward and the values are the object names to receive the forwarded messages.

For each item in the hash, it will loop through each method name and define a method using instance_eval and the generated string. Those methods send the message along to the object you specified.

The Forwardable code looks complicated, but it’s merely 2 loops over a hash and an array, then the instance_eval. The ultimate result is the equivalent of the original code above. With some simple iteration and dynamically defining methods, Forwardable helps us strip away the unimportant parts and raises the valuable information to the top:

delegate [:street, :city, :state] => :address

This shows us what methods will be sent to which object without any additional code to sort through. What could be simpler or easier to scan and understand?

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Permalink…

1999 - 2014 © Saturn Flyer LLC 2321 S. Buchanan St. Arlington, VA 22206

Call Jim Gay at 571 403 0338