On the folly of representing a first name with a String
Object-Oriented decomposition is supposed to be different
When I read Object Thinking, I was intrigued by this quote by Grady Booch:
Let there be no doubt that object-oriented design is fundamentally different from traditional structured design approaches: it requires a different way of thinking about decomposition, and it produces software architectures that are largely outside the realm of the structured design culture.
So it seems that OOD decomposes a problem in a way that is essentially different from what you would arrive at with other design methods. I was intrigued: I wonder what are these different, elusive ways of decomposing things.
One important hint came from reading this highly recommended paper by Alan Kay, also quoted by Carlo Pescio in a very interesting post:
“The basic principle of recursive design is to make the parts have the same power as the whole.” For the first time I thought of the whole as the entire computer and wondered why anyone would want to divide it up into weaker things called data structures and procedures. Why not divide it up into little computers, as time sharing was starting to? But not in dozens. Why not thousands of them, each simulating a useful structure?
So one main idea is to recurse. When you break up a system in data structures and procedures, what you get are pieces that are less powerful than the whole. A data structure has no behaviour, a procedure has no state. Computers have both state and behaviour, and so do objects. Let’s see how this idea applies to a common programming task: a web-based registration form.
Tedium and repetition
Suppose we must implement a registration form, with the usual abundance of of data: first name, last name, email, username, password, etc. The common way to do this in Java is more or less along these lines:
<form>
<label for="firstName">First Name</label>
<input id="firstName" name="firstName" value="${firstName}" />
<label for="lastName">Last Name</label>
<input id="lastName" name="lastName" value="${lastName}" />
<label for="email">Email</label>
<input id="email" name="email" value="${email}" />
<!-- and so on and so forth for 100 other fields -->
</form>
class RegistrationRequest {
private String firstName;
private String lastName;
private String email;
// and so on and so forth ...
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
// and so on and so forth ...
public ErrorList validate() {
ErrorList errors = new ErrorList();
if (isEmpty(firstName)) {
errors.add("First Name is required");
}
if (isEmpty(lastName)) {
errors.add("Last Name is required");
}
// and so on and so forth ....
return errors;
}
}
class RegistrationRequestController {
public void handleRequest(
HttpServletRequest request, HttpServletRequest response
) {
RegistrationRequest rr = new RegistrationRequest();
rr.setFirstName(request.getParameter("firstName"));
rr.setLastName(request.getParameter("lastName"));
rr.setEmail(request.getParameter("email"));
// etc etc ...
if (rr.isEmpty()) {
registrationDao.save(rr);
response.redirectTo(THANKYOU_PAGE);
} else {
registrationView.setErrors(errors);
response.getWriter().write(registrationView.toHtml());
}
}
}
class RegistrationDao {
public void save(RegistrationRequest rr) {
String sql = "insert into registration_requests" +
" (firstName, lastName, email, ...) " + // etc.
" values (?,?,?,....)"; // etc.
PreparedStatement statement = connection.prepareStatement(sql);
statement.setObject(1, rr.getFirstName());
statement.setObject(2, rr.getLastName());
// ... arrrgh!
statement.execute();
}
}
And so on and so forth. The list of the attributes: firstName, lastName, email… is repeated dozens of times in the source code. Talk about “remove duplication”! Rails has an approach to solve this problem. Rails’ ActiveRecord objects turn down the number of repetitions considerably, but not in a completely satisfactory way. Hibernate removes some of this tedium, but not all of it and definitely not in a satisfactory way. At least for me.
So is there a way to code this very simple and very common scenario without killing your soul with the tedium of repeating the same list of attributes over and over? Is there a programming technique that can save us without having to resort to the mysterious and treacherous magicks of Rails, Spring or Hibernate?
I hinted at such a way in my CodeMotion presentation in 2011. One simple way to get started is to stop treating the RegistrationRequest attributes as code and just let them be what they are: data. If we substitute the RegistrationRequest class with a simple HashMap we can remove many of the repetitions. When I showed slide 22 to the audience, they were surprised :-) Noted blogger and DDD authority Alberto Brandolini was so surprised that he tweeted about it. Many would say that this is a dirty trick, or the mark of an inexperienced programmer. But a Rails’ ActiveRecord object is not too dissimilar to a Map. In fact the heart of a Rails’ ActiveRecord object is a Hash of attributes. Using Maps this way is natural for people coming from PHP programming, like me and like David Heinemeier Hansson.
More inspiration
The HashMap kinda works, but even I admit it’s not the most elegant solution. The next flash of inspiration came from the Object Thinking book, where he presents the example of a mortgage application form. The form, he says, is a collection of data items.
Another flash of insight from Object Thinking: holding information is a responsibility. We budding OO programmers are constantly being warned against the anemic domain model. “Don’t confuse a data structure with an object! Stay away from objects without behaviour!” But Object Thinking says that some objects have as their primary responsibility the one of holding information. This is liberating :-) There are more responsibilities that are closely related with the one of holding information: presenting and validating the information. Now this is an interesting set of responsibilities.
If the application as a whole has a user interface, behaviour and persistence, then the principle of recursive design should imply that most objects should also have user interfaces, behaviour and persistence. Persistence itself is a kind of user interface, where the user is a database. So the registration form should have a user interface, behaviour and persistence. And since the registration form is essentially a collection of data items, its user interface should be composed of the user interfaces of its data items; the form’s behaviour should be a composition of the behaviours of its data items.
All this leads to the conclusion that storing a first name in a String is folly. A String cannot defend itself! It cannot encapsulate its state, it cannot validate itself, it cannot persist itself. Suppose we rewrote the RegistrationRequest like this:
class RegistrationRequest extends CompositeDataItem {
private PrimaryKeyDataItem requestId =
new PrimaryKeyDataItem("requestId");
private StringDataItem firstName =
new StringDataItem("First Name", "firstName");
private StringDataItem lastName =
new StringDataItem("Last Name", "lastName");
private StringDataItem email =
new StringDataItem("Email", "email") {{
add(new EmailValidationRule());
}}
// ...
}
Now this list of data items could be the one and only representation in the system of the list of attributes of the RegistrationRequest. A lot of duplication disappears. For instance, how do we load the HttpServletRequest parameters into the RegistrationRequest? Easy, by delegating the work to the DataItems. Every DataItem knows its name, so it can find the parameter(s) it needs.
class StringDataItem extends DataItem {
// ...
void loadFrom(HttpServletRequest request) {
this.value = request.getParameter(this.name);
}
// ...
}
The RegistrationRequest loads itself from the parameters by delegating to its data items:
class RegistrationRequest extends CompositeDataItem {
// ...
void loadFrom(HttpServletRequest request) {
for (DataItem item: dataItems()) {
item.loadFrom(request);
}
}
// ...
}
If I give an HtmlForm to the RegistrationRequest, then it can add its fields to the form:
class RegistrationRequest extends CompositeDataItem {
// ...
void presentYourselfOn(HtmlForm form) {
for (DataItem item: dataItems()) {
item.presentYourselfOn(form);
}
}
// ...
}
Every Data Item knows how to present itself on a form:
class StringDataItem extends DataItem {
// ...
void presentYourselfOn(HtmlForm form) {
form.addTextField(this.label, this.name, this.value);
}
// ...
}
Does this violate the principle of separating the domain from the user interface? Not really. We’re not concatenating strings to produce html here. We’re interacting with a view object.
Validation will also be handled recursively.
All of the various responsibilities that we’re giving the DataItems can make them increasingly complex. But we can deal with this complexity with delegation. For instance, validation rules could be separate objects that are added to the DataItems, like the EmailValidationRule in the example above.
Conclusion
So we’ve arrived to something that is quite different from what you would get with procedural thinking. Procedural thinking leads you to use a String to represent a first name. This may lead you to use Lombok to generate the setters and getters automatically, and then Hibernate to generate the SQL statements automatically, and so on. An apparently simple and obvious choice leads to a lot of complexity…
The non-entirely-obvious choice of storing the attributes in DataItems leads to a simple way to implement all of the basic functionality of a Crud, with little or no need for frameworks. This helps to keep accidental complexity low.
The approach shown here is not a framework; not even a library. it’s just an idea. You can implement it yourself in very little time, and it will probably come out different every time. That’s right; the DataItem you need in one project is not necessarily the same that you need in another.
January 5th, 2012 at 08:16
Very interesting, Matteo.
On the presentYouselfOn method: I like it very much, it is indeed very similar to Seaside’s renderContentOn method that accepts an HtmlCanvas as an argument.
http://book.seaside.st/book/fundamentals/rendering-components/fun-with-canvas
— Moreno
January 5th, 2012 at 14:47
I completely agree. We did something similar on gae-gwt project and it worked like a charms. Much better than the standard annotation ridden JPA solution.
On a side note:
maybe it’s just because of gwt but we use View specific interfaces.
interface RegistrationView extends FormView {
void setUser(User aUser);
}
then in the implementation we associate the fields in User with the html elements.
Note that there is no getter because the user is not stored as field in the view but just translated in html/js and that our User is immutable, so when the presenter needs the user the View will create a new one from its fields (there could be also hidden).
January 8th, 2012 at 06:29
Interesting but I’m not sure if, in a company, someone writes this code others who will work on the same code will actually use it. This will probably lead to more code redundancy and will worsen the situation.