views gone wild

views gone wild

The pragmatic programmers dave and andy once summed up object oriented programming in 1 sentence: Keep it DRY, keep it shy, and tell the other guy.

We all know DRY (mostly thanks to Rails now). We just discussed tell the other guy. But this time I want to touch on keep it shy.

Now keep it shy (a.k.a the law of demeter) is about coupling. An object is coupled to another object whenever it depends on it. Being dependent means sending a message to another object. So there has to be some coupling in a system or nothing would ever happen i.e. each object would stand on its own. However, having too much coupling results in a system were you make 1 change and you break all sorts of other things that were dependent on it. Objects were designed to hide implementation and avoid situations like that. But you still have to be disciplined in keeping your objects implementation hidden and not giving it out to any object that asks for it. And at the same time, not asking an object for too much of its stuff (i.e. implementation).

For example:


class Event < ActiveRecord::Base

  belongs_to :address

end

class Address < ActiveRecord::Base

  has_many :events

end

Now somewhere in a view we have the following code:



  <%= @event.address.street %>

Now that view is coupled to the Event class' implementation, specifically its dependent on the fact that Event#address returns an object that understands #street. Should we ever change that, this view would break.

If we want to keep it shy we’d have to write a wrapper method on Event:


class Event < ActiveRecord::Base

  belongs_to :address

  def street
    address.street
  end

end
And our view becomes:


  <%= @event.street %>

However, now we realize that the Address class is un-necessary; we normalized a little too much. So we scrap it and our schema goes from:


  events (id, title, address_id)

  addresses (id, street, city, state)

to:


  events (id, title, street, city, state)

And our Event class becomes:


class Event < ActiveRecord::Base
end

And our view code doesn’t need to change at all. Its still:

<%= @event.street %>

Because we wrote our view code shy, it was in no way dependent on the implementation of how Event stored its address information. We were able to change the implementation of Event and we didn’t break the view; great, now thats what objects are all about.

Then all of a sudden, the client says they need to CRUD addresses independently, so that when creating an Event you can just select its address from a drop down list containing all the addresses that are in the database. So we refactor and bring the Address class back, moving the street, city and state columns from the events table back into the new addresses table.

Next the client demands to see the city and state of the address in addition to its street on the web page corresponding to our view. Now that wrapper method requirement is starting to fire me up.

Because we need this:


class Event < ActiveRecord::Base

  belongs_to :address
 
  def street
    address.street
  end

  def city
    address.city
  end

  def state
    address.state
  end

end

So our view can be written nice and shy like this:



  <%= @event.street %>
  <%= @event.city %>
  <%= @event.state %>

Now Event is just 1 class and Address just 1 other class its associated with, imagine a normal app with several classes and many different associations between them. As you can see, in order to remain shy we’re going to have a ton of wrapper methods. I don’t want to write all those wrapper methods, so I have to be fine with my view looking like this:



  <%= @event.address.street %>
  <%= @event.address.city %>
  <%= @event.address.state %>

Yes it is not shy and it is dependent (coupled) to the implementation of the Event class but I’m going to justify that by saying views are allowed to rip apart objects.

Ok. Hear me out here.

So the front of our app is the view i.e. the web page. And the back of our app is the database. Now the database is nothing but state - no behavior, just the results of ripping apart (flattening) an object. What about the web page? It’s always a display of that same state. So I’m saying that the web page is nothing but state and therefore has the same rights as the database in ripping apart an object in order to display it to the user.

Everything between the web page and the database is behavior. And I’d say that your classes should be shy but your views have every right not to be because they have to show the object’s state to the user.

So I’d say keep your controllers and models shy but let your views run wild!

Jared Carroll Developer