The notion of bahavioral completeness as introduced with the Naked Objects approach comes across as a two-sided coin, at least to me. After taking note of Eitan Suez’ JMatter framework, I started cross-reading the book Naked Objects by Richard Pawson and Robert Mathews that can be found online. The core concept is a strict interpretation of object oriented methodology in a way such that every action that can be taken with a certain object must be defined within the boundaries of that object definition. The object must be behaviorally complete. This philosophy is in sync with the idea, that a software should display the internal model as closely to the user in its GUI as possible, which I agree with.

I have been trying to apply this concept into my daily coding tasks, because I think that good ideas should be useful in multiple contexts and to make things simpler, avoid excess bagage is always a good thing. However, there is a catch. Behavioral completeness, as nice as it sounds, introduces a conflict that I do not really see resolved. Take a classic Customer class that should be persisted via some O/R Mapper into a datastore. Should that class provide a save() method? According to the Naked Object people it should. (Aside: The popular ActiveRecord ORM layer of Rails does provide a save() method in that fashion as well.) From a user point of view that is what I’d want as well. Yet, from a designers point of view I ask myself: Where should I save this Customer to? And why should I design this “knowledge” into the Customer class?

Actually, in the JMatter framework this is accomplished via a superclass called AbstractComplexEObject from which the business object Customer must be inherited. From the JMatter examples, say this one by Eitan Suez, it also becomes obvious that the properties of these classes have to be certain framework classes, like StringEO instead of String. Now, this kind of tight coupling has some red flags waving in my head.

The trouble is that behavior usually not only involves an object and a message or action executed upon it but also an environement, a context in which everything takes place just as well. So, what I’d have done is something like this.

class Customer {
    // Class definition
    public void save( StoreContext context ) {
       context.save( this );
    }
}

The StoreContext class provides a connection to the data store and handles the actual saving of the Customer object. Maybe I also had Customer implement an interface Storable if that is necessary for the StoreContext to do its magic. But I’d never include all the database connection logic and saving of the object within the object itself — and I find it hard to believe that the inventors of Naked Objects were thinking in this direction, even though apparently they do.

I might even consider a Singleton class, say, a StoreContextFactory that produces a StoreContext so that the code changes to this.

class Customer {
    // Class definition
    public void save() {
       StoreContext context = StoreContextFactory.createDefaultContext();
       context.save( this );
    }
}

Yet, all in all I do not like this last solution very much, because it does not seem to be as explicit as the first one and that makes it harder to understand. An unweary developer using the Customer class might not be cautious with save() having no real involvement with what’s going inside that method, namely a costly database transaction. This applies just as well to an object that is behaviorally complete. Plus, we’re not only talking about persistence but about every possible behavior a Customer might exhibit in our application context, which we’d have to implement accordingly. Naturally, there is a framework of some sort necessary to support this, which means that it is hard to impossible to apply the philosophy of Naked Objects without one.

On the other hand, as I mentioned above, I do like the idea of a simple save() method if I picture myself in the shoes of a developer not have anything to do with persistence, because save() is very convenient.

In the end, the questions remains, is my scepticism towards a common superclass for business objects and the usage of a framework that essentially provides a rich environment for these business objects unfounded or not? If all this boils down to a cost-benefit analysis, are the benefits worth it? Or is the price too high? I’d be interested to hear how others interpret behavioral completeness and how to balance this with the idea of modular code.