dcsimg

Get Naked

According to the principles of object-oriented design, the most important facet of business software development is for programmers and users to collaborate fully on the creation of the project's object model. If both sets of constituents do a good job, the common wisdom dictates, the objects encapsulate the work being performed, the people who per-form it, and the information that's produced. Each object has all of the attributes and behavior it needs to be able to handle its responsibilities -- but no more -- so that its class can be changed quickly when business requirements change.

According to the principles of object-oriented design, the most important facet of business software development is for programmers and users to collaborate fully on the creation of the project’s object model. If both sets of constituents do a good job, the common wisdom dictates, the objects encapsulate the work being performed, the people who per-form it, and the information that’s produced. Each object has all of the attributes and behavior it needs to be able to handle its responsibilities — but no more — so that its class can be changed quickly when business requirements change.

This incredibly lofty development methodology, which has come to be known as agile software development, offers the promise of significant competitive advantage. And according to Java developers Richard Pawson and Robert Matthews, the best way to realize that advantage is to stop hiding business objects behind a custom graphical user interface, a view layer, or some other abstraction. Instead, they say, it’s time to get naked, time to expose business objects directly to users.

To expose those objects, the two programmers proffer Naked Objects, an LGPL Java framework that provides objects directly to users through a generic user interface made up entirely of calls to public constructors and methods of those objects, discovered via reflection. Naked Objects embodies a principle its creators call behavioral completeness, the belief that an object should completely model the behavior of the entity that it was created to represent.

The end result is Java software produced without a minute spent on a user interface: no dialogs, wizards, menu commands, or application-specific components of any kind; no interface designers; no usability studies; and no need to keep a user interface in synch with the underlying business objects.

This radical approach to software design, which usability guru Larry Constantine calls “simplistic, seductive, and perverse,” is an attempt to channel developers into the creation of behaviorally complete objects.




Listing One: The Client class

package org.cadenhead.naked.invoicer;

import org.nakedobjects.object.*;
import org.nakedobjects.object.value.*;
import org.cadenhead.naked.invoicer.*;

public class Client extends AbstractNakedObject {
private final TextString name = new TextString();
private final TextString company = new TextString();
private Location address;

public TextString getName() {
return name;
}

public TextString getCompany() {
return company;
}

public Location getAddress() {
resolve(address);
return address;
}

public void setAddress(Location address) {
this.address = address;
objectChanged();
}

public Title title() {
return company.title();
}

public Job actionNewJob() {
Job job = (Job) createInstance(Job.class);
job.setClient(this);
return job;
}
}

Getting Naked

