Wednesday, April 13, 2005

Layered Architecture design

Taken from http://www.hibernate.org/124.html
Just to expand on the architecture I chose (and have briefly and disjunctly discussed on the forum). Let me first suggest a great book on this subject, written by Martin Fowler, entitled "Patterns of Enterprise Application Architecture". It is extremely insightful, helpful and well written.

It seems that most of the discussion that I have seen on the forums regarding this topic relate to whether the objects mapped in Hibernate should be returned as-is to the clients, or whether some form of abstraction should be used to represent that data (whether XML, DTO, Commands, etc). To me, each approach has pros and cons. In my architecture, I chose the latter using DTOs as the communication medium with the presentation. In brief, my architecture is as follows:

1. At the bottom tier is a very strong domain layer (mapped using Hibernate). By very strong, I mean that it bundles all the data elements mapped from Hibernate along with a lot of domain logic (see the section discussing business logic vs domain logic in the chapter on the "service layer" pattern in Fowler's book)...
2. A set of DAOs with static methods for various methods of locating domain objects using HQL or session.load()
3. A service layer, implemented as session beans for no other reason than for the transaction support as I have to coordinate transactions across JMS, LDAP as well as the DB. This could easily be non-ejb also, possibly using aspects to acheive transaction "cross-cuts".
4. a set of "assemblers" (again, see Fowler) which are responsible for "molding" domain objects into DTOs and "swizzling" DTO data back into domain objects.
5. a slew of DTOs which carry data to and from the clients of the service layer.

To me, there are a couple of pros to this type of approach. Number one would have to be the fact that it completely decouples the client from anything that happens behind the service layer, and vice versa. Part of this is not having to worry about things like whether lazy relationships have been loaded when adding a new column to a search result table. Another advantage is that is gives your app a much more defined API feel. The methods exposed on the service layer are the functionality provided by the system to the outside world. And because a lot of the "nitty-gritty" code is hidden away in the DAOs and the assemblers, the service code is very clean. An example would be:

public ContactDTO loadContact( Long contactId )
throws my.PersistenceException
{
prepareCall();
try
{
return ContactAssembler.buildDTO( ContactDAO.load( contactId ) );
}
catch( Exception e )
{
throw new my.PersistenceException( "Unable to load contact", e );
}
finally
{
endCall();
}
}

The cons mainly deal with the fact that that's a lot of extra classes to code. At a minimum, in a small app, you can assume about a one-to-one correspondence between the domain objects in your app and their various DTO representations; this may be even bigger for larger apps. Why? Mainly it has to do with relationships and avoiding infinite loops. Consider a ContactDTO with a relationship to a CompanyDTO, which in turn has a collection relation to its employees which are ContactDTOs. This is normally handled by having different DTO representations of data with different "loading levels" (similiar to the Lightweight pattern discussed on the Hibernate patterns page). Thus, you now would have something like ContactDTO -> CompanyDTO -> ContactListDTO. And thats not even considering specialty DTOs like report DTOs, etc. Its hopefully pretty easy to see how this can become a lot of extra classes. Luckily, all these DTOs are pretty brainless to create as they are generally very simple Java Beans.