views:

725

answers:

2

I'm building a MVC web application (using the Spring MVC framework), and I'm a little stumped on the best way to design a particular area.

The application has to interact with a series of web services which are not really all that greatly designed, and don't offer much abstraction in and of themselves - basically there is a web service method for each create/update/retrieve/delete operation for each "datatype", and there isn't much of an API beyond that. The web service client needs to know which methods to invoke, and in which order, to be able to create the data it needs to - in other words, there are no "transaction" based methods.

For example, simply to create a new user account requires calling a total of seven different web service methods to set up all of the records in the necessary tables (a user record, adding the correct privileges to that user, setting up the user's billing details, etc).

I'm struggling with the best way to abstract this and encapsulate it within our application. Most of the app follows a standard flow:

request ---> Controller <---> Service/Business-level object <---> DAOs for data access

Within my application, I'm using my own set of "domain objects" to represent and abstract the datatypes defined in the web service WSDL, so that my domain logic is not dependent on the web service types and so that we can abstract and hide whichever details we like.

What I'm looking for some opinions on is the best way to design the "user creation process" I mentioned above as an example. The process to create a "regular user" involves calling seven different web services, as I mentioned, but this is just one "type" of user - we will have to be able to create several different types of users, each of which require different web services to be invoked.

Currently I've only designed this "regular user" creation, as a bit of a proof of concept - I have a domain object User, a UserDao interface which has methods for getUser(name) and createUser(User), and a WebServiceUserDao which implements the UserDao methods and knows how to invoke the above-mentioned seven web service methods. The createUser() method is called by a UserCreationService, which is my business/service-level class, which in turn is invoked by the SignupController.

But to expand this logic in order to be able to create the different user types (which are represented by different values in User.getType(), I'm unsure where to draw the line between the business/service layer class and the DAO. For instance, should I:

  1. Create one UserDao implementation per "user type", so the logic to create each "user type" can be encapsulated in it's own class, and let the UserCreationService decide which UserDao to use? This would correspond to 1 service class : many DAOs.
  2. Should I break the UserDao into smaller pieces, one corresponding to each "record" that needs to be created in the web service / DB, even though my overall application doesn't need to know about each of these individual types? And then have different UserCreationService implementations for the various different "user types"? In other words, this strategy would have a PrivilegesDao, a BillingPlanDao, etc., even though I would have no need for a corresponding Privilege or BillingPlan domain object. This would be many service classes : many DAOs.
  3. Contain all of the logic for which web services need to be called for each "user type" in a single WebServiceUserDao? This would have the drawback of having a very complicated class (and PMD is already complaining about cyclomatic complexity), but all of this logic would be encapsulated in the one class and might lead to less complication when viewed from an overall API perspective.

One goal that I have with this application is to make sure that if we ever have to change the details of the data persistence, that all we need to do is change the DAO implementations - if we have to start interfacing with a different billing system, I don't want any part of the application to change other than at the DAO-level.

Any opinions? What kind of strategies do you use when deciding where to break down "business logic" versus "data access logic" when they seem to overlap?

+2  A: 

What kind of strategies do you use when deciding where to break down "business logic" versus "data access logic" when they seem to overlap?

Maybe you can have three layers instead of two: "one extra level of indirection".

At the top layer, you might have business logic which doesn't know about data-access: this business layer uses classes like User, Account, etc., and maybe some factory methods like User.getAccounts and Account.getOwners.

The bottom layer might be a data-access layer, which is your wrapper around or facade to whatever your data layer is.

Between these two layers, a layer which knows what your business objects are (e.g. User and Account) but not what your business logic is. The middle layer knows your data access layer. The job of your middle layer is to use your data access layer's API to I/O your business objects.

ChrisW
facade, indirection, +1
annakata
A: 

"I'm unsure where to draw the line between the business/service layer class and the DAO."

Aren't we all?

I suggest using an ORM (iBatis, Hibernate, Toplink, etc.). Don't implement your own DAO's.

S.Lott
the problem here is there is a web service layer we are "supposed" to interface with, rather than go around it and access the database directly. Is there any ORM that can handle web services? p.s. I hate web services
matt b
@matt b: Your sketch shows "Business-level object <---> DAOs". Are you saying this sketch is incomplete? Please update the sketch to show the real situation including your web services layer.
S.Lott
The DAOs communicate with the web services. DAO is just a pattern - an object that retrieves another - so it's just as valid for them to connect to a SQL database as it as a web service.
matt b