By Peter Bell

Are Service Classes Communist Bureaucracy As Well?!

In a follow up to the Bureaucracy posting I noticed the other day, a new posting ups the ante by suggesting that service classes are also a waste of time.

The key comment:

The manager layer anticipates a future that may or may not happen. Because the language is inflexible, future-proofing is often done during initial development.

Not sure I agree. I find that I like being able to separate the concerns of what are effectively class vs. instance methods by putting them into two independent beans. That said SmallTalk and Ruby programmers seem to get by just fine without Service classes. Anyone have any experience of writing a big enough app in SmallTalk/Ruby/Python/whatever to comment on the relative experience of developing with and without service/manager classes?

Comments
I'm not sure I "get" what you're saying here:
"I find that I like being able to separate the concerns of what are effectively class vs. instance methods by putting them into two independent beans."

Would you stop using a service layer if you had static methods then? If that is the case, why do you see it in Java?

I thought he made a good point. (a little off topic: What is OO about keeping data in a data class and services on that data in a service class? we may as well go back to structs and libraries in C!)

More importantly, who are we separating concerns for? I would say it is for ourselves, not the machines. So, if the benefits to having a service class disappear (or some other mutex benefit someplace else outweighs it) in a dynamic language, which would you choose to do? (of course, one is free to choose -- I'm not trying to express any value judgement here)
# Posted By Sam | 5/12/07 7:21 PM
I personally find that the service layer offers a lot of benefit to the developer and the application.

What I usually do is create a service layer for all gateways, DAOs and many other types of handlers including an email service that can prioritize outbound emails in an email queue. Some may argue that I even overuse the service pattern, but in all truth, I think it is very underused in web applications.

1) Having services is often the more logical way for a programmer to think...
It often puts things in a very real world perspective. For instance, why do i see so many implementations of a shopping cart that not only contain items, but calculate all the invoice totals, manage taxes, shipping, etc. Doesn't it seem a little more logical to take the cart, along with coupons, etc. to a single register (similar to what you would do in real life)? I find it very easy to deal with a large set of requirements this way (no memorizing URL diagrams or looking at classes with 400 functions). With DAOs and gateways for a typical bean I like having the service layer to say, "Hey, go put this thing in storage for me" which could be totally different places (database, xml, etc.) any time I use the same bean. On the other hand, I can enjoy the active record type pattern by using ColdSpring to pass my beans a dao and give them an incredibly simple save method.

2) The application becomes incredibly solid with the use of the service layer...I love knowing that my application loads and 90% of the memory it will ever use is set and ready to go (and it is much smaller than reinstantiating a bunch of large objects on every request). My applications rarely bounce up and down by massive percentages of processor and memory usage because a few more or less users are on. It becomes very easy to spot when something is awry because I know what to expect.

Sorry for the long response, while I have viewed enough Ruby source code to decide that I'm not interested in its current state, the Ruby community has had a lot of great ideas and I think sometimes we get a little too radical for their own good. The "C structures and libraries" comment I think wasn't made disregarding the fact that dealing with those structures and libraries in C was an incredible pain. It is easy for us with these languages and we deserve that benefit for as little work as it is now.

Using beans vs structures isn't a battle really worth having, though I will say the main reason for having them as objects at all, at least as i see it, isn't for all the other nice things you can do like validation, etc. but so you know what you're passing around...unless you are going to validate that all the necessary keys exist in a struct before you try to do anything with it.

Anyway, sorry for the incredibly long comment...I'm quite windy sometimes.

Mike.
# Posted By Mike Kelp | 5/12/07 11:12 PM
After posting my previous comment, I decided to blog so that I could gather my words a little better. The following is the URL to that post if you are interested:
http://blog.edomgroup.com/blog/index.cfm/2007/5/12...

BTW, I just noticed that a sentince in my previous comment said:
I think sometimes we get a little too radical for their (<- should have been "our") own good.

Didn't want that to be interpreted as flame bait.

Mike.
# Posted By Mike Kelp | 5/12/07 11:53 PM
Against my better judgment, I'll respond.

There are two major problems with this post. The first is that the author uses an out-of-date Java example (probably intentionally) that makes Rails look like it's more special than it is. The second is that the example is so trivial that the need for a Service Layer isn't evident. Now for the details...

Point #1: So yeah, it's important to note that the example is using Struts 1.x, a framework that was originally developed about 7 years ago. At least they didn't compare it to writing equivalent code using a Servlet - complete and utter insanity - although I've seen other propaganda where the comparison is made to show how uberleet Rails is and why J2EE is teh suk! Of course, if they compared it to the current version of Struts (2.x) or even the its predecessor WebWork (which has been around for a number of years) you'd see that the code looks something like this:

