Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Lovely Demeter, Meter Maid

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.?

See my post “Life
Without Getters”
for an alternate vision… Or (thanks Wes) the Presenter Pattern

…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
from views.

More FUD.
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,
as a "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
windows.

Edit: We’re famous! This thread is referenced on the Wikipedia Law of Demeter page.

Comments
  1. Alex Chaffee says:

    Jim:

    From Wikipedia: For the Greeks, Demeter was still a poppy goddess.

    I’ve always thought that Lieberherr was a crackpot. Calling a simple “best practice” a law so overstates its usefulness. I don’t ask a drawer to give me a fork; I go into the drawer to get a fork. I don’t much care what the drawer thinks of that.

    Alex:

    Semantics. The reason it’s a law is that for the system named Demeter,
    it was a law. As it is it’s just a damn good idea and if you want to
    make an OO program that doesn’t obey the… Suggestion of Demeter…
    then you’d better have a good reason why not.

  2. Alex Chaffee says:

    One of the Ruby idioms that always give me a chuckle, just ’cause I can do it, is:

     hash.keys.sort.reverse.join(',')   # not necessarily a real example
    

    Because these are utilities, I expect I can do this without much future trauma.

    I also think the general problem is more nuanced than the solution Demeter provides. Back in the day (putting on my old fart hat!), C programmers didn’t use collections because there weren’t any (except built-in arrays). Until decent garbage-collected languages came along (‘decent’ doesn’t include C++ STL), you couldn’t reasonably put something into a collection and trust someone else to (or not to) free it for you. The above example uses arrays, which throw away their contents when finalized, so the hash doesn’t mind copying its keys into an array and then giving me the array to do whatever I want with because he knows that his keys will hang around until BOTH of us (and our transitive closure) free them.

    So Demeter (pre-C++) was designed around the problem of abstractions being unable to manage their own memory while simultaneously passing objects around in a reasonable fashion, which is a problem we don’t have in GC-based languages.

    Demeter was also developed at a time where our sense of what constitutes a “type” was not so nuanced. The above example works, not because I’m lazy, but because the Hash and Array classes are not precisely typed, but simply honor Enumerable and Comparable, which are much looser constraints. It’s much easier for the classes’ authors to change the behavior and still honor the contract than it would be in a language that didn’t have named interfaces (not to mention duck typing). So as long as I can iterate the collection and sort the elements, I don’t much care how they’re implemented.

    And lastly, we have TDD now; Lieberherr didn’t. So if we change something that messes up its callers, the tests will fail.

  3. Alex Chaffee says:

    abstractions being unable to manage their own memory

    Memory is one of the many things abstractions (objects)
    (obstractions?) should be able to manage. Demeter ensures they will
    keep control of all their private stuff (like instance variables,
    decorations, relationships to other objects, persistence,
    transactions, threading, etc.). Just because memory is less important
    these days doesn’t mean Demeter is obsolete.

    hash.keys.sort.reverse.join(‘,’) # not necessarily a real example

    Because these are utilities, I expect I can do this without much future
    trauma.

    Yes, there’s a sneaky exception to the LoD involving library classes.
    But even the above is not a true violation of the LoD, since the
    methods are returning immutable copies of internal state, not live
    references to nested objects.

    And lastly, we have TDD now; Lieberherr didn’t. So if we change something
    that messes up its callers, the tests will fail.

    TDD is indeed teh awsum, but it’s not a panacea, nor an excuse for
    sloppy programming practices. Tests support refactoring to patterns
    (like LoD) that make the code clearer and easier to maintain.

  4. Nick Kallen says:

    The Crux of your argument is that

    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.

    You make a mistake here in thinking that the Order must be the Decorator of the Customer. An Order could return a Decorated Customer when asked for a Customer. And voila all of your difficulties are solved.

    Yes, the ‘ripple-effect’ of a change in Interface to Customer is broad. But your solution is to provide numerous facade’s to Domain objects that otherwise should have a consistent interface. You’ve gotten loose coupling along with low cohesion.

    Suppose you have a CustomerRenderer. it is now no longer usable in your design; you cannot compose an OrderRenderer out of a CustomerRenderer. If you enforce the cohesion with an Interface, well you have your ripple-effect again. To me, the claim that

    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.

    –this is sufficiently persuasive. This is the argument from Ontology and it trumps the argument from Mockability any day.

  5. Zak Tamsen says:

    you make some good points. it is refreshing to finally see a discussion about views and LoD.

    but you are also “dead wrong”.

    “Ading [sic] delegation — for getters, at least — increases maintainability.”

    this an oversimplification and shows a misunderstanding of LoD. LoD is NOT about delegation.

    in addition, the tone of your post is unnecessarily aggressive. I could continue to pick it apart and be pedantic as you have with Dan’s but I find that childish and trite.

    so instead, I dare you to suggest that Dan is a chicken to his face… when I’m around.

    sincerely,
    Zak Tamsen

  6. Clint Bishop says:

    kick his ass, Seabass!

  7. Chad Woolley says:

    @Zak – man, that is some funny stuff. Well done. LOL.

    One thing, though – you said “with Rails development, instead of traditional view tests, I suggest massively parallelized Selenium tests. but that’s a different discussion.”

    I’d like to hear more about the massively parallelized part, especially gritty details of how you make this work easily on a day-to-day basis. We’ve been having fun with rspec view tests, but I’d love to hear your selenium-based alternatives. That’s not a challenge, it’s an honest request for enlightenment. Please don’t make fun of my hairline.

    TIA,
    — Chad

  8. @Zak – The reason Alex was thanking me was because I pointed him at Jay’s posts. Great comment.

  9. Brian Takita says:

    Boys, put away your object graphs. There are ladies present.

  10. Hammer says:

    Why would I want to bother writing Selenium tests when I can just pay someone a nickel to manually test it for me.

    Haven’t you heard of Mechanical Turk?

  11. Zak says:

    I said “with Rails development, instead of traditional view tests, I suggest massively parallelized Selenium tests. but that’s a different discussion.”

    and Chad wanted more detail.

    well, what we use for massively parallelized Selenium tests isn’t public yet. but it should be within the next 48 hours. I’ll come back in a few.

    in the meantime, may I suggest massively parallelized functional tests with deepTest.

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *