Fluent Interfaces – Let the API tell the story

In my last post about Creating a decent API for client side script registration, Eran raised a few great comments about the readability and proper usage of this style of coding. I decided to answer his questions with a post, as my comment started to fill enough paper to clean a Brazilian forest or two (well, in terms of a response).


Introduced by Martin Folwer, Fluent Interfaces ables the programmer to supply an API that can be used to build a genuine use-case in the system or just a complete logical query\request from a service. This coding style is quite different from the traditional 101 lessons in OOP school. The biggest benefit of Fluent Interface, in my opinion, is that you can read the code out load like the customer is talking to you instead of the programmer that wrote it. Sometimes it gets even better, you can read someone’s else code like she\he was next to you, explaining what she\he meant do do. My take is that using a method to describe use-case\action\query\request will be (almost)always better, in terms of readability, than using parameter(s) as you’ll need the IntelliSense to understand the latter. Here is a simple API, the first one is traditional OOP while the second one applies Fluent Interfaces. Please bare in mind that these samples were written just to set the ground for the difference between these two coding technique:


// take 1 – traditional style
public class ClientSideExtender
{
    public void CallMethod(string methodName, RunAt runScriptAt, bool ignoreExceptions, params object[] parameters);
}



// take 2 – Fluent Interfaces


public class ClientSideExtender
{
   public ScriptCommand CallMethod(string methodName);
}

public class ScriptCommand
{
     public ScriptCommand WithParameters(params object[] parameters);
     public ScriptCommand When(RunAt runScriptAt);
     public ScriptCommand IgnoreExceptions();
}


Assuming that we have a javascript method with this signature “markRow(rowId, shouldDisableOtherRows)”, here is how can one use these API to register client-side method call(accordingly):


clientSideExtender.CallMethod(“markRow”, RunAt.AfterPageLoaded, true, “5”, true);

clientSideExtender.CallMethod(“markRow”).WithParameters(“5”, true).When(RunAt.AfterPageLoaded).IgnoreExceptions();



Obviously, both API will create the same code eventually: <script …>markRow(“5″, true);</script>.
What I really love about Fluent Interfaces is that I don’t need the freakin’ IntelliSense in order to understand what “true” means as a parameter(the difference is marked in red). It ables me to read it out load – I want to call a client-side method named “markRow”, with 2 parameters, execute it after the page is loaded and wrap the entire thing to swallow exceptions (assume that someone else will take care of it). If you want to call a method that doesn’t get any parameter, don’t call to WithParameters method. You can always change the order of the calls if you see it fit (maybe calling IgnoreException before When).


One of the blames I hear(again and again) about Fluent Interfaces is that it “allows” programmers to abuse the code. “You can change the order of the calls or forget to call one and make a big mess” is a common response to the concept. To be totally honest, I don’t eat it as programmers can make a mess of pretty much anything. We’ve all been there, right? I agree that it requires some different way of thinking about creating & using API, but then again, so does learning a new programming principle, a design pattern or a coding techinque. It took several years until people started to chew TDD and accept the advantages of using it. My guess is that in ~1-2 years, Fluent Interfaces will be much more common in the way we’re writing and using code (LINQ rings a bell? well OK, leaving the “sql-like” synthetic sugar aside).



This leads me to my believe about designing Fluent Interface. I say – when appropriate, why not allowing the programmer to choose?
I would create two overloads for CallMethod, as shown above, and let the programmer decide which one she\he would like to use.


I would use Fluent Interface.

 

Oren Ellenbogen

 

