Movatterモバイル変換


[0]ホーム

URL:


Profile Picture
…and you like it

The Law of Demeter Is Not A Dot Counting Exercise

codepatternssuggest edit

Recently I read a discussion on an internal mailing list on whether ornot it would be worthwhile to add a null dereferencing operator to C#.

For example, one proposed idea would allow the following expression.

objecta=foo.?bar.?baz.?qux;

This would assign the variablea the valuenull if any one offoo, bar, orbaz is nullinstead ofthrowing aNullReferenceException. It’s a small, but potentially helpful,mitigation for thebillion dollarmistake.

Sure enough, it did not take long for someone to claim that this syntaxwould be unnecessary if the code here was not violating the sacredLawofDemeter(or LoD for short). I think this phenomena is an analog toGodwin’sLaw anddeserves its own name. Let’s call it the “LoD Dot Counting Law”:

As a discussion of a code expression with more than one dot growslonger, the probability that someone claims a Law of Demeter violationapproaches 1.

dippindotsCount the dots and win a prize!

What is wrong with the claim that the above expression violates LoD? Toanswer that let’s briefly cover the Law of Demeter. I’m not going tocover it in detail but rather point to posts that describe it in muchbetter detail than I would.

The Many Forms of Demeter

Theformal objectformof the law can be summarized as:

A method of an object may only call methods of:

  1. The object itself.
  2. An argument of the method.
  3. Any object created within the method.
  4. Any direct properties/fields of the object.

Ageneral formulation of thelawis:

Each unit should have only limited knowledge about other units: onlyunits “closely” related to the current unit. Or: Each unit should onlytalk to its friends; Don’t talk to strangers.

This of course leads to the succinct form of the law:

Don’t talk to strangers

In other words, try to avoid calling methods of an object that wasreturned by calling another method. Often, people shorten the law tosimply state “use only one dot”.

One of the key benefits of applying LoD is low coupling viaencapsulation. In his paper,The Paperboy, The Wallet, and The Law ofDemeter(PDF)(it’s a relatively quick read so go ahead, I’ll be here), David Bockprovides a great illustration of this law with an analogy of a paperboyand a customer. Rather than having a customer hand over his wallet topay the paperboy, he instead has the paperboy request payment from thecustomer.

In answer to “Why is this better?” David Bock gives these three reasons.

The first reason that this is better is because it better models thereal world scenario…  The Paperboy code is now ‘asking’ the customerfor a payment.  The paperboy does not have direct access to thewallet.  

The second reason that this is better is because the Wallet class cannow change, and the paperboy is completely isolated from that change…

The third, and probably most ‘object-oriented’ answer is that we arenow free to change the implementation of ‘getPayment()’.

Note that the first benefit is an improvement not only in encapsulationbut the abstraction is also improved.

Dot Counting Is Not The Point

You’ll note that David doesn’t list “50% less dots in your code!” as abenefit of applying LoD. The focus is on reduced coupling and improvedencapsulation.

So going back to the initial expression, doesfoo.bar.baz.qux violateLoD? Like most things, it depends.

For example, suppose thatfoo is of typeSomething and it containsproperties namedBar,Baz, andQux which each simply returnthis.

In this semi-contrived example, the expression is not an LoD violationbecause each property returns the object itself and according to thefirst rule of LoD, “you do not talk about LoD” … wait … sorry… “a methodis free to call any properties of the object itself” (in a future post,I will cover theclass form of LoD which seems to indicate that ifBar,Baz, andQux return the same type, whether it’s the sameobject or not, LoD is preserved).

This pattern is actually quite common with fluent interfaces where eachmethod in a calling chain might return the object itself, buttransformed in some way.

So we see that counting dots is not enough to indicate an LoD violation.But lets dig deeper. Are there other cases where counting dots leads donot indicate an LoD violation? More importantly, is it always a badthing to violate LoD? Are there cases where an LoD violation might evenbe the right thing to do?

Go Directly to Jail, Do Not Pass Go

Despite its name, violating the Law of Demeter will not get you on anepisode of Cops nor is it some inviolable law of nature.

As theoriginal paper pointsout,it was developed during design and implementation of the Demeter system(hence the name) and was held to be a law for the developers ofthatsystem.

The designers of the system felt that this practice ensured goodObject-Oriented design:

The motivation behind the Law of Demeter is to ensure that thesoftware is as modular as possible. The law effectively reduces theoccurrences of nested message sendings (function calls) and simplifiesthe methods.

However, while it was a law in the context of the Demeter system,whether it should hold the weight that calling it aLaw implies isopen to debate.

