Wes and Parker pointed us to this article:
Misunderstanding the Law of Demeter by Dan Manges
which is a very nice discussion of the “law” (actually just a suggestion, but a very strong one) that encourages your objects, like small children, not to talk to strangers. Some people seem uneasy with the LoD since it requires them to refactor their objects to have proxy methods all over them. Instead of Paperboy calling
customer.wallet.cash you have to put an extra method on Customer — either
cash (attribute delegation — check out
Forwardable in Rails btw) or
pay (behavior delegation). But these proxy methods are not clutter, they’re the essence of encapsulation. Do not fear encapsulation. Fear is the mind killer.
Anyway, Dan does a great job explaining this concept, until the very end of the article, when he totally chickens out.
Let’s say we’re developing a Rails view to display order information, and this should include details on the customer. We might write the view like this:
<%= @order.customer.name %>
…Our view now becomes:
<%= @order.customer_name %>
We’ve traded a dot for an underscore. And thinking about this further, why should an order have a customer_name? We’re working with objects, an order should have a customer who has a name. Adding these attribute delegations also decreases maintainability.
The crux of this is that webpage views aren’t domain objects and can’t adhere to the Law of Demeter. Clearly from the examples of behavior delegation the Law of Demeter leads to cleaner code. However, when rendering a view, it’s natural and
expected that the view needs to branch out into the domain model.
This is dead wrong. Ading delegation — for getters, at least — increases
maintainability, and especially mockability. It makes perfect sense
for an order to “have” a customer name — that is, respond to a
message querying it for its customer’s name — since now the order can
do things like decorate the customer’s name, or fake one up if there’s
no customer object set on the order. And if the interface of Customer
changes then none of the clients (including tests) of Order need to
change at all.
[ Invoice (view) ] -> [ Order ] -> [ Customer ]
The crux of this is that webpage views aren’t domain objects and can’t
adhere to the Law of Demeter.
Wow again. This is circular reasoning (the “begging the question”
fallacy). Why aren’t webpage views domain objects? Why did Rails make the
bizarre decision to make one of the MVC Holy Trinity be just plain text files,
and to share all instance variables (ugh) with the controller? Why can’t views
adhere to reasonable object-oriented semantics and support
encapsulation, interface-based design, etc. etc.?
…but even without going down those roads, the LoD provides a great way
of keeping views isolated from a tangled nest of model objects, all
pointing to each other. I try to make my views connected to a small
set of objects — often just one — and to make sure each of those objects’
public APIs exposes everything the view needs.
Clearly from the examples of behavior
delegation the Law of Demeter leads to cleaner code. However, when rendering
a view, it’s natural and expected that the view needs to branch out into the
domain model. Also, anytime something in a view dictates code in models,
take caution. Models should define business logic and be able to stand alone
A view is a perfectly valid client of a model object, and if
some of its logic makes more sense encapsulated in the model — say,
"display_name" property on a
Car object which concatenates make,
model, and year — then that’s where it should go. Put the behavior
with the data, tell don’t ask, and don’t peep into your neighbor’s
Edit: We’re famous! This thread is referenced on the Wikipedia Law of Demeter page.
About the AuthorMore Content by Alex Chaffee