A coworker commented to me today "what's up with all these libraries that encourage method chaining? ;-)" when we were talking about FEST. To stay in context, we are talking about this kind of thing:
assertThat(yoda).isInstanceOf(Jedi.class)
.isEqualTo(foundJedi)
.isNotEqualTo(foundSith);
This, of course, has also been called nice things like "train wreck" and is frequently seen to be a brittleness inducer in code. On the other hand, I encourage the heck out of it in libraries I write, from jDBI for example:
handle.prepareBatch("insert into something (id, name) values (:id, :name)")
.add(1, "Brian")
.add(2, "Keith")
.add(3, "Eric")
.execute();
On yet another hand, I pointed out that it was a bad practice to someone in a code review just last week. So, when is it a good fluent interface, and when is it a train wreck? Good question. My first reaction is "I know it when I see it" but that isn't very useful. So, to take a stab at a description...
Method chaining makes a good interface when the chained methods all
come from the same module, are part of the published API, and when taken
together represent a single logical action. In the first example, they are
all on the published interface of FEST-Assert and are asserting that
yoda is correct. In the second, they all come from the
published interfaces of jDBI and form one batch statement.
For a negative example, let's take data access traversal:
yoda.getMidiclorians().getForce().getDarkSide().getLightningFromFingers();
Here, even if the interfaces for all the intervening classes are in the same module, and are very stable, it sure as heck isn't a single logical unit.
Anyway, gotta run, lunch is done. If I think of a better way to describe it will do so this evening!