Search code examples
oopclass-design

OO vs. Layered; balancing "OO purity" with getting things done


I believe in OO, but not to the point where inappropriate designs/implementations should be used just to be "OO Compliant".

So, how to deal with the Serlvet/EJB/DataContainer layered architecture:

  • Servlets receive requests and call a "business layer" (e.g. session EJBs)
  • The business layer locates DataContainers from the database and manipulates them to implement the business logic
  • DataContainers contain no real code, just get/set corresponding to the database.

This approach has appeal; the DataContainers are clear in what they do and it's very easy to know where data comes from.

Aside from not being OO, this leads to unclear Business Layer classes that can be hard to name and hard to organize.

Even if we were trying to be more "OO" (e.g. putting some of these methods in the DataConatiners), some of these operations operate on more than one set of data.

How do you keep your Business Layer from getting confusingly procedural, but without polluting your DataContainers with business logic?

Example

class UserServlet {
  handleRequest() {
    String id = request.get("id");
    String name = request.get("name");
    if (UserBizLayer.updateUserName(id,name))
      response.setStatus(OK);
    else
      response.setStatus(BAD_REQUEST);
  }
}

class UseBizLayer {
    updateUserName(String id, String name) {
        long key = toLong(id);
        user = userDAO.find(key);
        if user == null
            return false;
        if (!validateUserName(name))
            return false;
        user.setName(name);
        userDAO.update(user);
        return true;
    }

    validateUserName(String name) {
        // do some validations and return
    }
}

class User {
    long key;
    String name;
    String email;

    // imagine getters/setters here
}
  • We don't want validateUserName on the user, since it only operates on a name; I guess it could go into another class, but then we have another procedural "uti" type class
  • We don't want persistence methods on the User, since there's value in decoupling data structures from their persistence strategy
  • We don't want business logic in our Servlet, since we may need to re-use that logic elsewhere
  • We don't want our business logic in our User, as this draws in way too much to the User class, making re-use of the business logic difficult and coupling the user with its persistence strategy

I realize this example isn't that bad, but imagine 10 DataContainers and 20 BizLayer objects with several methods each. Imagine that some of those operations aren't "centered" on a particular data container.

How do we keep this from being a procedural mess?


Solution

  • So I'll address my thoughts on this in a few bullet points:

    1. It seems in a Java EE system at some point you have to deal with the plumbing of Java EE, the plumbing doesn't always benefit from OO concepts, but it certainly can with a bit of creativity and work. For example you could might take advantage of things such as AbstractFactory, etc to help commonize as much of this Infrastructure as possible.
    2. Alot of what you are looking into is discussed in Eric Evans excellent book called Domain Driven Design. I highly reccomend you look at it as he does address the problem of expressing the knowledge of the domain and dealing with the technical infrastructure to support it.
    3. Having read and GROKD some of DDD, I would encapsulate my technical infrastructure in repositories. The repositories would all be written to use a strategy for persistence that is based on your session EJBs. You would write a default implementation for that knows how to talk to your session EJBS. To make this work, you would need to add a little bit of convention and specify that convention/contract in your interfaces. The repositories do all of the CRUD and should only do more than that if absolutely needed. If you said "My DAOS are my repositories", then I would agree.
    4. So to continue with this. You need something to encapsulate the unit of work that is expressed in UseBizLayer. At this level I think the nature of it is that you are stuck writing code that is all going to be transaction script. You are creating a seperation of responsibility and state. This is typically how I've seen it done within Java EE systems as a default sort of architecture. But it isn't Object Oriented. I would try to explore the model and see if I could at least try to commonize some of the behaviours that are written into the BizClasses.
    5. Another approach I've used before is to get rid of the BizLayer classes and then proxy the calls from the Domain to the actual Repositories/DAO's doing the operation. However this might require some investment in building infrastructure. But you could do alot with a framework like Spring and using some AOP concept's to make this work well and cut down the amount of custom infrastructure that is needed.