I’ve been working with a programmer recently who is new to both design patterns and object oriented programming. He’s been maintaining some old code I wrote a while back and trying to change how it behaves. Obviously, this could be challenging for someone who’s new to OO.
So, the other day he asked me to explain what Service Objects are. I tried to explain the nature of the Faade design pattern and how a service is simply a faade for more complex operations in your system. I tried to explain that it’s a good practice to wrap all of your model objects to make it easier to expose this functionality to various systems.
Honestly I wasn’t terribly successful with this explanation. In his particular case his service was going to use a gateway object (yet another design pattern) to get a query and return it. But, if the service is returning a query, how does the service differ from the gateway?
I had to think about how to explain this, and what I came up with was this analogy:
Let’s say I ask you to get me a nice frosty mug of beer. If you agree to get me this cool, refreshing, beer, you’ll be performing the service of getting a beer. You, you’re a service object. You perform a service.
Now, personally, and I’m not trying to be rude here, I honestly don’t care how you get the beer. You could run to the store and buy a mug, some dry ice, and a six pack. You could go to the neighborhood pub and run off with a fresh drawn beer. More likely, you’ll just walk (heck, you could run or skip, for all I care) to the fridge, grab a beer and poor it into a mug, and bring it back to me. And, just to illustrate my point again, you could use a bottle opener, your teeth or any other mechanism to open the beer. To me, those are just (implementation) details that don’t matter, so long as I get my frosty mug of beer back.
Now, let’s think about what you care about as the service. Do you care how the fridge stays cold? Do you care how it was manufactured? Do you care how the beer was brewed? You might care what brand of beer (microbrews only, please), but chances are that’s already a constraint of the system you’re running in. You don’t care how long the beer was fermented. You don’t care how long the mugs are kept cold to make them frosty. All these details are the responsibility of other systems that, though essential ultimately, to you, my BeerService, being able to successfully get me my beer.
So, lets break the analogy down a bit. Who are the players and what do they represent?
Me/I. I represent any system which uses your service. I could be a remote faade used by flex. I could be a controller in your MVC framework. I could be another service that just really needs a beer.
You. You’re a BeerService component (or maybe a BarTenderService). You have a set of methods related to beer (or bartending, I guess, as the case may be). For example, getBeer(), restockBeer(), cleanMugs(), wipeUpSpills(), cutOffUser(), etc. As the user of the service, I don’t care how you get these things done, you just do them, far as I’m concerned.
The Fridge, The Beer, The Mug, etc. These are components within your application’s model. In real computer systems these are objects that have specific responsibilities. For instance, the mug in our system is responsible for being frosty and holding beer. In a real system you might have a BeerGateway that is responsible for listing beers in your database.
I hope that helps clarify things!
Comments on: "Service Layers, an Analogy" (6)
Doug, I like where you are going with your explanation (as I am new to this kind of OOP style programming). However, I wasn’t really sold (as to the difference between a gateway and a server layer) until you actually got into the “BarTenderService” that would handle more than just getting you a beer.
I think with the beer-only example, there is not much of a difference between a gateway. A gateway gets data… maybe it gets it from a SQL Server, maybe it gets it from an XML file, maybe it gets it from a web service… the idea of not careing how/where the data comes from is, to me, akin to not careing where the beer comes from.
However, once you start talking about a BarTender taking orders, restocking, cleaning spills, I think this does a much better job of illustration the encapsulation of many services into one related and easy to interface-with service object.
Where is the behavior in the objects? Is this service oriented or object oriented (or both?)…
I didn’t think it was clear in the description if this is a case of anemic domain model (see http://www.martinfowler.com/bliki/AnemicDomainModel.html) Although it certainly is a good description of what a service does, I didn’t see the object part coming across well.
Of course, I could just be a bit blind, or the mention of beer distracted me from following the discussion. =)
Good post overall though!
I respectfully disagree, I think, with your assessment of this as an anemic domain model.
This is essentially a very simple app (getting Doug a beer). It’s objects will be simple. But the BeerService IS doing something — it’s getting you a beer.
I think you were actually distracted by the word “get”. Usually, get in our objects really means “return value” (or something very close to that). In this case, the service is actually “getting” you a beer. A longer, but slightly less “anemic” sounding method name might be prepareTransportAndServeBeer().
To resolve the issue that Sammy raises, can I modify the analogy a bit?
Le’s say our application is a fast-food restaurant. Among other things, it provides DriveThroughService. As far as the service clients are concerned, the interior of the restaurant is a mystery. All they know is they hand over an order and money, and get back food.
That doesn’t mean that all of the cooking, packaging, moneycounting, etc are all done by an object called DriveThroughService. No, DriveThroughService is just a thin layer on top of the domain objects (employees), which do the actual work. DriveThroughService hands over an order to the register system, which tells FryCook to prepare some fries, and Cashier to collect $1.99.
From the customer’s perspective, he’s just interacting with the DriveThroughService. The fact that he’s actually interacting with Stan the Cashier is completely hidden from him. From the application’s perspective, all of the domain objects are very important, and the DriveThroughService is pretty trivial.
@Toby – I didn’t mean to imply that this was definitely a case of having an anemic domain model. Instead, I merely wanted to point out that I felt the example didn’t adequately focus on “object orientedness.”
Now, the title of the post makes it clear that this is /supposed/ to be an analogy that explains service layers, but the first paragraph and the resulting explanation left me wanting more OO.
I don’t suppose it really would be anemic, since as you mention, it is a very simple system. But, it /looks/ like it because almost all of the behavior is concentrated on the service, with very little left to the domain objects. Not trying to knock Doug at all, but as he said “Honestly I wasn’t terribly successful with this explanation.”
I guess I just wanted to raise the question in hopes of finding a better analogy, because the domain objects in the story didn’t really do much of anything (hence, my question about anemia).
@Tim – I think your analogy does that a bit better.
I still think I was distracted by the beer though. =)
@Ben – The main difference between a service and a Gateway is that the service is simply responsible for using other components to accomplish its task. A gateway is responsible for acting on sets of data (for example quering a database). The service uses the gateway to accomplish its task while the gateway lists data in the database. And yes, the service has many methods that preform related tasks. It’s a facade into your system. A set of services really are an API for your entire system.
@Sammy – I didn’t attempt to make this example either anemic or otherwise. Honestly, I havn’t been following this debate. I’ve just been doing things that work well for me. 🙂 But, having read the first couple paragraphs from the link you sent I’d say that you’re right that this example doesn’t address that. But, my intent was that the fridge would be responsible for its own business rules as much as the mug its. The service component is simply a facade used to simply interaction with theses (potentially) more complex systems. Additionally, because the interface is simplified I can expose this service via a remote facade (for webservices, or whatever) to an MVC framework, to Flex to anything. I just try to hide the complexity of my system and provide a simple way to work with it. So…. probably not anemic.
@Toby – Again, I didn’t specify this, but I would say that I would personally give these objects behaviors as well as data. An component with a getters and setters is not necessarily anemic.
@Tim – Bingo