I read multiple things about the Law of Demeter but I never truly understood what it really means until I read Sandi Metz's book Practical Object-Oriented Design in Ruby (POODR). This article is shamelessly inspired from her work
It's quite hard to understand the Law of Demeter when encountered for the first time. As seen in the definition from Wikipedia :
More formally, the Law of Demeter for functions requires that a
objectmay only invoke the methods of the following kinds of objects :
- Any objects created/instantiated within
object's direct component objects
- A global variable, accessible by
object, in the scope of
More generally, Law of Demeter is a range of coding rules that helps keep our objects loosely coupled. We always refer it as the "use only one dot" rule or "only talk to your immediate neighbors".
But what does it really mean ?
What Demeter is telling us
Consider we have a
Rental class that contains a
depart method. And we have an
Owner model, that own a
Car has an
Engine which contains an
oil_level attribute and a
start method. Let's say we have implemented our
depart method like this :
The chaining dots in lines 4 and 5 are almost identical. The first one retrieves a distant attribute (
oil_level) and the second one invokes a distant behavior (
What's wrong with those lines ?
It's a clear Demeter violation. Let's list our issues with this piece of code :
- If we change something in
Engine, it might break something in
Rental, which is completely unrelated. This code is not transparent.
Rentalcannot be reused unless it has access to an
ownerthat has a
carwhich contains an
enginethat responds to
This design increases the coupling of our application, and coupling is bad, really bad. You know that moment when you change something in class A and suddenly, it breaks another thing in class B ? Well, most of the time it's due to the fact that your application is too much coupled.
Now think about it. In our example,
Rental knows that an
owner has a
car with an
engine and it also knows that this
engine can be started. It knows way too much.
So, what can we do about that ?
Object-Oriented Design is about managing dependencies. — Sandi Metz
Note : in
owner.car.engine.oil_level we try to access a distant attribute. It is also a Demeter violation but it is a particular case because it might be cheaper not to change this. In some cases, if we just need to access the attribute, we can keep this as it is. Just remember that this tradeoff is permitted as long as we are not changing the value of the attribute we retrieve. If we change the value of the attribute, we are implementing a new behavior that belongs to Engine
Focus on behavior rather than data
What if we can do something like that :
Wouldn't be amazing ?
Well, guess what ? We can.
And by doing so, we are trusting other objects to behave according to the message we are sending them. As
Rental, we don't want to know how the
owner plans to drive and
start his car. We just need to trust him that he will.
Then, we can implement the drive method in our
Owner class and delegate the
start part to the last object that needs to know about it :
Engine. We end up with this :
Those small modifications increase significatively the quality of our code. Each object trusts each other that it will do its job.
Rental is now "open for extension and closed for modification".
What does it mean exactly ? I think it deserves a post on its own.