David Bock refers to it as an idiom:

This paper is going to talk about a particluar(sic) ‘trick’ I like,one that is probably better classified as an ‘idiom’ than a designpattern (although it is a component in many different designpatterns).

 Martin Fowlersuggests(emphasis mine)

I’d prefer it to be called theOccasionally Useful Suggestion ofDemeter.

Personally, I think most developers are guilty of bad encapsulation andtight coupling. I’m a bit more worried about that than applying this lawinappropriately (though I worry about that too). Those who have deepunderstanding of this guideline are the ones who are likely to know whenit shouldn’t be applied.

For the rest of us mere mortals, I think it’s important to at leastthink about this guideline and be intentional about applying or notapplying it.

I Fought The Law and The Law Won

So what are the occasions when the Law of Demeter doesn’t necessarilyapply? There’s some debate out there on the issue.

In his post,Misunderstanding the Law ofDemeter,Daniel Manges argues that web page views aren’t domain objects and thusshouldn’t be subject to the Law of Demeter. His argument hinges on aRails example where you send anOrder object to the view, but the viewneeds to display the customer’s name.

<%= @order.customer.name %>

Counting two dots, he considers the change that would make it fit LoD:

<%= @order.customer_name %>

He then asks:

Why should an order have a customer_name? We’re working with objects,an order should have a customer who has a name.

…when rendering a view, it’s natural and expected that the view needsto branch out into the domain model.

Alex Blabs of Pivotal Labstakes issue with Daniel’s post andarguesthat viewsaredomain objects and an order ought to have acustomer_name property.

It’s an interesting argument, but thefollowing snippet of acommentby Zak Tamsen summarizes where I currently am on this subject (though mymind is open).

because they don’t. the primary job of the views (under discussion) isto expose the internal state of objects for display purposes. that is,they are expressly for data showing, not data hiding. and there’s therub: these kind of views flagrantly violate encapsulation, LoD is allabout encapsulation, and no amount of attribute delegation canreconcile this.

The problem as I see it with Alex’s approach is where do you stop? DoestheOrder object encapsulate every property ofCustomer? What aboutsub-properties of theCustomer’s properties? It seems the decision toencapsulate the Customer’s name is driven by the view’s need to displayit. I wouldn’t want my domain object’s interface to be driven by theneeds of the view as that would violate separation of concerns.

There’s another option which might be more common in theASP.NETMVC world than in the Railsworld, I’m not sure. Why not have a view specific model object. Thiswould effectively be the bridge between the domain objects and the viewand could encapsulate many of the these properties that the view needsto display.

Another case where an LoD violation might not be such a bad idea is incases where the object structure is public and unlikely to change. Whilein Norway, I had the opportunity to briefly chat withMichaelFeathersabout LoD and he pointed out the example of Excel’s object model fortables and cells. If LoD is about encapsulation (aka information hiding)then why would you hide the structure of an object where the structureis exactly what people are interested in and unlikely to change?

Use It or Lose It

When I learn a new guideline or principle, I really like to dig intowhere the guideline breaks down. Knowing where a guideline works, andwhat its advantages are is only half the story in really understandingit. When I can explain where it doesn’t work and what its disadvantagesare, only then do I feel I’m starting to gain understanding.

However, in writing about my attempts at understanding, it may comeacross that I’m being critical of the guideline. I want to be clear thatI think the Law of Demeter is a very useful guideline and it applies inmore cases than not. It’s one of the few principles that can point to anempirical study that may point to its efficacy.

In aValidation of Object-Oriented Design Metrics as QualityIndicators,the authors of the study provide evidence that suggests The Law ofDemeter reduces the probability of software faults.

the-countStill, I would hope that those who apply it don’t do it blindly bycounting dots. Dot counting can help you find where to look forviolations, but always keep in mind that the end goal is reducingcoupling, not dots.

Found a typo or mistake in the post?suggest edit

Comments

avatar

