Fluent Interfaces

A few weeks back, a friend asked my opinion of fluent interfaces. My impression, based on what I’d read here and there, was not favorable. Expending that kind of design effort to avoid a few keystrokes while coding and to make code read more like natural language never struck me as a worthwhile trade for most cases. I should note here that this is in the context of .Net development. Other languages have different characteristics that make this style less of an imposition of additional work.

However, in spite of a negative initial impression, I decided that it was time to explore the subject in a more disciplined manner in order to fairly evaluate the value of the technique. In my research, I found it interesting that I found much more about how to implement fluent interfaces than I found about why to use them in my designs. Step one was to go to the source to get a good definition. Martin Fowler, one of the originators of the term, provided an example that illustrates it:

I’ll continue with the common example of making out an order for a customer. The order has line-items, with quantities and products. A line item can be skippable, meaning I’d prefer to deliver without this line item rather than delay the whole order. I can give the whole order a rush status.

The most common way I see this kind of thing built up is like this:

private void makeNormal(Customer customer) {
Order o1 = new Order();
customer.addOrder(o1);
OrderLine line1 = new OrderLine(6, Product.find(“TAL”));
o1.addLine(line1);
OrderLine line2 = new OrderLine(5, Product.find(“HPK”));
o1.addLine(line2);
OrderLine line3 = new OrderLine(3, Product.find(“LGV”));
o1.addLine(line3);
line2.setSkippable(true);
o1.setRush(true);
}

In essence we create the various objects and wire them up together. If we can’t set up everything in thnote constructor, then we need to make temporary variables to help us complete the wiring – this is particularly the case where you’re adding items into collections.

Here’s the same assembly done in a fluent style:

private void makeFluent(Customer customer) {
customer.newOrder()
.with(6, “TAL”)
.with(5, “HPK”).skippable()
.with(3, “LGV”)
.priorityRush();
}

Probably the most important thing to notice about this style is that the intent is to do something along the lines of an internal DomainSpecificLanguage. Indeed this is why we chose the term ‘fluent’ to describe it, in many ways the two terms are synonyms.

Fowler himself admits that there is a cost involved:

The price of this fluency is more effort, both in thinking and in the API construction itself. The simple API of constructor, setter, and addition methods is much easier to write. Coming up with a nice fluent API requires a good bit of thought.

In addition to confirming that the technique injected extra work into the development, Fowler also points out another issue: “One of the problems of methods in a fluent interface is that they don’t make much sense on their own”. He admits that, in isolation, With() is a “badly named method that doesn’t communicate its intent at all well”. So far, not so good.

Martin Fowler’s article linked to another by Piers Cawley, that defined fluent interfaces as “essentially interfaces that do a good job of removing hoopage (James Duncan’s handy term for all the jumping through hoops you have to do in order to achieve something that ought to be a lot simpler)”. I would question whether the technique has simplified anything, however. I’ve seen no data to justify that the effort expended in designing and coding the fluent interface is recaptured in the code using it. Additionally, we have Fowler’s admission that the methods aren’t always intuitive.

Further research continued to confirm my impressions. Paul Jones and Scott Hanselman both came to the conclusion that the technique works best in very specialized cases. Some of those cases seen in my research were test frameworks, mocking frameworks and entity factories. The fact that those first two cases involve public APIs is instructive. The investment for an internal API will likely not be worth it.

In most cases, the effort spent on designing and coding a fluent interface for internal use could be better directed to providing business value. While I am a proponent of investing in maintainability, the information above leads me to believe that the “bang for the buck” is lacking.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s