Friday, September 17, 2004

decoupling in session facade

Some J2EE architectures involve session facade design pattern, as a way to hide the implementation from the client and as a way to minimize network roundtrips (if the session has a remote interface). Most of these architectures have either an Entity Bean, a POJO, or another Session Bean, depending on the needs & the requirements.

Most developers still get the facade concept incorrectly. Sometimes, there's hardly any difference between the reponsibilities of the session facade and the responsibilities of the underlying classes. Sometimes, both layers implement the business rules and access the DB at the same time. This may lead to a bad situation where less and less code can be reused.

Here's my opinion on the facade concept. I'm trying to decouple the DB access layer from the business rules layer as best as possible. For example, I've always tried to put the business rules in the facade, and leave the DB access to the underlying layer, may it be an Entity Bean, a POJO or another Session Beans. This would help me a lot in terms of reusability and ease me up a bit on portability.

I get to reuse the same DB access method for multiple business rules. I get the chance to refactor these common methods to be as generic as possible while still keeping the performance in check. I also get a better chance at DB access layer switching, e.g. from Session Bean (DAO) to Entity Bean or from TopLink to Hibernate, etc. Only my DB access layer needs to be modified, where my business rules layer should be less impacted by such switch.

A sample facade would be like the following:

public void deleteUser (String stUserID,
    String stLoginUserID)
throws Exception {
  // verify that all arguments are valid
  // ...

  if (stUserID.equals(stLoginUserID)) {
    // cannot delete him/herself
    throw new Exception ("...");

  // delegate the process to underlying layer
  List roles = listUserRoles (stUserID);

  for (Iterator it = roles.iterator();
    it.hasNext(); ) {
    RoleVO role = (RoleVO);
    String roleName = role.getName();
    if (roleName.equals("SUPERVISOR")) {

      // delegate the process to underlying layer
      reassignMembers (stUserID);

    } else if (roleName.equals("MEMBER")) {

      // delegate the process to underlying layer
      reassignTasks (stUserID);

    } else if (roleName.equals("ADMIN")) {

      // admin users cannot be deleted,
      // they must be demoted first
      throw new Exception ("...");

  // delegates the process to underlying layer
  invalidateUser (stUserID);

As the example above shows, DB accesses to different tables in the DB is being delegated to the underlying layer, i.e. listUserRoles (String), reassignMembers (String), reassignTasks (String), and invalidateUser (String). On the other hand, the business rules, i.e. validation for self-removal, validation for admin role, and additional steps to be performed when the user is a supervisor/member, before actually invalidating the user, will stay in the facade.

This decoupling will improve readability, reusability, and at the same time will minimize the ripple effects should the underlying DB schema is changed, or the business rule is slightly modified.

I know sometimes it's hard to get the discipline..
But in the end, I think it's worth the efforts.. :D

No comments:

Post a Comment