public String execute()
{
Person p = manager.find(personId);
return SUCCESS;
}

If the best the Rails crowd can do is talk smack on Java code that was written 5-7 years ago then that's pretty sad. It's sorta like Ford coming out and saying that their 2007 model line is better than Chevy's from 1980. Yeah. Big surprise there.

Point #2: why a Service Layer? Let's see...

1. Server-side validation in controller/action = bad. If you need to expose part of your app over a remoting protocol like SOAP then you get to duplicate all that code in the new "web service controller" which incidentally will look exactly like your service layer if you just took the time to write it in the first place. So you get 2 for the price of 1 there.

2. Transactions... hmm, where to put these semantics? Not in the domain model of course, and the DAO is bad too. Imagine you have one data operation that actually needs to invoke another data operation from within it. If every DAO method is wrapped in its own transaction shit goes horribly wrong because most transaction managers can't nest transactions.

3. So you need to send an e-mail each time a user record is updated from the management UI. Does your domain object send the e-mail, or your DAO? Or your controller? #1 is obviously wrong. #2 is bad too because (1) e-mail has nothing to do with data access, and (2) it would get sent after every user update, even if the user updates their own profile, which is not what the requirement says.

I realize you didn't write the article but it's pure absolute rubbish. It's so hip to rag on Java these days but I yawn every time I see it.
# Posted By Cliff Meyers | 5/13/07 12:11 AM
Ah, and one more priceless quotes from that blog post:

"'How can I tell what the code does without the type information?' This is a good point! Static typing makes code readable, just like training wheels make a bicycle ridable. But eventually you want more than not-falling. You want elegance and speed."

1. Elegance = "You don't understand, man. I want my code to look cool. I don't give a shit if someone else needs to read and maintain it later on. That is so much less important than me feeling like I am cool when I program. Let's go drink some Mountain Dew and go snowboarding!"

2. Speed = "I just wanna knock this shit out ASAP. Quality is for the QA team to worry about. I won't get a compiler error with my cool weak-typing, so I'm good to go. Then some poor sap can spend him time writing tests to see what happens when they pass an integer, String, float, Date, etc to my method. Or they can just find the error at runtime. But hey, that's not my problem! Now where did you say that rave was gonna be on Friday night?"

And certainly he can't be talking about execution speed because Ruby is slow as shit compared to Java. Good times.
# Posted By Cliff Meyers | 5/13/07 12:42 AM
@Mike & Cliff,

Just in case it wasn't obvious from my posting, I also use service classes and find them really useful - for a number of reasons that you both mentioned. I KNOW what is cool about service classes (and good point Cliff about the example Java code - even just using DI to inject the manager simplifies the "straw man" somewhat).

What I was hoping for was someone on the other side of the debate - someone who has written large apps in a dynamic language putting all of the heavy lifting into domain objects to provide some input on how they dealt with the issues we all perceive of non having a service layer for non-trivial apps.

Either Ruby is a case of pure mass hysteria where a large number of otherwise extremely smart people have taken one too many bumps on the head while snowboarding and are now simply incapable of making rational architectural choices and are building big balls of mud that will be seen in hindsight as the biggest screw up in application engineering since a universal computing device was first constructed, or maybe there is something to what they're doing. I'll bet on the latter not because it is more likely to be true, but because if I pretend that everyone else knows more than I do I'm more likely to listen and learn from them. If after listening and learning, I reject their approach as immature or inferior (either in the general case or for my specific use case) I have lost little by learning something useless. I just don't want to bet on me (or my favored approach) being smarter than everyone else because in the long run that is always a fools bet.
# Posted By Peter Bell | 5/13/07 6:18 AM
@Sam,

No, this isn't a matter of having static methods. As you point out, Java supports that and yet is the language where I've seen the most manager/service layer classes. It is a matter of coming up with the right way to separate concerns. If I just want simple CRUD for a dumb object I might get away with putting everything into a User bean, but I find once I have a bunch of smart getters and setters for user properties and a bunch of class style methods my User bean is getting a little cluttered, so I'm thinking about breaking it up. There are a lot of ways I could do this, but it seems very natural to me to break it up based on the separation of concerns between handling collections of objects and providing a remote capable API from the concerns of returning the Age of the user given their date of birth or validating that their first name doesn't exceed 50 characters - both of which I fnd fit well within the bean (using composition for stuff like validation).

To me managers and going back to structs and libraries are quite different. I'm not suggesting a distinction between logic and data but a distinction between an API for handling collections of an object type (class style methods) and operations that primarily relate to a single object (User.getLastName(), User.validate() and so on).

