[Moved from LawOfDemeter
Demeter and Unit Tests
s easier. Consider:
person deductionProfiles last stateTaxDeduction amount "SmalltalkLanguage code"
person.deductionProfiles().last().stateTaxDeduction().amount(); // JavaLanguage version
To test this, we need to instantiate a deduction profile, a collection of them, a state tax deduction and give it an amount. That's a lot of objects and setting up to do. If we use the "real" objects, we'll be testing half application rather than a single unit (especially if each object is tied to other objects in turn). If we use dummy StubObject
s, we've still got a lot of stub classes and methods to write for this test, and the test will be relatively slow to run.
If we refactor into something like:
then we only have to write one StubObject
Stub, and one method, to
get the line of code to run. Testing will be easier and faster.
This shows that Demeter genuinely tends to produce less coupling.
What are you testing, Person, or the functionality of the object you get via stateTaxDeduction? The functionality of the object returned by deductionProfiles should be tested in the DeductionProfile? unit tests, not the unit tests on Person.
I'm in the process of rewriting a large chunk of code from my current project. The new version is far more Demeterish than was the previous one, and the difference is remarkable--now, when I'm working on a section of code, I can see directly what other parts of the code it relates to. This means that I can give my full attention to the part I'm working on, rather than having to wonder about how it affects the rest of the program. This is especially helpful since I'm working in MacromediaFlash
, which really isn't meant for programming and has no useful development tools. -- MossCollum
I tend to treat it as a guideline. E.g. If I'm violating it, and I can't justify the violation, then I ought not to be violating it. On the other hand, the OKBC protocol (for accessing knowledge bases) has the very un-demeter like command "follow slot chain" and I get the feeling that LISP programmers, in particular, find Demeter repugnant. -- WilliamGrosso
To use a real-world analogy: A dog has legs. If you want your dog to run do you talk (send a message to) your dog or to each leg? Further, should you be able to manipulate the dog's leg without it knowing about it? What if your dog wants to move its leg and it doesn't know how you left it? You can really confuse your dog. (See: DontConfuseYourDog.)
We can generalize this scenario. A "Master" class exposes a "Detail" class. You can talk to the Detail directly, but then you find that the Master needs to know what you've done with its Detail. Often you get better encapsulation by hiding the Detail and talking directly to the Master.
But consider an Order-OrderItems structure, where you have to indicate whether various OrderItems are to be dispatched
[Order Items are basically Line items in an Order. So if you have just bought stuff from Circuit city you have one single order and it could have one or more order items like a P.C, TV, Monitor, Memory etc]. There are a few ways you could do this:
1. Order.OrderItems[n].State = dispatched
2. Order.setItemState(ProductID, dispatched)
3. OrderItem? = Order.findItem(ProductID);
Well, you might be missing a DomainClass?
. If you're working with a business that ships out partial orders, it needs per-shipment information stored anyway, such as tracking numbers and such. So you'll probably want to define something like an O
rderShipment class, which points to one Order and one or more O
rderItems. Once you've done that, it's naturally O
rderShipment's responsibility to notify its O
rderItems that they've been dispatched. Or maybe that step is entirely unnecessary, since you might be able to infer if an O
rderItem has been dispatched by asking if it belongs to an O
rderShipment. -- francis
At the risk of drifting off topic for this page... An Order is one thing and a Shipment is another thing. Each may have "items", but there is not necessarily a one-to-one relationship between an OrderItem and a ShipmentItem (let alone between a Shipment and an Order). You may, for example, order seven widgets and receive only five, then order three more widgets and receive a further four, and then receive one final widget. In this case, you have two Orders and three Shipments; the second Shipment has (depending on your point of view) one ShipmentItem, two OrderItems (both partial, or one complete and one partial), or two ShippedOrderItems.
Right. There are many ways in which complications can arise: It's up to the programming team to understand what level of complexity is appropriate for their client. (For example, I think there are a lot of small merchants who don't ship partial orders just to keep things simple.) The general lesson to take away, I think, is that code like the example code above might be a sign that you could use an intermediate object of some sort to take on responsibility for itself -- less coupling more cohesion yadda yadda yadda. Which could be related to what's said below about seeing the LawOfDemeter
as a smell. Maybe. --francis