April 5, 2008 @ 8:37 pm
Configuration Method Chaining
We have all seen method chaining, especially in configuration classes. Architecture Rules has a typical configuration class that currently does not support method chaining. Modifying the public API of a tool is hardly ever a good thing, but in this case, the change would still be completely backwards compatible. So we decided to investigate method chaining to determine if it should be introduced into this project or not.
What is it
Method chaining is a programming technique that is supported by many public interfaces. It allows the programmer to call one method from - directly after - another. For example, in Java:
Chained
Event event = new Event()
.setDescription("")
.setStartDate(start)
.setEndDate(end)
.setPrivate(true);
Unchained
Event event = new Event();
event.setDescription("");
event.setStartDate(start);
event.setEndDate(end);
event.setPrivate(true);
Where Is It
We see it very often with configuration classes. Such as the Hibernate Configuration class.
Configuration configuration = new Configuration()
.addClass(org.hibernate.Item.class)
.addClass(org.hibernate.Bid.class)
.setProperty("...dialect", "...MySQLInnoDBDialect")
.setProperty("...connection.datasource", "java:jdbc/test")
.setProperty("...order_updates", "true");
Its also used commonly with the Builder Pattern which simply creates a complex object using a number of steps.
How To
Designing method chaining into your code is pretty simple. In Java, rather than returning void by a method, such as a setter methods, return the entity being acted on. In Java, just return this;
class Event {
public Event setDescription(String description) {
this.description = description;
return this;
}
public Event create() {
... something complicated ...
return this;
}
}
So, to change an existing class to support method chaining in Java, change all your void methods, to return the entity type, and add return this; at the end of the method. It is pretty much a trivial task.
Concerns
There are some concerns with method chaining.
First, there are some out there who claim that chained methods are less readable. To them, it could be less readable. To other, more readable. Aligning the chained method calls on new lines can increase readability. A single line of method calls is certainly less readable than a single method call on a single line. Compare this to the examples of the Event class above.
Event event = new Event()
.setDescription("").setStartDate(start).setEndDate(end);
Second, mixing setter methods, with action methods can be very confusing to the readers. The problem comes with determining where these complex actions are taking place. Consider the following.
int eventId = new Event()
.setDescription("")
.setStartDate(start)
.setEndDate(end)
.setPrivate(true)
.insert()
.getId();
This is simple example. Most everyone understands that the insert() call is utilizing JDBC code to insert the Event in to a table, it probably sets the Event id property, and then the getId() returns that id. But what if the entity was more obscure, and the method name was not so clear? It might not be obvious where complex actions are taking place.
A third concern is when do you stop? and when don’t you stop? Let say an entity has a dozen or so setters that are commonly called as part of setting up a usable entity. Should you call all twelve? Two groups of six? Group by type? What is more readable? what is less readable? I don’t know. Depends on the author, the readers, the context. There are a lot of considerations.
When to Use
Method chaining is pretty commonly used when you are performing one complete action, building a complete entity, or performing an atomic task.
First, performing an action, such as a query. Here is an example from Hibernate.
List cats = session.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("age", minAge, maxAge) )
.list();
Second, building an entity. Sometimes this is done with a Builder class. With the example of the Event class, calling the setters could be chained. Calling insert() and getId() should not be chained.
Finally, an atomic task, such as validation, could reasonably be chained.
boolean valid = validator(value) .isGreaterThan(0) .isLessThan(10) .isCurrancy();
Our Dilemma
We did this research to determine weather or not we should modify the Architecture Rules API to support method chaining in the Configuration and Rule classes.
Based on the research that we have done, since the Configuration and Rule classes have no actionable methods - just setters, they are essentially POJOS - we think it would be appropriate to chain those setters together, and that the resulting code would be no less readable or deceiving. We will include method chaining in 2.1.0.
Resources
http://martinfowler.com/dslwip/MethodChaining.html
http://www.hibernate.org/hib_docs/reference/en/html/session-configuration.html
http://kasparov.skife.org/blog/src/method_chaining.html
Now that you've read what we think, what did you like about the post? Where do you think we went wrong? Join or star the discussion.
Filed under Architecture-Rules, Open Source, Software Development Permalink

