Talking to strangers in 1930s Moscow was not a smart thing to do. Mikhail Alexandrovich Berlioz (chairman of the management committee of one of the biggest Moscow literary clubs – MASSOLIT) and his young companion, poet Ivan Nikolayich Poniryov (who wrote under the pseudonym of Bezdomny) knew that all too well. Yet, this is exactly what they did at the sunset hour of one warm spring day at the Patriarch’s Ponds when a suspicious-looking stranger approached them.
The stranger turned out to be the Devil himself and if you wish to know more about what awaits Berlioz, Bezdomni, and the citizens of Moscow when the Devil and his entourage come for a visit, go read Mikhail Bulgakov’s masterpiece Master and Margarita. Since this is a blog on software development, you may be wondering: what does this have to do with software development?
Well, talking to strangers can be dangerous when it comes to software development, too. And it is expressed by an Object-Oriented design guideline called The law of Demeter. It says that a “module should not know about the innards of the objects it manipulates”. [1]
The formal definition of the Law of Demeter states that when writing a method in a class, our methods should only call:
- other methods of the class
- methods on an object that was created in our method
- methods on an object that was passed as an argument to our method
- methods on an object that is a class property
class TheClass {
private OtherClass $instanceVariableObject;
private function otherMethodOfTheClass() {}
private function demeter(PassedInClass $argument)
{
// other methods of the class
// this is okay
$this->otherMethod();
// methods of an object we created
// this is okay
$object = new ClassC();
$object->someMethod();
// methods on an object passed in
// this is okay
$argument->someMethod();
// methods of a class property
// this is okay
$this->instanceVariableObject->someMethod();
}
}
But, our method should not invoke methods on objects that are returned by any of these allowed method calls. In other words, objects should only talk to their friends, never strangers. And in this context, friends of friends are considered strangers.
Here is a typical Law of Demeter violation example:
$blog->comments()->add($comment);
Chained method calls can be a good indicator of this, but even if we “unchain” the methods, a violation persists.
$commentCollection = $blog->comments();
$commentCollection->add($comment);
Our calling code knows about the Blog
object. This is its friend. The Blog
object knows about the CommentCollection
object. That is its friend. But to our calling code, CommentCollection
is a stranger and we should not be talking to strangers. In more technical terms, our calling code is aware of the internal structure of the Blog
class, so if this internal structure changes we would have to update our code. This is more coupling than we need.
What we can do instead is have a method on the Blog
itself:
$blob->addComment($comment)
Our calling code only needs to know how to call this addComment
method on a Blog
object. It doesn’t need to know how a Blog
object will add that comment internally, and if we change the way that a Blog
keeps its comments internally, our calling code won’t need to be updated. Thus, we have reduced the coupling of our code. And that is good since higher coupling increases the chances that any (small) change we make will break something else. So we want less coupling.
The downside of obeying the Law of Demeter is that you may end up with a lot of delegate methods that act like wrappers:
public function addComment(Comment $comment)
{
$this->commentCollection->add($comment);
}
Some would argue it could also be an indicator of problems in your design, especially if you have these methods nested across objects.
In any case, although talking to strangers in software development may not be as dangerous as in Soviet Russia (and you won’t end up like poor old Berlioz), The Law of Demeter is still a useful design principle to know and to apply when possible.
[1] – Robert C. Martin – Clean Code
Member discussion