6 thoughts on “Fluent Interfaces – Let the API tell the story

  1. Hi Oren!

    This is a nice new approach. I think the adventage with that is the clarity of reading and using the code for the outside watcher, BUT there is also one big disadventage: By using this API and way of programming, you don’t encapsulates the methods (/properties/members) under one issue/category, the result is that you will have a quite long list of methods that are not devided to categories and this is quite annoying.

    I think that some refactoring will be necessary here… (tell me aht you’re thinking about it)

  2. Hi dude!

    Sorry, but I don’t see how you can get around the fact that nothing can hint you about the correct order to call the functions. I’m assuming in some cases the order is important and you certainly don’t want to support all 6 possibilities in your ScriptCommand class code, right?

  3. @Eran – well, the way I see it it’s actually quite the opposite. It requires you to think about how to split responsibilities to other objects just like it should be(in OOP). The ClientSiteExtender should not contain IgnoreException nor WithParameters, the ScriptCommand(I would change the name to ScriptBlockCommand, but that was just an example with ONE method) should.

    Keep in mind that ClientSideExtender will contain methods like CreateVariable that will return VariableScriptCommand that implements IScriptCommand, AttachHandler that will return AttachmentScriptCommand etc…). Now ClientSideExtender should hold a List<IScriptCommand> and call the "RegisterCommandToControl" and that’s it. It does not understand the "scripting" logic. In addition, I can give it(ClientSideExtender), as constructor parameter, something like IScriptWritter and thus decouple Microsoft’s ClientSscriptManager(asp.net 2.0)\ScriptManager(asp.net ajax) from my extender (making it more testable, wheeo! :)).

    I think that the traditional way of writing these methods(meaning – with a lot of parameters) is cumbersome and requires some\a lot of IntelliSense work in order to make sense. I hate the idea that code doesn’t look understandable at FIRST-LOOK. Please let me know how would you refactor it, maybe I’m missing something here. I hope that after I’ll upload the full code things will make more sense.

  4. @Kalish(aka T-bag ;-)) –
    This is a great question but I have a simple answer. I think. If you have coupled proerties – let’s say you get 2 parameters in a method and if the first paratmers is true then you do A and if it’s false you do B on the second parameter – you’ll never split them into seperate methods as you (like you said) can’t know(and don’t want to) in which order they will be called. You’ll put it in one method with a great name(to make things understandable at FIRST-LOOK). You must plan your Fluent Interface to be order-ignorant. I did not see a scenario, yet, that blocked me from using Fluent Interfaces, it’s just a matter of modeling your objects in the right way and thinking very carefully about responsibilities. I think that this is a GOOD THING anyway so if Fluent Interface makes us think a little harder to come up with an elegant solution (just like Test Driven Development does) – great!

    This leaves us with a very important scenario where you need to get some "MUST" properties set. Let’s say that in our example, without setting the method name(string), there is no sense in calling CallMethod, right? In addition, it doesn’t make any sense to send string.Empty or null as the methodName. This is what I call a "MUST" property.
    The trick I love to use in this scenario is to make the "MUST" properties as parameters in the "entry-point". From the code above:
    public class ClientSideExtender {
    public ScriptCommand CallMethod(string methodName);
    }

    The method CallMethod inside the class ClientSideExtender is what I call the "entry-point" to the Fluent Interface. That’s why I’ve decided to put the methodName parameter there (you can’t start the "flow" without setting it).

    To recap – put coupled properties in the same method(just like you had before, but now all the decoupled properties will sit in a better place) and put all the "MUST" properties in the Fluent Interface entry-point(s). I hope that it covers your questions, but please let me know if you have more.

  5. Thanks for the answer, One more question if I may…
    Where does the “execute” code resides on the fluent interfaces? If I understand correctly, every method implementation sets some private member(s) on the object and returns “this”, right? Assuming you don’t know the order of the called methods, you don’t know which will be the last method called, so you can never execute anything. All you can do is set the parameters but never do anything else – at least not on the class implementing the interfaces, right?

    T-Bag

  6. @Kalish(= T-Bag) –
    Great questions dude, I appreciate it. So my answer for your last question will be:
    Don’t look at Fluent Interfaces as a set->execute pattern, look at it only as a set(in a very descriptive way) pattern. "But who should "activate" the all thing eventually?" you might ask, well, it depends. In some scenarios it will be done in the same class that was used to hold the "entry-point" (my ClientSideExtender registers to an event on the control and "execute" all the registrations there) and in other scenarios in can be done via additional (service)class that recieves the "fluent generated object" as a parameter.

    For instance, consider the following:
    Customer customer = Repository<Customer>.FindOne(1);//customer with ID=1
    customer
    .RegisterNewOrder(".Net 2.0 Books") //this baby is the entry point. I’ll return Order for Fluent Interface
    .AddItem("Design scalable .net 2.0 applications") // Return Order
    .AddItem("C# 2.0 for monkies") // Return Order
    .WithDiscountInPrecentage(10); // Return Order, end of "set"

    Repository<Customer>.Save(customer); //This is the "execute"

    The "Save" here is NOT interesting, it’s the description of the order that we want to see in front of us. In this scenario, an external class(Repository) will handle the "boring" task of persisting the data.
    By the way, it is possible to add additional method named "SaveOrder" that will "return" void so this will execute the code as part of the Fluent Interface. It can get quite confusing so I would think hard before doing something like it(and consider renaming to StartRegisterNewOrder and FinishRegisterationAndSave instead of RegisterNewOrder and SaveOrder accordingly), but it’s possible.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>