On a quest for the silver bullet..

Law of Demeter: A real-world example

Demeter - http://www.flickr.com/photos/zaqarbal/2416461325/ The Law of Demeter (LOD) helps decouple objects, it makes mocking intensive tests much easier to write, and it offers a concrete set of rules that can make things clearer.

I recently ran into an example in Glue where I refactored towards LOD. I will share my thoughts on that here.

The problem

I am working on a new feature in Glue. In order to make room for that feature, I had to do some refactoring, to make it smoother to add that feature. What I found during the refactoring was this line (in the Mapper-class):

1
mapping.Relations.GetRelationsTowardsRight()

I found it because I already had some trouble with the Mapper class’ dependency on the Mapping class. I realized that I was exposing a lot of information, Mapper shouldn’t know about Mapping. This dependency made my refactoring job bigger. I strongly believe that objects should know as little as possible.

This is a good example of breaking LOD. I think breaking LOD isn’t always a big offense (Martin Fowler suggests we rename it “Suggestion of Demeter”), and I don’t think doing it here is my largest mistake. But now a new feature had brought the need for some refactoring, and at this point applying LOD seemed like a good idea. So it’s not only a question of where to apply a pattern, but also when.

The solution

The Mapping class is a kind of facade to the rest of the system. It is an attempt to make the API as simple as possible. That means it handles the creation of some objects. In our case this is how Mapping creates Mapper objects:

1
var mapper = new Mapper<LeftType, RightType>(this);

(Notice how Mapping passes itself in to Mapper). Mapper gets what it needs by calling:

1
mapping.Relations.GetRelationsTowardsRight()

Mapper gets a RelationContainer (the Relations property) from Mapping.

This breaks LOD. There is a simple fix in this case. The code passes a Mapping object, while what the Mapper wants is a RelationContainer. We should only pass the object it needs (in the Mapping class):

1
var mapper = new Mapper<LeftType, RightType>(Relations);

The Mapper now gets what it needs by calling:

1
relations.GetRelationsTowardsRight()

It’s fixed!

This way we have lowered the coupling, making Mapper unaware of Mapping, meaning that now it can access only what it needs, not a whole lot more. For me it is important that objects know as little as possible, and now it knows a whole lot less. It doesn’t care (or know) where the RelationContainer comes from. That isn’t its concern, and shouldn’t be either.

(The Law of Demeter is a rather academic specification of who is allowed to call who, specified here. Basically what it boils down to is that you shouldn’t ask for other objects from an object, and do an action on that. Or in other words, you should just use one dot per line.)

Not the “standard” solution

This solution is not how one normally is advised to resolve the breaking of LOD. Normally you’re supposed to hide the inner object. In this case it would mean that Mapper should be unaware of the fact that Mapping contains a RelationContainer, it should just ask Mapping to get the relations (a concept called encapsulation, it’s pretty standard object oriented thinking). Like this:

1
mapping.GetRelationsTowardsRight()

That’s a smart solution, if you’ve got the right problem. That solution enables Mapper to only know about Mapping, and none of its collaborators (hiding the RelationContainer in this example).

But the problem we have here is slightly different. What I found here was that Mapper should not know about Mapping at all. Mapper should only concern itself with the relations, and in this case Mapper should only receive the RelationContainer to work with. So the problem was that we depended on the wrong object altogether, not that we had the right object, and had to know about its collaborator. A subtle, but important difference. It’s important to be aware of what your problem is in order to find the right solution. It’s not always as easy as choosing the “standard” solution.

Reflections on Law of Demeter

LOD is just a concrete set of rules that aims to help writing less coupled code. You can do this without even knowing about LOD. In our case, focusing on separation of concerns can yield the same effects. As can sound object oriented thinking, like hiding as much as possible (not exposing things through properties or getters), focusing on knowing as little as possible, applying “Tell, don’t ask”, and so on.

The problem with concrete rules like LOD is that it works great if you understand the intention, but if you do not, you’re probably going to apply it wrong. And if you understand the intention, often you can get the effects without even thinking about LOD.

For me, I like the intention of LOD , but I do not think about it that often, as I use other guidelines to help me yield the same result. On the other hand, knowing the LOD principle have helped me on several occasions, as in this example, to see clearly what is going on.

Also, if you need to justify a style of programming that is heavy on mocking, LOD is an often used argument.

This refactoring is checked in as changeset 52023 in Glue. Compare that and the previous changeset to see what was done.

- Tore Vestues

August 5th, 2010 at 22:05 (962)


Leave a Reply