24 responses

  1. Avatar for Daniel Lindh
    Daniel Lindh March 11th, 2010

    I have the last couple of days been thinking a bit about The Law of Demeter and Composition, and it feels like this article is the sum of all my thoughts. Thanks

  2. Avatar for Zohirul Alam Tiemoon
    Zohirul Alam Tiemoon March 13th, 2010

    Good explanation on LoD.

  3. Avatar for Rus Pornoları
    Rus Pornoları August 20th, 2010

    Yes Really Good explanation

  4. Avatar for David V. Corbin
    David V. Corbin September 29th, 2010

    Although you mention ASP.NET MVC...you completely miss the MVVM pattern used by WPF/Silverlight...
    In this case a View Model exposes exactly what the view should interact with.
    Using the specific example, exposting the Customer object (to get the name) also exposes the remainder of the customer object. This is dangerous. What if the view creator (often a graphic designer rather than a programmer) accidently binds a button to Order.Customer.DeleteAllInformation() !!!!
    Why should a Order FORM (screen/report/etc) be dependent on a customer object at all? Sure it needs a name (probably address, phone, etc), but could that not be some entity that is not a "Customer" in the underlying system?

  5. Avatar for Tom
    Tom October 22nd, 2010

    hahah that purple guy

  6. Avatar for Rob Edwards
    Rob Edwards November 4th, 2010

    It seems to me that in order to make things separate in the Order/Customer scenario, the following would be considered. The Order doesn't need access to all of the properties of a customer, just a subset. That subset could be encapsulated into a class, like Billing Info or Shipping Info that contains a customer's name, address and the like. Just like the wallet example has the Officer class consuming the Driver's License class, the Order class should consume a BillingInfo or ShippingInfo class that Customer provides.

  7. Avatar for ADK
    ADK November 14th, 2010

    Good coverage of the LoD argument. I would go on to point out that the suggested "fixes" to LoD violations that are usually covered in such discussions don't really cover the bases. IMHO, the tenet "tell, don't ask" leads us toward a solution more in keeping with the spirit of the law.
    e.g.man.getWallet().getMoney(double amount) would becomeman.pay(Payee payee) where Payee is an interface implemented by the Paperboy. In fact, it may even be implemented by the Paperboy's Wallet, which he passes to the Man. The Man neither knows nor cares - which is kind of the point.
    To apply this toOrder.getCustomer().getName() we have to think about what we plan to do with the Customer's Name. Are we just displaying it somewhere? If so, perhapsorder.display(OrderDisplay display) would be an alternative solution. You would implement the OrderDisplay to do what you wanted to do with the order details.
    IMHO, this solution is really what the LoD should lead us towards. I should also point out that this will not always be "better" than the LoD violation, as it can tend to make the class take on too many responsibilities. e.g. is it really the job of an Order to display itself? Perhaps it is in your model - or perhaps not. Some judgement is required.

  8. Avatar for Gary
    Gary December 5th, 2010

    I thought Dementers were something to do with Harry Potter.

  9. Avatar for Headlight Converters
    Headlight Converters May 23rd, 2011

    well done, nice informations about LoD

  10. Avatar for Alan
    Alan June 21st, 2011

    It does seem pretty silly to say that data must be normalized in the DB and it must be fully denormalized in the application.

  11. Avatar for James
    James February 21st, 2012

    Good summary.
    As with all software design principles, LoD is mostly a good suggestion. For most internal method calls, if the object is purposefully tightly coupled to another object (by design, where they are separate objects conceptually, but not really decoupled functionally), violating LoD can be OK, because it wouldn't really be able to decouple anything without creating a sea of objects that "don't make sense" to most people. For external calls, LoD really ought to be followed, because it is far too easy to provide unseen security holes by sending an entire object, as opposed to a specific set of data that can be verified as secure.
    The page view case is more in the "internal" category, since it is still local code, and some items like reports are intrinsically bound to the underlying data, no matter how many layers you put between the view and the data. But if there are many reports that look at similar data, it can make sense to centralize that aspect of the data model, and create a specific viewmodel that flattens it out for each slightly different report. That way, if the underlying data structure changes, you only need change the properties in that single viewmodel, instead of in each of the dozens of reports that reference it.

  12. Avatar for Theodore R. Smith
    Theodore R. Smith August 14th, 2012

    It looks like this article is a **blatant** plagiarism ofhttp://www.dan-manges.com/blog/37, written exactly two years earlier... Care to explain?

  13. Avatar for haacked
    haacked August 14th, 2012

    Well we both discuss the same topic, but it's clearly not plagiarism. The approach we take and the language used is very different. The only similarity is our use ofmetasynctatic variables foo.bar.baz.

  14. Avatar for haacked
    haacked August 14th, 2012

    Oh, the other similarity is that I reference and properly attribute thepaperboy example by David Bock.
    The post you mentioned also uses that example but fails to attribute it. Perhaps that led to your false charge of plagiarism.

  15. Avatar for Theodore R. Smith
    Theodore R. Smith September 12th, 2012

    haacked, that could very well be it.
    I looked again at the article you referenced. Its example looks to be in C# and both of your guys is in Python.
    The thing that looked the weirdest was how you both have
    <%= @order.customer.name %>
    and then

    <%= @order.customer_name %>
    But that could very well be chance, and you're right, the other guy doesn't attribute at all, further muddying the waters.
    I apologize.

  16. Avatar for Sergey Akulinin
    Sergey Akulinin July 25th, 2013

    Very good article!
    As for me, next example shows real reason of LoD usability:

    public function order($application) {
    $application->getProduct()->addToCart();
    $application->getCustomer()->checkout();
    }


    Why we don't pass real dependency for the function (customer and product), but pass application object? LoD is violated here and shows us bad architecture.
    In next example I will never want to follow LoD:

    public function testStructure($root) {
    $directoryElements = $root->getDirectory()->getSubDirectory()->getChildren();
    $this->assertGreaterThan(0, count($directoryElements));
    $anotherDirectoryElements = $root->getAnotherDirectory()->getChildren();
    $this->assertGreaterThan(0, count($anotherDirectoryElements));
    }


    IMHO LoD should be re-defined in the way to handle the difference of 2 above examples.

  17. Avatar for Christian Tietze
    Christian Tietze April 30th, 2014

    I wonder: what is your opinion on (1) "presenter" objects, and (2) "data-transfer object"-like representations of the `Order` model for rendering purposes?

    In Rails-land, both approaches seem like over-engineering at first.

    I think it's reasonable to give `Order` the ability to compile an `OrderRepresentation` or something similar which is just a value object containing all the data the view likes to have. This way, the presentation layer can't access the model objects. Although we wouldn't do this intentionally of course, this way we can't even modify model objects by accident when we're writing view templates.

    I think this separation has its benefits: security and a buffering layer between model and presentation. But it adds complexity to the overall application because it introduces a presentation object for every aggregate (or every entity).

  18. Avatar for Programaths
    Programaths February 13th, 2015

    I am glad that PHP uses arrows "->" and that XQuery uses slahses "/" !

  19. Avatar for JeanFrederic Nault
    JeanFrederic Nault August 16th, 2015

    For the examble of the view with the order. Order should not have a property username, it should have a method getUserName that will use the user object.

    So the view know the order
    The order now the user

    The order expose through its public interface a method to communicate with its user object

  20. Avatar for Jeffrey L. Whitledge
    Jeffrey L. Whitledge October 7th, 2015

    A piece of code that is designed to display an order does not need to know—and should not know—anything about customer names. To do so is not only a violation of the LoD, but it is also (more importantly) a bad design.

    Is the customer name stored in one field or two or several? It is common to have first_name and last_name. It could also be prefix and sort_name, to better handle international names. Perhaps titles are stored separately. Perhaps there is a formal name and a familiar name. Is there a maximum length for the name?

    Can any of these things change? And if they change, how much code is expected to change to support that?

    Why should the programmer who is responsible for displaying orders need to get into the nuts-and-bolts of customer names?

    The correct design clear and simple: The code that displays the order information does not display customer's names, but rather it displays a Customer. An entirely different piece of code will be responsible for figuring out how the customer is to be displayed.

  21. Avatar for Alex Perez
    Alex Perez December 21st, 2016

    Regarding the example with the view, wouldn't using a Data Transfer Object (https://en.wikipedia.org/wi... be the better choice versus the existing two? In that case, there's no violation of LOD in the view itself since all the data used in the View are fields in the DTO, which becomes the only place where where the coupling should happen, AKA the only object that needs to talk to the View's dependencies is the DTO.

  22. Avatar for Roy Stegers
    Roy Stegers May 19th, 2017

    Very good acticle!

  23. Avatar for Omid Khadem
    Omid Khadem October 16th, 2018

    I think the problem with violating LoD in view you mentioned is not relevant because of separation of concerns. If some data has to be shown in view clearly what we want is a data structure and not a object. Just think about what happen if we pas an object with behavior to view? One could accidentally mutat object state in view! So in this case maybe we must ask the order object for a read only representation of its data (whic it can control to what it expose) as a data structure. As uncle Bob said in his great book “clean code”, law of demeter depends on if class is an object or data structure.

  24. Avatar for Zack Light
    Zack Light June 22nd, 2023

    It seems to me that LOD is especially useful/applicable if the object returned from an violation goes through various transformation such as the wallet example. However, if there are not any transformation logic, as in the UI & driver’s license example. We could justify it by saying one of the chained objects serve as containers, and the violation is okay.


[8]ページ先頭

©2009-2025 Movatter.jp