I agree that separation of concerns is absolutely for ourselves not the machines, but I'm not sure that I understand your last paragraph, so I guess I won't respond to it - a clarification will get a response :->
# Posted By Peter Bell | 5/13/07 6:26 AM
Peter,
When you say "but it seems very natural to me to break it up based on the separation of concerns between handling collections of objects and providing a remote capable API," what type of concerns are you talking about putting in the new service class?

Stuff like Mike alluded to when he said, "Doesn't it seem a little more logical to take the cart, along with coupons, etc. to a single register (similar to what you would do in real life)"? I can certainly see how a "Cart" object shouldn't be able to calculate tax and whatnot. But, I think the use (or non-use) of service classes depends on how you are modelling your application. A register may well be more than just part of a service layer, and become a true object.

Maybe I've been using similar things all along and just not calling them services for all I know =).
...

Cliff- A couple of responses if I may. I'm a bit ignorant on the example you provided (the Struts 2 code), but it looks like there is a bit of boilerplate code missing. I agree that the author could have made his point in a better way that using what he called "old school" Struts, but the Rails example he showed is complete. There is no other instantiation or XML to take care of anywhere else (in fact, if you didn't want to, you don't even necesarily have to write the 3 lines he did).

Can you confirm or deny if there is any extra in the Struts 2 example (with Hibernate?) , as I'm not as familiar with it as I probably should be.

And, regarding the elegance and speed- I don't know that I even agree that it is less readable to not have the type information there (at least, I've never run into a problem with it in 6 years of heavily using dynamic languages). Normally, it is clear from the context, plus the initial instantiation of an object still includes type information with the call to instantiate the object - you just don't need to declare it multiple times (type inference could help with this in static languages).

For me, readability and ease of coding are tightly coupled with each other and with elegance. In fact, the clutter of having to cast and declare types in my opinion degrades readability because you are having to sort through the noise to find the useful information - what's actually going on. Therefore, I don't see the disconnect between elegance and readability as you seem to imply in your comment.

As for speed, yes I agree he is talking about speed of development and not speed of execution. But, for many (probably most) applications, Ruby in particular and dynamic languages in general may indeed be slower than Java, but are still fast enough. In those cases, it becomes useless to talk about one being slower or faster than another. It was only a decade ago or so that we were saying Java was too slow, and "I'll stick with C/C++ thank you."

And back to Peter, I'll try to better explain my last paragraph:

We are separating concerns for /ourselves/ (ease of maintenance and such). We may even agree that service classes can be beneficial along those lines in static languages (and/or in general). But if we don't see the same benefits of traditional separation (via service classes) in a dynamic language (maybe we can get it via mixin, since we are still separating the concerns for ourselves in that way), then would/should we continue using service classes? So, maybe the benefit to them disappears in dynamic languages (not saying it does, just exploring the possibility), or there is some other mechanism that better accomplishes the job, where you can't do both and get the same benefit (the mutex comment).

Hope that helps.
# Posted By Sam | 5/13/07 12:00 PM
@Sam, I typically have the following kind of API for a business object. Let's take product as an example:

Service Class:
Product = ProductService.new()
Product = ProductService.getByID()
Product = ProductService.getByProperty()
ProductList = ProductService.getByFIlter()
ProductList - ProductService.getAll()
Status = ProductService.deleteByID()
Status = ProductService.deleteByProperty()
Status = ProductService.deleteByFilter()
Status = ProductService.deleteAll()
Status = ProductService.saveStruct()

Business Class:
Value = Product.get(PropertyName)
Void = Product.set(PropertyName, PropertyValue)
Status = Product.save()
Valid = Product.isValid()
as well as my first(), next() and reset() iterator methods and all of the custom getters and setters.

It isn't everything but probably gives a sense of the kind of separation of concerns between service class/manager class and business object class that I use.

I'll leave the comments to Cliff for him to respond to although I personally agree with your statements regarding type inference in static languages, the readability of dynamic languges even without type information and speed of development vs. runtime performance.

As for your last paragraph, I take pretty good advantage of dynamic language constructs including dynamic typing and mixins, but I personally still find service methods useful as I'd hate to have all of the above methods (plus the bits and pieces I didn't mention) in a single class file. Of course, I could break it out into two files and mix them in using class based mixins, but I just dobn't see a compelling reason to do so as I don't get that much from having a Product singleton that I can call Product = Product.find(filter) to get a transient instance compared to my Product = ProductService.getByFilter(filter) which solves the same problem.

I still think I gotta go read some more Ruby code though - I may well be missing another approach to breaking down my methods into manageably sized class files.
# Posted By Peter Bell | 5/13/07 12:47 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.