views:

1901

answers:

3

I've inherited a large Java app that uses Struts, Spring, and Hibernate. The classes and interfaces I deal with daily are: Struts Actions, Struts ActionForms, Value Objects, Service Interfaces and Implementations, DAO Interfaces and Implementations, and Entities. I'm pretty clear on the how and why of most of these, except I'm unsure about the correct separation of responsibilities between the ActionForms, Value Objects, and Entities. I should also mention that the Domain Model (i.e. all of the entities) doesn't contain much (if any) real business logic. This is essentially a CRUD app and most of the real logic is in the database (yuck!). Anyway, there are several distinct Java related issues that I'm wondering about:

1) It seems there is not much difference between the Entities and the Value Objects (VOs), and a lot of code must be written to transform on into the other when they pass through the service layer in either direction (Struts Actions deal only with VOs, DAOs deal only with Entities). So, VOs and Entities seem somewhat redundant. Why have them both?

2) Where should the VO<->Entity translation code go? The service layer, the Entity, the VO?

3) VOs are placed directly into ActionForms and directly bound to tags in the JSP (e.g. ). Is this a good practice? If not, what's the appropriate design?

4) It is unclear how to properly handle foreign key dependencies in the Value Objects. For example, certain VOs have a type field that, in database terms, represent a foreign key relationship into a type table. In the UI, this translates into a dropdown field that lets the user pick the type, OR a label that simply displays the textual representation of the type (depending on which screen it is). Now, should the VO have a property for the type ID, the textual representation of the type, or both? Who is responsible for translating between the two, and when?

5) The VOs have a field for their database ID. I thought VOs don't have identities? What's up with this?

I hope these questions are generic enough to be of general interest. It seems this would come up all the time in this type of architecture.

Also, I have the suspicion that this architecture is way to heavy for this app, and if you have suggestions about a better one, go ahead. But I'm mainly interested in the answer to the above questions since a different architecture is a long-term refactoring that I can't do right now.

+1  A: 

1) No need for separate VO and Entities : some companies mandate such a structure for their project. It might have made sense in a different project and hence it was mandated (I can only guess)

2) Service layer : it is the natural separation from DAO and Action layer, right ?

3) It does NOT hurt however value Objects are bound as long as they are properly validated before sent to DAOs

4) The service layer should be responsible for translating between the two. During load and save time

5) if they don't have identities, then how would you prevent duplication ?

I hope these terse answers helped. I'll try and get back and give a longer answer later.

anjanb
A: 

To answer your last part, use Spring MVC instead of Struts. Then you can just use the same Domain Objects at all layers - the Classes that bind to form parameters are also used in Hibernate, and contain real business logic.

For example, in an app I did using Spring MVC, I had a member class. The login, registration, change password, and edit profile forms all were bound to this class. The class also had a hibernate mapping and a good bit of business logic inside (for example, for a social network an "add friend" method).

bpapa
In a large project, you can't just switch from Struts to Spring MVC. That's a MAJOR refactoring. I pretty much need to make small incremental changes.
thvo
+2  A: 

1. Considering the DAO - VO transformation; whether this is usefull depends on how Hibernate is used. If the entire Web request handling is in a single Hibernate session you should not really need separate VO's.

If, however, your DAO layer opens a session to retrieve an object and closes the session before you are finished using the DAO you may get trouble with collections and references to other objects. There is a fair chance that those are lazily loaded, meaning that the Session must still be opened when requesting those properties.

In short, before you start ditching those VO's have a good, hard look at you database transaction and session boundaries.

3. As for using a VO in a Form; if the VO maps nicely to the JSP I would say why not? I'm either impressed that the data model so closely matches the process it supports, and a bit suspicious that the database has not been normalized (which may or may not pose problems in the future).

Going back to 1. If you use DAO's with lazy loading and collections, remember that the database session must also include the JSP phase as the DAO will be read in that phase.

  1. The service layer must have a facility to know which database objects to alter, and the id is designed to do just that. The service layer will have to retrieve the DAO from the database and write the fields from the VO in the DAO, though it obviously does not need to update the id of the DAO with the id of the VO :)

  2. What you need from the request is the id of the foreign key field. As it comes from the client you should probably check in the business logic whether an object with such an id exists.

Depending on whether the VO accepts the id of the foreign object or requires an object you should then either:

  • set the id, or
  • get the foreign object as a VO by id using the service layer and put it in your VO, and store it using the service layer

Your business layer is responsible for translations as the service layer only deals with object retrieval and storage. And either the text or the id are not objects but identifiers of the objects. The service layer may offer search facilities, but it should not need context information.

And if I read your question right your VOs refer to other objects in the database by id. In that case you enter the id. If you get a String from the client you should look it up in the business layer (using the service layer) and put the id of the found object in the VO. Or, if no ID is found, return a decent error message.

As a closing note; don't touch the DAO-VO thing unless you know what you're doing REALLY WELL. Hibernate is a powerfull and complex tool which is deceptively easy to use. You can very easily make mistakes and they can be very hard to find. And customers and bosses alike don't seem to appreciate the introduction of bugs in stuff that used to work.

By the way; my conservatism in the DAO-VO thing come from fixing problems due to similar problems in EJB2 to Hibernate transitions. The devil is in the details, and changing how you deal with the data layer is a major refactoring even if it looks like a piece of cake.

extraneon
Nice answer, thanks!
thvo