In a terrific book that’s published in full on the Naked Objects web site (http://www.nakedobjects.org), Pawson and Matthews state that object-oriented programming, the most widely adopted methodology for software design, has become an emperor with no clothes.

“Most people continue to design business systems that separate procedure from data, albeit dressed up in the language and technology of object-orientation,” they write.

This occurs, they say, because several well-intentioned development techniques — including a strong emphasis on business process, use-case-driven design, task-based GUIs, component-based software development, and the Model-View-Controller pattern — discourage the development of behaviorally complete objects (even though each individual technique may be beneficial in other ways). Instead, the Naked Objects framework enforces completeness by requiring that core business objects are exposed to the user.

For example, an invoicing system could have Employee, Client, Location, and Job objects. The source code for Employee, Client, Location, and Job is contained in Listings One through Listing Five.

All user actions are taken by calling instance or class methods of the objects. Need an invoice? Create a new Job object, drag existing Employee and Client objects onto it to associate them with the job, and fill out the payment amount and completion date. The data is immediately persisted through one of the framework’s object stores, such as XML files, serialized Java objects, or a relational database accessed through JDBC.

Objects are manipulated using a standardized user interface. There’s no other code between the object and the user in the framework. The end result is software that can adapt quickly to changing business requirements and empowers its users, according to the developers.

As Pawson and Matthews explain, “The net effect is that business systems designed this way feel more like using a spreadsheet or a drawing program than a conventional transactional system. [Business systems like this] treat the user as a problem solver, not merely as a process follower.”

Naked applications also improve communication between users and developers, because both talk about the application on the same terms.

(In the) Buff Code

The Naked Objects framework consist of more than 340 classes in 24 packages, including org.nakedobjects and org.nakedobjects.object.

A naked object can be created by subclassing the AbstractNakedObject class or implementing the Naked and NakedObject interfaces.

Naked objects hold three kinds of instance variables that subsequently appear in the graphical user interface: naked values, naked objects, and collections of either category. These fields, as they are called, are accessed by get() and set() methods, and can be edited directly by a user.

Naked values are the most basic fields, representing standard objects that handle common data types.

The following naked value classes are available in the org. nakedobjects.object.value package: Date, DateTime, FloatingPointNumber, InternalCollection, Label, Logical, Money, Option, Percentage, TextString, Time, UrlString, and WholeNumber. More can be created by inheriting from their parent class, AbstractNakedValue. Most of these fields mimic Java’s primitive data types, which can’t be used in Naked Objects because Naked values contain behavior that supports their use in the framework.

A naked value is edited directly — TextString fields are text fields, true-false Logical fields are check boxes, and so on.

The following statements create naked values for a Job:


private final TextString name = new TextString();
private final Money fee = new Money();
private final Date creationDate = new Date();
private final Date dueDate = new Date();
private final Logical paid = new
Logical(false);

The Job class represents a job performed by an Employee object for a Client object. Most of these values are required to generate and track an invoice for that job. Another object, Location, holds contact information that can be associated with Employee and Client objects.

The name of a field determines its label when the object is presented by the standard interface. Spaces and capitalization are added for readability — so, fee becomes “Fee,” creationDate becomes “Creation Date,” and so on. Values may be assigned to fields when variables are declared or in the naked object’s default constructor.

In the Job class, the TextString object called name holds a title for the job (such as “Set Up New Domain”). The graphical user interface that supports Naked Objects relies on identifiers like this for the display and retrieval of objects.

Every naked object must contain a title() method that provides a title. Here’s how Job handles it:


public Title title() {
return name.title();
}

The title() method must return an instance of the Title class from the main Naked Objects package. An easy way to accomplish this is to call the title() method of a naked value.

In order for a naked value to be directly editable by a user, it must have a getX() method, where X is the name of the variable with its first letter capitalized. The method must return an object of the correct class. For example:


public Date getCreationDate() {
return creationDate;
}

A naked value also may be derived from other values rather than being edited. Whenever the creationDate field is changed, the dueDate value in the Job class is automatically set to 30 days beyond that date:


public Date deriveDueDate() {
Date dueDate = new Date(creationDate);
dueDate.add(30,0,0);
return dueDate;
}

Here, the add() method supports simple date arithmetic — one of the advantages of using Naked Objects’ own framework-specific data types is their support for this kind of common data manipulation.

Naked values do not require set() methods because the framework automatically takes care of receiving user input for these fields. A naked object also may contain other naked objects as instance variables. For example, the Job class declares two:


private Employee employee;
private Client client;

These references are not assigned an object in the declaration or in a constructor method, because the user must create Employee and Client objects and assign them to a Job object.

A naked object requires a getX() method to retrieve its value and a setX() method if it may be set directly by the user. Two examples:


public Employee getEmployee() {
resolve(employee);
return employee;
}

public void setEmployee(Employee employee) {
this.employee = employee;
objectChanged();
}

As you can see, these methods call the resolve() and objectChanged() methods inherited from Abstract-NakedObject in the manner that all getX() and setX() methods should for fields that hold naked objects.

The resolve() method makes sure that a naked object exists when it is first referenced. The framework only loads objects on an as-needed basis. Calling resolve() with the object as an argument makes sure it is available before being returned by a get() method.

The objectChanged() method indicates that the object’s value has been modified, which causes it to be saved by the persistence method employed by the application.

These two methods enable Job objects to support the most common form of object association in a Naked Objects project: assigning one object to another by right-clicking the object’s icon and dragging it to the field of the receiving object.

Interface a la Nude

The framework’s built-in user interface presents three icons to provide feedback as an object is being dragged over a particular field:

A gray circle indicates that the field does not yet contain an object.

A red circle indicates that the field cannot contain an object of that type.

A green circle indicates that the field can contain that object.

Dropping an object on a green circle assigns that object to that field.

When one object is assigned to another, it’s often necessary for both objects to know about the relationship. This is accomplished by adding associateX() and dissociateX() methods to both objects.

Here’s an example from the Job class:


public void associateEmployee(Employee
employee) {
setEmployee(employee);
employee.getJobs().add(this);
}

public void dissociateEmployee(Employee
employee) {
setEmployee(null);
employee.getJobs().remove(this);
}

When an associateEmployee() method is present, the framework calls it in favor of setEmployee(). Here, the associateEmployee() method calls setEmployee() to assign the employee to the job’s “Employee” field. Next, it uses the add() method — inherited from AbstractNaked-Object — to do the opposite, assigning the job to the employee’s “Job” field.

The dissociateEmployee() method removes a cross-relationship when an object has been removed from a field. Access control is implemented in Naked Objects using methods that indicate how and when a field may accept an object. These methods are discovered via reflection and take the form about X(), where X is the name of the field whose access is being specified.

Because Naked Objects uses reflection to find and present fields, fields are presented in a haphazard order. The fieldOrder() class method may be overridden to specify the top-to-bottom order of fields, as in this method from Job:


public static String fieldOrder() {
return “name, employee, client, fee,
creation date, due date, paid”;
}

fieldOrder() should return a string of field names separated by commas.

The names are the readable version presented on forms without regard to capitalization — creationDate becomes “creation date” or “Creation Date,” for instance.

A field can hold multiple objects as values using the InternalCollection class in the org.nakedobjects. object.collection package. The following statements from the Employee class in Listing Two set up a collection and its getJobs() method:




Listing Two: The Employee class

package org.cadenhead.naked.invoicer;

import org.nakedobjects.object.*;
import org.nakedobjects.object.collection.*;
import org.nakedobjects.object.value.*;
import org.cadenhead.naked.invoicer.*;

public class Employee extends AbstractNakedObject {
private final TextString name = new TextString();
private Location address;
private final InternalCollection jobs = new

InternalCollection(Job.class, this);

public TextString getName() { return name; }

public Location getAddress() {
resolve(address); return address; }

public InternalCollection getJobs() {
return jobs; }

public void associateJobs(Job job) {
job.associateEmployee(this); }

public void dissociateJobs(Job job) {
job.dissociateEmployee(this); }

public void setAddress(Location address) {
this.address = address; objectChanged(); }

public Title title() { return name.title(); }

public Job actionNewJob() {
Job job = (Job) createInstance(Job.class);
job.setEmployee(this);
return job;
}
}

private final InternalCollection jobs = new InternalCollection(Job.class, this);


public InternalCollection getJobs() {
return jobs;
}

The collection’s constructor method takes two arguments: the class being held by the collection, which must be a naked value or naked object class, and the object that holds it. No setJobs() method is needed — it’s automatically supported.

All Naked Action

Behavior is implemented by a naked object through the use of public methods that begin with the word action. The rest of the method name forms a command on the object’s context menu, which appears when a right-click occurs over the object’s icon.

In the Employee class, the following method appears as “New Job” on the context menu:


public Job actionNewJob() {
Job job = (Job) createInstance(Job.class);
job.setEmployee(this);
return job;
}

This method enables an Employee object to create a new job with that employee automatically in the right field upon creation.

When deployed, a Naked Objects application is run by executing the org.nakedobjects.Client class, which looks for a client.properties file that defines the naked objects that comprise the project, its appearance, and the location of the server that provides objects and persists their contents.




Listing Three: The Job class

package org.cadenhead.naked.invoicer;

import org.nakedobjects.object.*;
import org.nakedobjects.object.value.*;
import org.cadenhead.naked.invoicer.*;

public class Job extends AbstractNakedObject {
private final TextString name = new TextString();
private Employee employee;
private Client client;
private final Money fee = new Money();
private final Date creationDate = new Date();
private final Date dueDate = new Date();
private final Logical paid = new Logical(false);

public TextString getName() { return name; }

public Employee getEmployee() { resolve(employee); return employee; }

public void associateEmployee(Employee employee) { setEmployee(employee);
employee.getJobs().add(this); }

public void dissociateEmployee(Employee employee) {
setEmployee(null);
employee.getJobs().remove(this); }

public Client getClient() { resolve(client);
return client; }

public Money getFee() { return fee; }

public Date getCreationDate() { return creationDate; }

public Date deriveDueDate() {
Date dueDate = new Date(creationDate);
dueDate.add(30,0,0); return dueDate; }

public Logical getPaid() { return paid; }

public void setClient(Client client) {
this.client = client; objectChanged(); }

public void setEmployee(Employee employee) {
this.employee = employee; objectChanged(); }

public Title title() { return name.title(); }

public static String fieldOrder() {
return “name, employee, client, fee,
creation date, due date,
paid”;
}

}

For testing purposes, the application may be run by creating a subclass of Exploration in the org.nakedobjects package. The class identifies the project’s naked objects and contains a main() method. An example for the Invoicer project is shown in Listing Five.

Icons for each object are set up externally by placing them in an images subfolder and naming them after each naked object’s class. For each object, create a GIF file in 16×16 and 32×32 pixel sizes, and give them names of the form class16.gif and class32.gif, where class is an object’s class name. For example, the Employee class has icons Employee16.gif and Employee32.gif. (The Naked Objects installation includes an icon-library folder with suitable icons in 16-by-16 and 32-by-32 pixel sizes.) The placement of the images subfolder is relative to the folder from which the application runs.

The org.nakedobjects.Server class is run to support clients, using a server.properties class to specify the particulars of the application. The server and its clients may be on the same computer or separated over an intranet or the Internet.




Listing Four: The Location class

package org.cadenhead.naked.invoicer;

import org.nakedobjects.object.*;
import org.nakedobjects.object.value.*;
import org.cadenhead.naked.invoicer.*;

public class Location extends AbstractNakedObject {
private final TextString name = new TextString();
private final TextString street1 = new TextString();
private final TextString street2 = new TextString();
private final TextString city = new TextString();
private final TextString state = new TextString();
private final TextString zip = new TextString();

public TextString getName() {
return name; }

public TextString getStreet1() {
return street1; }

public TextString getStreet2() {
return street2; }

public TextString getCity() {
return city; }

public TextString getState() { return state; }

public TextString getZip() { return zip; }

public Title title() { return name.title(); }

public static String fieldOrder() {
return “name, street1, street2, city, state, zip”;
}
}

Persistence is supported through an object store that’s specified as one of the properties of the server application. Currently, five persistence mechanisms are supported:

* TRANSIENT. Naked Objects’ org.nakedobjects. object. TransientObjectStore class only saves objects while the application is running and discards them afterwards.

* SERIALIZATION. org.nakedobjects.persistence. file.FileObjectStore stores naked objects by serializing them.

* XML. The org.nakedobjects.persistence.file. XmlObjectStore class saves objects as files using a simple XML dialect.

* SQL. The org.nakedobjects.persistence.sql. SqlObjectStore class uses any JDBC-compliant database to hold naked objects. In many projects, it can set up a database and tables automatically.

* EJB. A Naked Objects developer, Dave Slaughter, has created an object store for Enterprise Java Beans that supports scalability, security, and transactions.

The Serialization and XML object stores are intended for testing and small-scale use only; the SQL and EJB stores are the only ones currently suitable for wide deployment. As new or improved persistence mechanisms become available, they can be implemented simply by changing a line in the server.properties file.

In a Naked Objects application, objects are created by right-clicking an object’s icon and choosing Create from the context menu that appears.

There’s a nettlesome bug in the Linux implementation of the current build (version 1.0.2): if you release the mouse after a right-click, you can’t choose anything on a context menu. As a workaround, right-click and hold down the mouse, then find and left-click a context menu option.




Listing Five: The Run class

package org.cadenhead.naked.invoicer;

import org.nakedobjects.*;
import org.nakedobjects.object.*;

public class Run extends Exploration {
public static void main(String arguments[]){
new Run();
}

public void classSet(NakedClassList classes){
classes.addClass(Employee.class);
classes.addClass(Client.class);
classes.addClass(Location.class);
classes.addClass(Job.class);
}
}

To Naked or Not to Naked

Naked Objects is a hard sell as a complete replacement for a customized user interface. The generic interface is rudimentary even by open source standards, and relies heavily on two cumbersome interactions: drag-and-drop and right-click context menus. It’s also a bit daunting to contemplate a world in which users are comfortable with terms like instantiation and constructor.

However, designing business objects that work instantly in a no-work-required interface has strong appeal. The Naked Objects graphical user interface is surely to get better, and it can be replaced entirely without affecting existing business objects, as one early implementor has already done.

The ability to create objects and immediately use them is an enjoyable and instructive way to develop a Java project. As the Invoicer application was developed, several object interactions were created because the program seemed incomplete without them — such as the job creation method of the Employee object. Working directly with objects suggests ways in which they should interact, and can show where the model is flawed and new objects are necessary.

The framework encourages the development of software in which complex solutions can be achieved by a variety of means. Conversely, it makes it difficult to create software that restricts users to a fixed sequence of limited interactions.

There’s also value in Naked Objects as an incubator for business objects. Once the objects are created and work well, they could be used beneath a Swing interface, Java Server Pages web application, or the like.

The hardest sell of all for the framework will be user interface designers.

In a paper published on his usability web site at http://www.foruse.com, guru Constantine writes, “Programmers love Naked Objects. It proves to them that we are frauds, that all these years we have been flogging issues that are ultimately irrelevant. You do not have to design [a complicated windowing] user interface to suit the users of the work; users will do perfectly fine with a simple user interface that lets them solve their own problems.”

Whether you regard that as a worst- or best-case scenario, Naked Objects is a definite eye-opener.



Rogers Cadenhead is a Web application developer and the coauthor of Teach Yourself Java 2 in 21 Days, Third Edition from Sams Publishing. To contact Cadenhead, visit his weblog at http://www.cadenhead.org/workbench. You can download the code from this column at http://www.linux-mag.com/downloads/2003-10/java.

Comments are closed.