views:

379

answers:

6

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?

A: 

Crudely, the "We don't want" section has to go. Either you want it to be right, or you want it to stay as it is. There's no point in not creating a class when you need one. "We have plenty" is a bad excuse.

Indeed, it is bad to expose all the internal classes, but in my experience, creating a class per concept (i.e. a User, an ID, a Database concept...) always helps.

Next to that, isn't a Facade pattern something to solve the existence of loads of BizRules classes, hidden behind one well-organized and clean interface?

xtofl
I don't really understand what you mean. Are you sayiing I *do* want persistence code in my data container?Further, a Facade as you describe would result in a huge 100-method class, potentially, wouldn't it?
davetron5000
A Facade does two things :1. Hide complexity from a client that doesn't want to deal with complexity.2. Create a functional view on a subsystem. Often this view is a subset of what you could do by handing all the internal objects to the client.
QBziZ
+1  A: 

since you're implementing classes and objects, your solution is going to be OO regardless of how you layer things - it just may not be very well-structured depending on your situation/needs! ;-)

as to your specific question, it would in some cases make sense for validateUserName to belong to the User class, since every User would like to have a valid name. Or you can have a validation utility class assuming that other things have names that use the same validation rules. The same goes for email. You could split these into NameValidator and EmailValidator classes, which would be a fine solution if they will be used a lot. You could also still provide a validateUserName function on the User object that just called the utility class method. All of these are valid solutions.

One of the great joys about OOD/OOP is that when the design is right, you know that it is right, because a lot of things just fall out of the model that you can do that you couldn't do before.

In this case I would make NameValidator and EmailValidator classes, because it seems likely that other entities will have names and email addresses in future, but I would provide validateName and validateEmailAddress functions on the User class because that makes for a more convenient interface for the biz objects to use.

the rest of the 'we-don't-want' bullets are correct; they are not only necessary for proper layering, but they are also necessary for a clean OO design.

layering and OO go hand-in-glove based on a separation of concerns between the layers. I think you've got the right idea, but will need some utility classes for common validations as presented

Steven A. Lowe
+1  A: 

Think about how these tasks would be done if there was no computer, and model your system that way.

Simple example... Client fills out a form to request a widget, hands it to an employee, the employee verifies the client's identity, processes the form, obtains a widget, gives the widget and a record of the transaction to the client and keeps a record of the transaction somewhere for the company.

Does the client store their data? No, the employee does. What role is the employee taking when he's storing the client data? Client Records Keeper.

Does the form verify that it was filled out correctly? No, the employee does. What role is the employee taking when he's doing that? Form Processor.

Who gives the client the widget? The employee acting as a Widget Distributor

And so on...

To push this into a JEE implementation...

The Servlet is acting on behalf of the Client, filling out the form (pulling data from the HTTP request and making the appropriate Java object) and passing it to the appropriate employee (EJB), who then does with the form what needs to be done. While processing the request, the EJB might need to pass it along to another EJB that specializes in different tasks, part of which would include accessing/putting information from/to storage (your data layer). The only thing that shouldn't map directly to the analogy should be the specifics on how your objects communicate with each other, and how your data layer communicates with your storage.

Illandril
I think the real problem, is not how to approach designing in an object oriented way, it is how to do design in an object oriented manner and then resolve that against the technical infrastructure of a framework such as JEE.
DanielHonig
A: 

I've had the same thoughts myself.

In the traditional MVC the most important thing is separating the View from the Model and Controller portions. It seems to be a good idea to separate the controller and the model simply because you can end up with bloated model objects:


public class UserModel extends DatabaseModel implements XMLable, CRUDdy, Serializable, Fooable, Barloney, Baznatchy, Wibbling, Validating {
  // member fields
  // getters and setters
  // 100 interface methods
}

Whereas you can have separate controllers (or entire patterns) for many of the interfaces above, and yes, it's rather procedural in nature but I guess that's how things work these days. Alternatively you can realise that some of the interfaces are doing the same thing (CRUDdy - database storage and retrieval, Serializable - the same to a binary format, XMLable, the same to XML) so you should create a single system to handle this, with each potential backend being a separate implementation that the system handles. God, that's really badly written.

Maybe there's something like "co-classes" that let you have separate source files for controller implementation that act as if they're a member of the model class they act on.

As for business rules, they often work on multiple models at the same time, and thus they should be separate.

JeeBee
+2  A: 

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

  1. It seems in a JEE system at some point you have to deal with the plumbing of JEE, 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 JEE 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.
DanielHonig
A: 

I think this is a question about "separation of concerns". You seem to be a long way down the right track with your layered architecture, but maybe you need to do more of the same - i.e. create architectural layers within your JEE layers?

A DataContainer looks a lot like the Data Transfer Objects (DTO) pattern.

A modern OO design has a lot of small classes, each one related to a small number of "friends", e.g. via composition. This might produce a lot more classes and Java boiler-plate than you're really comfortable with, but it should lead to a design that is better layered and easier to unit test and maintain.

(+1 for the question, +1 for the answer about when you know you have the layering right)

richj