Is code like this a "train wreck" (in violation of Law of Demeter)?
Posted
by
Michael Kjörling
on Programmers
See other posts from Programmers
or by Michael Kjörling
Published on 2011-09-21T13:43:42Z
Indexed on
2012/10/24
17:14 UTC
Read the original article
Hit count: 282
language-agnostic
|clean-code
Browsing through some code I've written, I came across the following construct which got me thinking. At a first glance, it seems clean enough. Yes, in the actual code the getLocation()
method has a slightly more specific name which better describes exactly which location it gets.
service.setLocation(this.configuration.getLocation().toString());
In this case, service
is an instance variable of a known type, declared within the method. this.configuration
comes from being passed in to the class constructor, and is an instance of a class implementing a specific interface (which mandates a public getLocation()
method). Hence, the return type of the expression this.configuration.getLocation()
is known; specifically in this case, it is a java.net.URL
, whereas service.setLocation()
wants a String
. Since the two types String and URL are not directly compatible, some sort of conversion is required to fit the square peg in the round hole.
However, according to the Law of Demeter as cited in Clean Code, a method f in class C should only call methods on C, objects created by or passed as arguments to f, and objects held in instance variables of C. Anything beyond that (the final toString()
in my particular case above, unless you consider a temporary object created as a result of the method invocation itself, in which case the whole Law seems to be moot) is disallowed.
Is there a valid reasoning why a call like the above, given the constraints listed, should be discouraged or even disallowed? Or am I just being overly nitpicky?
If I were to implement a method URLToString()
which simply calls toString()
on a URL
object (such as that returned by getLocation()
) passed to it as a parameter, and returns the result, I could wrap the getLocation()
call in it to achieve exactly the same result; effectively, I would just move the conversion one step outward. Would that somehow make it acceptable? (It seems to me, intuitively, that it should not make any difference either way, since all that does is move things around a little. However, going by the letter of the Law of Demeter as cited, it would be acceptable, since I would then be operating directly on a parameter to a function.)
Would it make any difference if this was about something slightly more exotic than calling toString()
on a standard type?
When answering, do keep in mind that altering the behavior or API of the type that the service
variable is of is not practical. Also, for the sake of argument, let's say that altering the return type of getLocation()
is also impractical.
© Programmers or respective owner