One big Service class or several small classes?
I asked this question on the Spring Forums a couple of days ago, but I didn't get a response, so I'll try it here.
Looking through the Spring's petclinic and jpestore applications - both seem to advocate one single class to interface with the database (hibernate or dao/ibatis). I also noticed this pattern in Java Open Source Programming. Is this a recommended pattern or do you still think there's value in several service-level classes (i.e. one for each DAO)? I imagine the single interface and impl could grow quite large on a big project. In fact, in the Spring examples, the Manager isn't even a Business Delegate, it's really a Persistence Manager.
BTW, the Petclinic app is a helluva plug for Hibernate. The Hibernate implementation class is 53 lines, and the JDBC implementation class is 770 lines! If you're still using JDBC over Hibernate, please explain why you put yourself through the pain?
I do like the simplicity of the Single Manager approach, but I tend to do 1 Manager for each DAO (or something resembling this pattern). What do you advocate? AppFuse follows the 1-Manager to 1-DAO pattern. Should I switch to the Single Manager pattern?
Posted by Sam Newman on February 02, 2004 at 05:46 PM MST #
Posted by Rob Kischuk on February 02, 2004 at 06:12 PM MST #
Posted by B. K. Oxley (binkley) on February 02, 2004 at 07:18 PM MST #
Posted by Jaap on February 02, 2004 at 08:34 PM MST #
Posted by Jaap on February 02, 2004 at 08:45 PM MST #
Solution 1: A news service and an articles service where each service provides support for comments, e.g. each service might have something like addComment(...). The drawback of this solution is that code duplication is required though it might be prevented by using inheritance.
Solution 2: A news service, an articles service and a comments service. This approach seems to follow the composition idea and allows other entities to be commentable as well (for example comments service might have a method like addComment(String id...)). The question is if news service and articles service should use comments service directly or should the consumer of the services ask the comments service for comments of a given entity? Furthermore this solution requires more SQL selects.
All in all I think the main problem is that SQL isn't object oriented. Though you have tables which could be seen as classes joins of two or more tables produce new types (or combinations). Even a select <column> from <table> produces a new type.
Posted by WoEyE on February 03, 2004 at 01:18 PM MST #
Posted by Sam Newman on February 03, 2004 at 01:26 PM MST #
Sam,
WoEye's use-case still represents an interesting example. I wonder how you would approach this using a use-case driven service-layer. I have a similar example, with BlogEntry and Album entities that both can have a one-to-many relation with Picture. Currently, both the BlogEntry and the Album hibernate mappings know how to fetch their respective Picture-collections. Difficult to separate this into a separate PictureService, but perhaps in such cases code-duplication is wiser?
Posted by Jaap on February 03, 2004 at 02:45 PM MST #
Another point I want to bring up is the question whether a join for result lists returned by Hibernate should be considered as a class? Nowadays I tend to handle them as maps and not as classes for there are typically read-only (or should I say display-only). And of course it gets quickly very time consuming to write classes for each join combination :-)
Posted by WoEyE on February 03, 2004 at 04:37 PM MST #
Posted by Juergen Hoeller on February 03, 2004 at 05:10 PM MST #
Something everyone has overlooked is the possibility of automatically generating much of the service layer via XDoclet or a similiar tool. All of my persistable classes implement the empty AutogenerateDAO interface. This tags them so an XDoclet task will create a DAO & hibernate implementation with the standard CRUD functionality. I haven't needed additional functionality yet, but there are hooks for it in the standard XDoclet inclusion mechanism.
The only remaining piece is a common base class for the Hibernate implementation, allowing the XDoclet-generated implementation to be very thin.
This gives me the benefits of a 1 class - 1 DAO design but in practice I only need to maintain two files - the base Hibernate implementation and the XDoclet template. I can add a new method to all DAOs by changing a single template file, or change the persistence layer from Hibernate to something else by providing a new base class and making suitable changes to the template file.
Posted by Bear Giles on February 03, 2004 at 05:37 PM MST #
The problem is that developers might use these sample apps to develop their own apps - borrowing the patterns, copying code, etc. I know that I've done this and continue to do it when I see patterns I like. Maybe there just needs to be more visibility in the documentation saying <strong>a single business facade works great in small applications, larger applications may require several</strong>.
Thanks to everyone for the feedback - good stuff.
Posted by Matt Raible on February 03, 2004 at 06:43 PM MST #
JPetStore was a simple app that needed just one simple service. Most business applications will require a number of these. It's a good idea to spend some time thinking about these services and how they relate to each other (in terms of the business) and to the horizontal layers as well (in terms of the architecture). I'm also a fan of separating "nouns" from "verbs", and therefore in JPetStore you'll notice that I have a separate group of domain objects that the service layer will act upon. This is a much more scalable architecture and can easily be ported to Session EJBs at a later time if you want to (services Business Deligate pattern, domain objects become DTOs).
If you're application generally ends up being 5 layers and 10 vertical partitions that line up perfectly like a grid (one action, to one domain object, to one service, to one DAO to one database table...etc.), then the solution is probably over-architected. Services and domain objects should partition logically to the business, which does not always (rarely) matches up to the database(s). Similarly, the user intercace is often some bastardization of the domain model and business process such that even it doesn't line up to the services well. The point of layering is that none of this misalignment is a problem. The layers deal with the misalignment. If you're not misaligned, then too many layers just becomes extra work. Beware if you groan every time you need to code "yet another layer", or if you're thinking: "Man, I should just generate this here service layer!" If this sounds familiar, you might not need to layer as much as you are. There is a such thing as overdoing it <GASP!>. :-)
Cheers,
Clinton
Posted by Unknown on February 04, 2004 at 06:30 AM MST #
Posted by anonymous too on February 04, 2004 at 11:12 AM MST #
Posted by Clinton Begin on February 04, 2004 at 03:07 PM MST #
save(), update() saveOrUpdate(), load(), delete() etc.
Most of my DAOs just provide useful queries: findEntityByName(String name) etc.
And as an aside, thank the lord for the Spring framework. Never before has programming been SO simple.
Posted by Ian Blizard on February 06, 2004 at 04:59 PM MST #
Posted by Bhupesh Arya on March 01, 2004 at 08:57 AM MST #
I think I agree with Clinton. Layers should be not aligned. Make a service layer use more than one data layer. And I think, an interface should define what exceptions it may throw. Because the layer that consume the lower layer, will have no idea what kind of implementatation currently used.
But then when we still care about compatibilty with jdbc data layer (not only ORM data layer compatible), we should create service implementation that treat all dao as jdbc dao. I mean, we should not leverage data graph (student.getFather().getName() in ORM since jdbc implementation can't do it and service implementations do not care about data layer implementation.
Posted by Muhammad Ichsan on June 22, 2006 at 09:59 AM MDT #
Posted by Sudhir Nimavat on January 12, 2007 at 11:11 AM MST #