One of The Blabs’ most controversial articles was Lovely Demeter, Meter Maid, in which Pivotal and Thoughtworks battle over which Agile consultancy has the better understanding of the Law of Demeter, and which has better hair and music taste (seriously).
I have never found this “law” very persuasive.
- The bizarre, culturally loaded analogy about a paperboy and a wallet says nothing insightful about encapsulation boundaries as they arise in real software systems.
- The blogosphere’s endless scholastic hermeneutics of the law’s 4 allowances for message sending is a masturbatory philosophical enterprise with nothing relevant to real-world software.
- The Mockist’s insistence on easy mockability is of dubious merit–build better mocking frameworks!
- And the few practical, real merits that arise in from following the Law of Demeter are better arrived at using other techniques, such as “Tell, Don’t Ask”.
Here Are Two Examples, one where I violate the Law of Demeter, and another where I don’t.
I wrote this code recently, in flagrant violation of the Law:
cookies[:store_id] = @login.store.id
Suppose @login is not an ActiveRecord object, it does not automatically have a #store_id method. Should I create a delegator for this?
class Login
def store_id
store.id
end
end
This is pretty silly. The store_id is not an attribute of the login; rather it’s an attribute of the store, and the store is an attribute of the login. The delegator is needless code cruft to replace a dot with an underscore, it smells of the endless boilerplate Java code of my youth. Demeter be damned.
On the other hand, here is a refactoring I did, incidentally complying with the law of Demeter:
Here is the original, Demeter-violating code:
def find_attribute_given_name(name)
attributes.detect { |a| a.name_or_alias == name }
end
The call to == here is the violation of Demeter. I later replaced this with:
attributes.detect { |a| a.named?(name) }
The latter complies with the “law”. And it’s much better code. But was I lead to the improvement to this by Demeter? No, I was lead to it by a better understanding of the encapsulation boundaries of the object (#name_or_alias became private) and by a desire to have my code be more terse and clear. a.named?(name) is the most terse explanation of the intended computation that I can think of.
Demeter be damned.
Well said.
May 7, 2008 at 10:16 pm
if anyone uses ‘piffle’ in my presence i’m firing them immediately.
May 7, 2008 at 10:41 pm
LOD is not a law (or shouldn’t be) – it’s a guideline. If I find myself “violating” it, I take a second look at the code. Then I do what I think is right.
a.named? is correct because it’s intentional – it describes what you’re trying to do.
login.store.id is merely a shortcut for the LODish
store = login.store
id = store.id
And in an important sense, the store == its id. It’s the same object, conceptually. It’s just dereferenced differently.
///ark
May 7, 2008 at 11:10 pm
Nick, I know you have a problem with authority, so may I remind you that the “law” was only a law in that long-ago system named Demeter? These days it’s a rule of thumb meant to remind you to pay attention to the (ahem) encapsulation boundaries of the object you’re interacting with. And presumably it did its job, since after you pulled off your sweet little encapsulation with your “named?” method, you thought about it, and had to admit (grudgingly) that you had followed it.
Now then, in your first example, what the heck are you doing asking an object for its id in the first place? Shouldn’t you be tell-not-asking that object to do something instead, that may or may not require knowledge of its internal state? Like, oh,
login.write_cookie(cookies)
? That would let you change the format or content of the cookie later without changing the API, and would also let you unit test it without using a mock at all, but just by passing in a hash (the best mocking framework is the one you never have to use, IMHO).
It’s funny, I’ve recently been thinking of a followup to [Lovely Demeter](http://pivots.pivotallabs.com/users/alex/blog/articles/273-lovely-demeter-meter-maid) called “You Are Not An Object-Oriented Programmer” (because “you” violate encapsulation all over the place)… which is not to say functional or struct-oriented or database or two-tier programming doesn’t have its place but just cause you do that stuff in an OO language doesn’t make your code OO. It’s nice, despite your endearing rebellious teenage angst, to see that you’ve got the OO chops when you want to bust them out.
May 7, 2008 at 11:47 pm
> login.write_cookie(cookies)
If login is the cookie’s client – i.e., there is an equivalent Login.read_cookie(cookies) – that would make sense. If some other object actually cares about the cookie’s contents, then it should do the writing. I think.
///ark
May 8, 2008 at 12:23 am
Second example first: If you weren’t using the #name_or_alias method and instead just used #name, would you still have encapsulated the query behind #named? (I think it’s better to use #named? in both cases, but I might not have had that insight if I were just testing on the name. #name_or_alias exposes implementation details through its name, so it would be a more obvious refactoring)
re: the cookie example: You could make the cookie writing more OO as Alex pointed out. I’d probably just do the same thing as you though. I wonder how much of the decision has to do with being at a conceptual boundary of the system – we’re leaving the fuzzy warm OO part of the app and entering the web request side. We make the tradeoff of using integer IDs instead of objects here because sticking AR objects in the cookie is a bad idea. In this case you simply want to destructure the object, and your implementation is the clearest way of doing that…but I think it’s important to recognize why it’s the correct decision.
May 8, 2008 at 7:36 pm
“t’s funny, I’ve recently been thinking of a followup to Lovely Demeter called “You Are Not An Object-Oriented Programmer” (because “you” violate encapsulation all over the place)… which is not to say functional or struct-oriented or database or two-tier programming doesn’t have its place but just cause you do that stuff in an OO language doesn’t make your code OO. It’s nice, despite your endearing rebellious teenage angst, to see that you’ve got the OO chops when you want to bust them out.”
Perhaps Alex thinks of himself as the guardian of all that’s good and true about OO, that being “truly OO” in this sense is some sort of end worth anyone’s time. And that we should all be running around disturbed and slightly ashamed that we write code like
do_it(foo.id)
“your code isn’t object-oriented enough” is an example of an utterly meaningless statement, which if really followed would result in programmers doing the equivalent of running in a hamster wheel, chasing whatever the OO fashion mavens put forward as the next “pattern” or “idiom” you need to really get before you’re one of the cool kids.
Now I’m going to write some sql and pipe the results to a file.
May 10, 2008 at 2:52 am
As a public service:
* __pif·fle__ n: Foolish or futile talk or ideas; nonsense.
* __her·me·neu·tics__ n. (used with a sing. or pl. verb) The theory and methodology of interpretation, especially of scriptural text.
(Courtesy of the [Free Online Dictionary](http://www.thefreedictionary.com)
May 10, 2008 at 3:58 am
Steve, I couldn’t agree more. In fact, if you re-read my post you will notice that, in sympathy with Macbeth(*), nowhere do I say you’re not doing “enough” OO — just that you’re not doing it. I’m merely trying to point out that lots of code is not object oriented, and hopefully by doing so will enable people to make more informed design decisions, and think about whether the verbal mode of tell-don’t-ask is right for you, rather than unthinkingly defaulting to what I like to call the manual mode, where you pull some value out of a box, manipulate it, then put it back in or place it somewhere else.
Okay, yes, there is a touch of — I hesitate to say holier-than-thou attitude, but really I honestly do think that real OO designs tend to be cleaner and more elegant and therefore superior. But I’m really confused where your and Nick’s defensiveness comes from. The lady doth protest too much, methinks.
– Sir Francis Bacon Cheeseburger
(*) And damn’d be him that first cries, ‘Hold, enough!’
May 13, 2008 at 7:22 pm
I find it hard to disagree with anything you say in this second comment. The question is how did Nick *really* arrive at this end result that we all agree is good – in 100 years we might have the technology to actually figure that out, but for now all we have is what Nick himself reports.
May 17, 2008 at 8:38 pm