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).
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
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)
events (id, title, street, city, state)
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
class back, moving the
state columns from the
table back into the new
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 %>
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
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!