Just A Summary

Piers Cawley Practices Punditry

Fluent Interfaces 10

Posted by Piers Cawley Wed, 21 Dec 2005 09:28:00 GMT

[Edited to correct an accidental misrepresentation, and again to correct an attribution, and again to correct some code]

Martin Fowler is talking about interfaces again and, as usual, he’s mostly talking sense.

This time he’s talking about what he’s christened ‘fluent interfaces’—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) from the client side of the interface. In the examples Fowler gives, client side complexity (and in one case a subtle, but unpleasant code smell) is reduced by moving object construction behind a thoughtful, humane interface.

A truly fluent interface can be a delight to use. Anything which reduces the amount of stuff I have to remember about how a class is implemented when I’m reading code that makes use of that class is definitely a good thing. Using a fluent interface can be akin to programming in a well thought out Domain Specific Language.

Where I take issue with Fowler is that he describes this kind of fluency as a ‘new’ thing. Now, it may very well be a new thing in the Java world, but it’s bordering on old hat in dynamic language circles. Fluent interfaces have been around in dynamic language circles for years, but good examples are depressingly rare. At its simplest there are all those handy Smalltalk constructor methods like 1 upTo: 10 which builds a range, or (generally more usefully) 1 upto: 10 do: [ i | ... ], which builds a range, then calls the block for every integer in the range. I quite like the iterator version as an example here. On the face of it, it would be perfectly reasonable not to provide that method and make the programmer write (1 upTo: 10) each: [ i | ... ] but that’s kind of ugly, so Integer gets yet another convenience method.

Old Lisp hands will find this sort of interface familiar too. Lispers have probably gone further than most down the fluency road. Lisp macros allow them to go the whole hog and offer a ‘real’ domain specific language rather than an interface that looks like one.

In the Perl world, Damian Conway has been doing this for years. His ability to make Perl do the seemingly impossible in the service of a clear and powerful interface is a delight to see. His Advanced Interfaces course is one of those courses I really, really want to take one of these fine days. Mark Jason Dominus is good in this area too. His book, Higher Order Perl is chock full of examples of fluent interfaces to powerful tools.

Meanwhile, over in the Ruby world, the Rails interfaces are emphatically fluent. David Heinemeier Hansson uses class methods for some rather neat declarative programming techniques. For instance, a single has_many :foos ‘declaration’ sets up the underlying relationship and adds a bunch of accessor methods.

Designing a truly fluent interface is hard; implementing the library behind them can be harder still. I’m not sure I’ve ever managed to do it, but I’ll offer a few pointers based on the good examples I’ve seen:

  1. Hide your working. Showing your thought processes only ever gets you bonus points when you’re doing maths homework.
  2. Keep your state to yourself. In the ‘order’ example that Fowler gives, the ‘before’ version has a slightly fishy odor to it because Order’s implementation as a collection of OrderLines is exposed to the client. Hiding OrderLine construction behind a fluent interface helps maintain loose coupling. Also note that it’s better to write methods along the lines of message.publish and message.mark_as_draft say, than it is to have the client write message.published = true—you never know when you might need more than two states for something that used to be a boolean after all.
  3. Think really hard about names. Designing an API is an exercise in language design so focus on making that language make sense from the point of view of the client. It’s especially easy to make this mistake with languages that allow you to pass named parameters to your methods. Smalltalk’s method selectors are the winners here: Integer#upTo: anInteger do: aBlock is great; the method selector parts (upTo:do:) inform the user what role the parameter plays, and parameter names anInteger, aBlock are free to suggest the type of value being passed.
  4. Take advantage of your implementation language. For instance, ActiveRecord classes can be initialized using a block:
    new_post = Message.new do |m|
      m.title = "Some title"
      m.body = ...
      ...
    end
    This has several advantages. From a conciseness point of view, you can give your post a nice short name in the block so the various initialization steps are concise, but you can also give it a usefully descriptive name outside. You can also do tricks like only enabling consistency checking after the block’s completed its initialization, which can be very handy for some types of objects.
  5. If you have them, blocks are you friends. Once you can start passing blocks to your methods you can start writing methods that look remarkably like syntax.
  6. Test first design can be a useful way of exploring what your interface should be. Write tests that use the interface you want and then move heaven and earth (but only if necessary) to make them pass. Use the Just Principle—the idea that you can answer most “How do I … ?” questions about your library with a short “You just …” answer.
  7. Reasonable defaults. Don’t force the client to tell you the same thing nine times out of ten—Rails is strong here.

There’s more, but it’s surprising how far you can get along the road to fluency simply by being rigorous about things like encapsulation, good names and the DRY principle.

Comments

