TITLE: A Short Introduction to the Law of Demeter AUTHOR: Eugene Wallingford DATE: December 14, 2012 3:50 PM DESC: ----- BODY: Preface My students spent the last three weeks of the semester implementing some of the infrastructure for a Twitter-like messaging app. They grew the app in three iterations, with new and changed features at each step. In the readme file for one of the versions, a student commented:
I wound up having a lot of code of the sort
I smiled and remembered again that even students who would never write such code in a smaller, more focused setting can be lulled into writing it in the process of growing a big, complicated program. I made a mental note to pay a little extra attention the next time I teach the course to the Law of Demeter. I actually don't talk much about the Law of Demeter in this sophomore-level course, because it's a name we don't need. But occasionally I'd like to point a student to a discussion of it, and there don't seem to be a lot of resources at the right level for these students. So I decided to draft the beginnings of a simple reference. I welcome your suggestions on how to make it better. You might also check out The Paperboy, The Wallet, and The Law Of Demeter, a nice tutorial I recently came across. What is the Law of Demeter? The Law of Demeter isn't a law so much as a general principle for software design. It is often referred to in the context of object-oriented programming, so you may see it phrased in terms of objects:
Objects should have short reach.
An object should not try to know too much, or need to.
The law's Wikipedia entry has a nice object-free formulation:
Only talk to your immediate friends.
If those are too squishy for you, the Wikipedia entry also as a more formal summary:
The fundamental notion is that a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents).
Framed this way, the Law of Demeter is just a restatement of OOP 101. Objects are independent. They encapsulate their state and behavior. Instance variables are private, and we should be suspicious of getter methods. As a matter of programming style, I often introduce this principle in a pragmatic way:
An operation should live with the data it uses.
Those are all general statements of the Law of Demeter. You will sometimes see a much more specific, formal statement of this sort:
A method m of an object obj may send messages only to these objects:
This version of the Law is actually an enumeration of specific ways that we can obey the more general principle. In the case of existing code, this version can help us recognize that the general principle has been violated. Why is the Law of Demeter important? This principle is often pitched as being about loose coupling: we should minimize the amount of knowledge that any component has about the implementation of any other component. Another way to think about this principle from the perspective of the receiver. Some object wants access to its parts in order to do its job. From this angle, the Law of Demeter is fundamentally about encapsulation. The receiver's implementation should be private, and chained messages tend to leak implementation detail. When we hide those details from the object's collaborators, we shield other parts of the system from changes to the implementation. How can we follow the Law of Demeter? Consider my student's example from above:
The simplest way to eliminate the sender's need to know about thisInsideCollection and thisAttribute is to Coming up with a good name for the new message doSomething forces us to think about what this behavior means in our program. Many times, finding a good name helps us to clarify how we think about the objects that make up our program. Notice that the new method in thisCollection might still violate our design principle, because thisCollection needs to know that thisInsideCollection is implemented in terms of thisAttribute and that thisAttribute responds to thisMethod(). That's okay. You can apply the same process again, looking for a way to push the behavior that operates on thisAttribute into the object that knows about it. More generally, when you notice yourself violating the Law of Demeter, think of the violation as an opportunity to rethink the objects in your program and how they relate to one another. Why is this object performing this task? Why doesn't its collaborator provide that service? Perhaps we can give this responsibility to another object. Who knows how to help this object with this task? Sometimes, we even find that we can move thisMethod() into thisCollection and take our object out the loop entirely, letting the object that sent us the message communicate directly with thisCollection. That is a great way to make our code less tightly coupled. A Potential Wrinkle There is a potential problem when we program in a language like Java, though. What if thisCollection is a primitive Java class, say, a Vector or a HashMap? If so, you cannot add a new method to the class. This is sign of another problem looking in your program. This object depends on your choice of data structure for thisCollection. What role does thisCollection play in your domain? Maybe it's a catalog of users, or the set of users that follow another user. Make a new class that represents this domain object, and make your data structure an instance variable in that class. Now you can write your program in terms of the domain object, not the Java primitive. This makes solves several problems for you: This new wrinkle is sometimes called Primitive Obsession. OO masters know to beware its temptations. I sometimes like to play a little game in which every base type and every primitive class has been pushed down to the bottom layer of my program and wrapped in a domain object. This is often overkill -- taking a good thing too far -- but such an exercise can help you see just how often it really is a good thing to hide implementation detail and program in terms of the objects in your domain. -----