This post: http://tiny.cc/rpj99
Part 2: http://tiny.cc/h7c5r
Part 3: http://tiny.cc/37paz
The term Fluent Interface was coined by Eric Evans and Martin Fowler in Fowler’s bliki as a proposal to build more readable code in a object oriented API. It can be used with any object oriented language but in this series of posts I will use only c# samples.
It’s based on the method chaining technique where the return of a method is an object that allows the call of another method making the code looks like this:
//C# Sample
subject.DoSomething().DoSomethingElse().Finalize();
This post was motivated by the fact that I did not find any guide or help to build a coherent fluent interface. It was just the opposite I found several different approaches. After some thought I’ve decided to write this one. This is not a definitive guide nor a set of rules but just a proposal to a set o best practices that would help to write a good fluent interface.
Let’s start defining some terms and concepts that I will use in this series.
- Sentence: Is the statement or sequence of methods that defines a operation. The above c# sample is a simple sentence.
- Subject: Is the object been manipulated by the sentence.
- Sentence Starter: The first element of a sentence. In c# it can be:
- An object;
- A method that returns a object or property; or
- A type with static methods that returns a instance object.
The choice of using one of the above depends on the scope you are.
- Term: Is a method or property that can be called from the subject at some point in the sentence. Terms can be:
- A Verb: A term that does something to the subject (sets a property, changes a value or even changes the current subject of the sentence.
- A Constraint: A term that limits the list of terms available next by changing the subject of the sentence.
- A Constraint Verb: A verb that also works as a constraints.
- Sentence Finalizer: An element that does not allow the sentence to continue. Generally It is a method that returns a void.
In a very strict approach every sentence should end with a finalizer, but in practice that not true and the sentence can end in any point the we are satisfied with the state of the subject.
Readable Code X Natural Language Utopia
The initial objective of Fluent Interface was to create a more readable code. But some developers raise the flag of making it to make the code as close as possible to natural language. I consider that over coding. Take the sentence:
Make a car that is yellow and uses gasoline.
We can write is as:
MakeACar().That.Is("Yellow").And.Uses("Gasoline");
Or as:
CreateCar().WithColor("Yellow").WithFuel("Gasoline");
Both approaches are valid. Both are easy to read but I think the first one is harder to code. And this is a very simple sentence.
I think we always need to analyze the problem and the context extensively before coding a fluent interface identifying the possible subjects and verbs to avoid making it too complicated to code or too raw.
Chaining X Nesting
Since we are talking about methods there is always the question about chaining or nesting then. Consider this:
Make a car that has an engine that consumes gasoline, has electronic ignition and max RPM of 4500 and paint it as yellow.
We can write is as:
CreateCar().SetEngine()
.WithFuel("Gasoline")
.WithMaxRPM(4500)
.WithEletronicIgnition
.SetCar()
.WithColor("Yellow");
Or as:
CreateCar().SetEngineTo(CreateEngine().WithFuel("Gasoline")
.WithEletronicIgnition
.WithMaxRPM(4500))
.WithColor("Yellow");
Again both approaches are valid and easy to read but instead of only use method chain we use the nesting to clarify that at some point we are talking about the Engine instead of the Car. By using this alternative we avoid using two Verbs that changes the subject (SetEngine and SetCar) and even define a clear scope for the internal subject (the Engine).
These are the initial considerations I’d like to mention. In the next post I will talk about some techniques to code each part of the sentence with some samples. I will talk about the use of static methods, generics, delegates, builders etc. I hope it helps.