Leave a response

  1. Avatar
    Joe Reddy swcses.eponym.com about 1 year later:

    I like your 7 points. I too have been practicing the idea of “fluent” interfaces for awhile without giving it a name. Although I don’t use Visual Basic much anymore, the English-like syntax was very attractive.

    I espcially ike the “Just Principle” I think I will use that when explaining using an english-like appraoch to interfaces.

    Take care,

    Joe http://swcses.eponym.com

  2. Avatar
    Bob about 1 year later:

    The fluent interface has been around for more than 20 years most likely from SmallTalk. This was considered cool in the early 1990s and fell out of favor for the same reasons that a complicated single line for loop with only a semi-colon body is now avoided.

    From: j...@hplsla.HP.COM (Jim Adcock)
    Newsgroups: comp.lang.c++
    Subject: Re: ********
    Message-ID: <6590264@hplsla.HP.COM>
    Date: 26 Sep 89 18:54:01 GMT
    References: <3863@helios.ee.lbl.gov>
    Organization: HP Lake Stevens, WA
    
    In any case, assignment to this is considered obsolete with 2.0, though
    still allowed for backward compatibility.  Expect C++ compilers to not
    support assignment to this in the future.  Not allowing assignment to
    this can allow more efficient compilers. For example, consider the following
    oop style of chaining commands:
    
    ---------------------------------------------------------------------------
    class something
    {
    public:
     something& dothis();
     something& dothat();
     something& doanotherthing();
    };
    
    something& something::dothis(){ /* do something, then */ return *this;}
    something& something::dothat(){ /* do something, then */ return *this;}
    something& something::doanotherthing(){ /* do something, then */ return *this;}
    
    main()
    {
      something I;
    
      I.dothis().dothat().doanotherthing();
    }
    
  3. Avatar
    Piers Cawley about 1 year later:

    I can’t honestly say I’m advocating doing that. Even in Smalltalk where a method defaults to returning self unless you tell it to return something else, you’d use a cascade:

    SomeClass new
      doThis;
      doThat;
      doTheOther

    is rather neater than:

    |anObject|
    
    anObject := SomeClass new.
    anObject doThis.
    anObject doThat.
    anObject doTheOther

    Interestingly, the Rails framework now defines a returning method which can be abused to give something like Smalltalk cascades:

    returning(SomeClass.new) do |o|
      o.do_this
      o.do_that
      o.do_the_other
    end

    but it does seem rather clumsy next to Smalltalk’s syntax.

  4. Avatar
    Bob about 1 year later:

    This C++ practice of chaining together member function calls fell out of favor because writing the code using traditional means was about the same number of lines of code without hiding the implementation details. It also fell out of favor because it promotes writing code that does not do error handling for individual member functions called (via a large try/catch block around all of the calls).

    Code like the following should be avoided by having an AddLineItem(string, quantity) method for BillingRecord

    BillingRecord r = new BillingRecord()
    LineItem i = new LineItem("Apples", 10)
    r.AddLineItem(i)
    LineItem j = new LineItem("Pears", 10)
    r.AddLineItem(j)
    LineItem k = new LineItem("Oranges", 10)
    r.AddLineItem(k)
  5. Avatar
    Piers Cawley about 1 year later:

    While I take your point, your comments seem to be directed more at Martin Fowler’s original post than this one.

    You seem to think that exposing implementation details is a good thing, which strikes me as odd; I’ve always taken the view that you leave the implementation to the object and concern yourself with coming up with message protocols that are relevant to the task you want the object to perform.

  6. Avatar
    dan ros about 1 year later:

    good once

  7. Avatar
    Stehan Schmidt about 1 year later:

    The blog and the comments mix different concepts. They miss the point. This reminds me of David Weinbergs “There is no problem.” The blog post mainly talks about DSLs and the comments about cascading calls. upTo and belongsTo are not examples for fluent interfaces. Fluent interfaces are more than this. They are semantically on a higher level. Fluent interfaces use clever cascading calls with clever return types to create human readable constraint or object descriptions.

    Quaere is an example of an fluent interface.

    http://andersnoras.com

    Peace -stephan

    — Stephan Schmidt :: stephan@reposita.org Reposita Open Source – Monitor your software development http://www.reposita.org Blog at http://stephan.reposita.org – No signal. No noise.

  8. Avatar
    Piers Cawley about 1 year later:

    Looking at Quaere, I find it hard to think of any API that requires the user to pass ‘executable’ string arguments as being particularly fluent.

    You seem to be under the impression that interface fluency is something that only applies to a particular domain, and in that, I think you’re flat out wrong.

    Fluent interfaces can crop up anywhere. The (1 upTo: 10) do: [ ... ] example I gave from Smalltalk exhibits exactly what you claim is the distinguishing feature of a fluent interface. It’s an example of a cascading call that makes use of a clever return type (a message sent to a number builds a range object) to build a human readable loop.

    Admittedly, it’s not as tiresomely clever as some fluent interfaces can be, but denying that it’s fluent simply because it doesn’t fit your model of where fluent interfaces should be used isn’t really on either.

    I contend that fluency is a condition that all api designers should aspire to, whatever their domain. Smalltalk uses fluency to solve problems that other languages address by introducing syntax. Fluently designed classes like Range and the rest of the collection hierarchy, coupled with well thought out constructors on other classes mean that a Smalltalk image is well supplied with expressive, fluent ways of specifying loops and other types of control flow, that the language itself has special syntax for handling control flow.

    Every time I come back from exploring smalltalk, I find myself wondering about adding ifTrue(&block), ifFalse(&block), ifNil(&block) etc to ruby…

    So far, I’ve resisted.

  9. Avatar
    Neil Martin about 1 year later:

    I have referenced this post in my post : http://neildmartin.spaces.live.com/blog/cns468.entry468.entry

    I love method Chaining and fluency in its place it is very powerful and makes API’s easy to consume however it isnt the end of the story and can be used very badly i liked your 7 points.

  10. Avatar
    Mert Nuhoglu over 2 years later:

    I think, Stephan Schmidt’s blog post on this topic is the way to go: Fluent Interface and Reflection for Object Building in Java

Comments



Just A Summary