PDA

View Full Version : Java packaging strategy for well-layered J2EE applications



barryhawkins
Jan 7th, 2005, 10:39 AM
My project team at work has a J2EE application that is a fairly typical Struts/Spring/Hibernate effort. One of our key goals is to maintain a well-layered structure that is intuitive and promotes good practice. The approach to Java packaging is a key factor in keeping a clean setup, but I haven't seen that much discussion about it. So, I figured I would throw ours out there and ask for input/feedback/submission of other samples.

Our application uses a persistence layer, a domain layer, a service layer, and a presentation layer. We are currently working out the service layer/domain layer boundaries through refactoring of some rather large service objects. The packaging scheme is below; I am using a ficticious prefix to avoid any privacy issues:

Java Packaging Scheme
com.acme.application
com.acme.application.action
com.acme.application.dao
com.acme.application.dao.hibernate
com.acme.application.domain
com.acme.application.domain.logic
com.acme.application.forms
com.acme.application.resources
com.acme.application.service
com.acme.application.service.spring

Persistence Layer
dao contains interfaces for DAOs to be implemented, and dao.hibernate contains the Hibernate implementations of the interfaces.

Domain Layer
domain contains the domain objects, also referred to as business objects; just how much business logic is contained in these is an ongoing discussion. Beyond the getters and setters for the required properties, validation may be included in them. domain.logic contains interfaces and implementations of more-complex objects that manage collections and/or hierarchies of domain objects. This is somewhat similar to the structure of the jpetstore sample application, from which we took the idea for this structure.

Service Layer
service contains interfaces for service objects that group and/or manage domain.logic objects within transactional boundaries. service.spring contains the Spring implementations of those objects. This allows for other implementations, such as Pico, if need be (although highly unlikely).

Presentation Layer
As can probably be inferred, action contains Struts Action classes and forms contains Struts Form beans. The action classes operate against the service interfaces to accomplish their work, with the implementation of those interfaces being wired up through Spring.

Our version control system makes it particularly painful to have to rename files and directories, so I am attempting to avoid as much of that as I can. It's one of those things where the tool impedes our willingness to refactor and revise our initial choices; I am sure many folks face that same issue. I would welcome feedback and dialog about packaging, hoping this brief writeup might serve as a catalyst and reference point for discussion.

Regards,

Dan Washusen
Jan 9th, 2005, 11:39 PM
I like the layout perscribed in capter six (page 128) of EJB Design Patters (http://www.theserverside.com/books/wiley/EJBDesignPatterns/) (free PDF available after registration). To provide a brief summary:


presentation (UI Layer)
-------------------
User interface helpers to aid formatting, etc. (e.g. Custom Tags, etc).

application (UI Layer)
-------------------
Use-case UI workflow, syntactic validation, interaction with services.
(e.g. Struts actions and forms).

services
-------------------
Controlling transactions, business/workflow logic (possibly spanning multiple
domain object) spanning, acting as facade. A key distinction here is that
multiple application layers can access the same services layer, such as
a web based front end and a "thick" swing application.

domain
-------------------
The domain layer contains the meat of the business logic. The difference between
this and the services layer is that the domain objects contain logic specific to
themselves and their associated objects. So for example in a Message Board
situation, a Forum object would contain logic the create a Message object
(because you can't create a Message without knowing what Forum it belongs to).

persistence
-------------------
The persistence layer contains all the plumbing logic required to make your
domain model persist in a data store.

Cheers,
Dan

barryhawkins
Jan 10th, 2005, 11:33 AM
Dan,
Thanks for your input on the topic, and thanks also for the link to that free PDF of the book! That section titled "A Quick Refresher on Design Issues and Terminology" is an excellent overview; I am recommending it to my team members right away.

scarface@magma.ca
Aug 10th, 2007, 01:22 PM
Hi there,

I had the same question as you with respect to packaging strategy. I like the proposed structure, but where would you put exceptions using that approach?
What if they are top-level, application exceptions used by classes in different layers?

Your insights would be appreciated.

zarick
Aug 13th, 2007, 06:33 PM
When think about package design, beside the layering issue, I'd aso
consider the dependency within package.

I think simple package per layer approach have a few issue,
1. It doesn't answer modularization by function
2. With sub-package per layer approach, service / dao / bo packages
may be cyclic dependency.

Another problem is, I think, service/repos/BO can altogether think
as one 'domain layer'. They are just different types of beans,
placing it in one package or separate packages are both acceptable (for me).

If placing in one package, the class name may adopt some 'convention'.

For example:
PurchaseOrder
PurchaseOrderDAO
PurchaseOrderService
PurchaseOrderRepository

While I am also adopting the package per layer approach,
I starting think, if I shall move all service/dao/repos/bo into one package.

If we first split the project into functional blocks (useraccount, base, purchaseorder, humanresource, etc). Then the size of one package
would not be really BIG.

Also, it may help to further sep the package by key / public interface
and impl.

Altogether, the packaging can looks like this:
domain/useraccount (domain layer, public interface)
domain/useraccount/support (domain layer impl / non public class)
ui/useraccount (pure UI related class)
domain/base
domain/base/support
ui/base
domain/purchaseorder
domain/purchaseorder/support
ui/purchaseorder


What do you think about this?

karldmoore
Aug 14th, 2007, 06:58 AM
If in doubt why not look at the way well written software is structured? e.g. Spring and the examples that come with it.

bdavisx
Aug 16th, 2007, 01:16 PM
When think about package design, beside the layering issue, I'd aso
consider the dependency within package.

I think simple package per layer approach have a few issue,
1. It doesn't answer modularization by function
2. With sub-package per layer approach, service / dao / bo packages
may be cyclic dependency.

Another problem is, I think, service/repos/BO can altogether think
as one 'domain layer'. They are just different types of beans,
placing it in one package or separate packages are both acceptable (for me).

If placing in one package, the class name may adopt some 'convention'.

For example:
PurchaseOrder
PurchaseOrderDAO
PurchaseOrderService
PurchaseOrderRepository

While I am also adopting the package per layer approach,
I starting think, if I shall move all service/dao/repos/bo into one package.

If we first split the project into functional blocks (useraccount, base, purchaseorder, humanresource, etc). Then the size of one package
would not be really BIG.

Also, it may help to further sep the package by key / public interface
and impl.

Altogether, the packaging can looks like this:
domain/useraccount (domain layer, public interface)
domain/useraccount/support (domain layer impl / non public class)
ui/useraccount (pure UI related class)
domain/base
domain/base/support
ui/base
domain/purchaseorder
domain/purchaseorder/support
ui/purchaseorder


What do you think about this?

I agree with this way of doing things. It keeps classes that only depend on each other in the same packages.

Can you elaborate on your reasons for the support package?

zarick
Aug 18th, 2007, 02:22 AM
I agree with this way of doing things. It keeps classes that only depend on each other in the same packages.

Can you elaborate on your reasons for the support package?

Say, for the module "base", "base.support" can contains implementation class of the interfaces defined in "base", as well as some other classes used internally.

With this arrangement, client of "base" module will only depends on the interface / classes exposed by the "base" module, but not "base.support".

With this approach, module implementation class deps on the public interface of the module (base.support => base). Other modules will depends on the public interface only (purchaseorder => base).

BTW, I admitted that, "support" may not be a good name for this purpose.

To be frank, I am not very sure if this approach works, I'll try to adopt this plan on the next project.