Paul

Monday Oct 15, 2007

Flattening the Web App Stack.

Last week I read an article by Allen Holub called "Why getter and setter methods are evil" (http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html) It basically states that by creating getters and setters in objects you are exposing the inner workings (aka fields and types) to the outside world. It also allows users to dig several levels deep in a tree of objects to get data they're after. He suggests that for example, instead of having a getX, getY, and getZ methods on a class and then having a separate class that calls those to build and render some kind of widget. The object oriented way of doing this would be having a render() method on an object that allows it to render itself.

I started to think about the above philosophy and realized that often the web applications I have seen consist of a group of objects for each domain object. A Person object has a PersonDAO, a PersonService, a PersonController, a PersonValidator, and possibly several other helper classes. Generally a framework like Spring is used to build an application that consists of a "stack" of these such classes that basically pass an object (Person in my example) up and down modifying/accessing it at each level by way of the getter/setter methods. The problem I have with this is twofold. Firstly, the inner structure of the class (it's fields and the types of those fields) are exposed to all of these classes making them hard to change. Secondly, a bunch of extra Java code or XML is needed to wire all this stuff up. This creates the need for getters and setters in all the Service layer classes to set the DAO, Controller classes to set the Manager/Validator, etc.

I decided to start rethinking this standard way of structuring a web app as a bit of a thought experiment over the weekend in an effort to reduce the code/configuration required and hopefully simplify the structure.

The goal:

What I wanted in the end was what appears to be a domain object that implements several methods to do various tasks. Continuing my Person example. A Person should have the following methods: save(), delete(), loadFromDb(Long id), isValid(), getValidationErrors(), loadFromForm(HTTPServletRequest request), renderToHTMLForm(), renderToHTMLDetails(), etc.

I wanted the Person class to "appear" to have these methods. I didn't want to simply dump all the methods from the old stack into one huge class. My first answer to this was to have the person class hold a reference to a DAO, a Service, a FormReader, etc and delegate all calls to methods in those objects.

This type of delegator pattern works well except that the classes being delegated to need to have read/write access to the Person object's fields. I didn't want to simply create getters and setters because I don't want to give code outside these classes the ability to arbitrarily read and write fields in a Person.

My first answer to this was to move the fields in Person outside into their own class and create getters and setters. (a normal POJO) This a reference to this object would be held in Person and passed to the DAO, Validator, Renderer, Reader, etc. when Person delegates calls to them. This allows them to all read/modify the needed information. It is important to note that Person does not have a getter/setter for this object. Other code can not see it.

I didn't like the above approach. It seems too much like the old method and is just more complicated (extra delegation) without much benefit. What I really wanted to do was get rid of this extra class (i called mine PersonBean) and move the fields back into Person and get rid of the getters/setters in the process. After thinking about this for a bit I started to wonder if I could leverage the access level of "protected" for my variable names to prevent outside objects from accessing them. This would require that my helper classes (DAO, Validator, etc) be subclasses of Person. This really doesn't make much logical sense in a traditional design of an application but just bare with me on this. This allows access to the fields i need, but each subclass will have their own copies. They need to share the same data.

It turns out that in Java protected and private access are not restricted by the caller and target being the same instance but just the same class/subclass. It also turns out the protected allows access to subclasses from superclasses not just superclass methods/fields from a subclass.

What this means is that the following code works:

public class Person{
    protected String name;
    protected String id;

    protected PersonValidator validator; //still creating a validator child object

    public boolean isValid() {
        return validator.isValid(this); //still delegating to it.
    }
}

public class PersonValidator extends Person {
    protected PersonValidator(){} //i'm making the constructor protected to prevent  
                                  //code from randomly making instances of this and 
                                  //passing Person objects to it. I want to force 
                                  //the use of Person.isValid();

    protected isValid(Person p){               //notice here that i have access to 
        return(p.id != null && p.name != null  //the protected fields in p even tho
               && p.name.length() > 0);        // this != p 
    }
}
The above strategy basicly uses inheritance backwards to the normal use. This use, while working, causes three problems.

1. my PersonValidator can not extend anything other than Person so I can't utilize utility behavior common to all Validators (probably most useful in a DAO for example). static imports might help with this problem.

2. in the above example there is a reason why the protecte PersonValidator validator line does not finish with = new PersonValidator(). Doing so would cause an infinate loop creating objects as each PersonValidaoor creates an instance of Person and therefor another instance of PersonValidator. I have found three solutiosn for this prolem. A) create an init() method that gets called on person to set this stuff. (i don't like init methods). B) Make the validator field static (fine as long as the validator doesn't need to hold state). C) Create the instance in the constructor for Person. This code needs to be wrapped in an if statement that will determine if this object is being created as a response to a new Person or the VM calling it as a result of creating an instance of a subclass. the code (this.getClass().equals(Person.class)) will evaluate to true only if a new Person is being created.

3. The above example is just plain sloppy/complicated/somewhat ridged.

Conclusion:

I have not yet given up hope and have found some very unconventional ways of using inheritance. Feel free to post or send me any comments/criticisms.

Comments:

Why not just put your validator in the same package? This will have the same effect. You could even tighten the scope of the member variables to default.
Then, you could create a Validator interface with some templated methods or something along those lines.

Posted by JK on November 27, 2007 at 03:25 PM CST #

Post a Comment:
  • HTML Syntax: NOT allowed

Calendar

Feeds

Search

Links

Navigation

Referrers