Announcement Announcement Module
Collapse
No announcement yet.
Java packaging strategy for well-layered J2EE applications Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Java packaging strategy for well-layered J2EE applications

    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,

  • #2
    I like the layout perscribed in capter six (page 128) of EJB Design Patters (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

    Comment


    • #3
      Thanks to Dan W.

      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.

      Comment


      • #4
        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.

        Comment


        • #5
          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?

          Comment


          • #6
            If in doubt why not look at the way well written software is structured? e.g. Spring and the examples that come with it.
            Last edited by karldmoore; Aug 27th, 2007, 03:27 PM.

            Comment


            • #7
              Packages by functionality

              Originally posted by zarick View Post
              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?

              Comment


              • #8
                Originally posted by bdavisx View Post
                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.

                Comment

                Working...
                X