Tell, Don't Ask in the case of a web service
Tell, Don't Ask in the case of a web service
Join the DZone community and get the full member experience.Join For Free
See why over 50,000 companies trust Jira Software to plan, track, release, and report great software faster than ever before. Try the #1 software development tool used by agile teams.
This is a language agnostic post: it is valid for each object-oriented imperative language like Java, C#, PHP.
Let's start from the beginning: a web service adapter
I had a requirement: downloading posts from a particular group on LinkedIn for analysis of their content. So far so good: for any integration with my applications I follow the Hexagonal Architecture.
According to Cockburn, the Hexagonal Architecture features a series of ports (usually interfaces defined in the language), where you can plug in adapters to make the application actually work. Persistence is dealt with Repository interfaces; web service integration with a WebServiceName interface. In my case, the implementation is an object that asks the LinkedIn Api via HTTP.
The rest of the application just depends on the interfaces of the ports: testing becomes easier as for new test cases you can plugin a Test Double for the web service, which is able to return all the fake XML (or JSON) responses you need.
With this habit in mind, I started test-driving this design:
Scribe is the name of the OAuth library used for making the requests in the implementation of the service. PostsParser composes the service, and is the first object in the domain of my application. The code is a bit simplified omitting the need for timing limits and various options in the request.
Recapping: now my code depends on an interface and I can test most of it with a stub returning fake XML responses. I actually just put one object in front of it to analyze the XML, so from then on the rest of the system will work with Plain Old YourLanguage Objects. Right? Right.
Can you see the problem yet?
Weren't getters evil? Am I mocking or stubbing?
Yes, getters on objects containing logic are not my definition of clean code. However, when I write adapters I fill the classes with them: getPosts(), getUsers(), getComments()...
I can segregate the methods in various interfaces, and have just one implementation. This time let's try something different and get some inspiration from what is called (wrongfully) the London school.
I watched a Ruby presentation (to write with a Java application, as a PHP programmer... I told you this post was language agnostic), titled Why you don't get mock objects.
An outlined problem was that often we are writing mocks which become stubs, and we both verify the arguments passed to them and the result of the computation:
$mock = $this->getMock(); $mock->expects($this->once) ->method('whatIsThis') ->with(42) ->will($this->returnValue("The answer")); ...bit of work to obtain $response from a real object composing the mock... $this->assertEquals("According to Deep Thought, 42 is The answer", $response);
State-based (the assertion), and behavior-based verification (with(42)) at the same time are becoming a smell to me. This kind of tests also lead to test and production code which are mirror each other.
In our LinkedIn example, I have to verify the parameters (groupId == 23 and postsToFetch == 10, or whatever), and that the class composing the service does its job (returning Post domain objects containing the right values parsed from XML).
There was also an interesting discussion on Hollywood objects in the GOOS mailing list a while ago. Hollywood objects were defined as hypothetical objects that do not have getters, but just methods with callbacks:
mainObject.getField(); //becomes: mainObject.tellField(objectWhoNeedsIt);
The missing piece in that discussion (I may have missed even if someone wrote it) was that objectWhoNeedsIt was passed on the stack, and tellField() is a level of indirection which I find useless in most cases.
But if objectWhoNeedsIt is passed in the constructor of mainObject it becomes a collaborator. The method call becomes just mainObject.tellField().
My new solution
Now that I have refreshing my ideas on object composition, let's try to eliminate the getter on LinkedInService:
Inverted Dependency Inversion... nice name. PostsParser will in turn pass his newly created Post objects to someone else, and so on and so on. No need for getters on ScribeLinkedInService, and I don't even need a stub for the service now; the Test Doubles I use are still all mock of my own types, but excluding the service.
Repeat with me:
Why is that so? Each object does it work and a part of the system can change without affecting the rest of the application (the messages does not change). Method calls which asks for state expose very much of the two objects that interact, since data flows into two directions as parameters and return values.
We cannot always use so-called Hollywood objects, but when appropriate, method calls which just tell only go in one direction and simplify the protocol. When the protocol is simpler, you reap the benefits while substituting objects for testing or for adding new behavior to the system.
Hey, the whole aynchronous paradigm in SOA, or of events between DD Aggregates is also based on this advantage of one-way communication.
Why I mock less often than I can?
The tools we use have a profound (and devious!) influence on our thinking habits, and, therefore, on our thinking abilities. -- Dijkstra
I originally used only JUnit and PHPUnit for TDD: the absence of a mocking framework in the first and of decent matchers in the second has lead me to favor state-based verification with lot of assert*() even when mocks proved equally capable. As a consequence, I wrote a lot of getters instead of following the Tell, Don't Ask principle. State-based verification is also how I learned (and taught) TDD, since it is the most immediate method.
But now I have transformed my LinkedIn code: it's easier to test with mocks, and it's easier for me to substitute objects.
Opinions expressed by DZone contributors are their own.