81

In many respects I really like the idea of Fluent interfaces, but with all of the modern features of C# (initializers, lambdas, named parameters) I find myself thinking, "is it worth it?", and "Is this the right pattern to use?". Could anyone give me, if not an accepted practice, at least their own experience or decision matrix for when to use the Fluent pattern?

Conclusion:

Some good rules of thumb from the answers so far:

  • Fluent interfaces help greatly when you have more actions than setters, since calls benefit more from the context pass-through.
  • Fluent interfaces should be thought of as a layer over top of an api, not the sole means of use.
  • The modern features such as lambdas, initializers, and named parameters, can work hand-in-hand to make a fluent interface even more friendly.

Here is an example of what I mean by the modern features making it feel less needed. Take for example a (perhaps poor example) Fluent interface that allows me to create an Employee like:

Employees.CreateNew().WithFirstName("Peter")
                     .WithLastName("Gibbons")
                     .WithManager()
                          .WithFirstName("Bill")
                          .WithLastName("Lumbergh")
                          .WithTitle("Manager")
                          .WithDepartment("Y2K");

Could easily be written with initializers like:

Employees.Add(new Employee()
              {
                  FirstName = "Peter",
                  LastName = "Gibbons",
                  Manager = new Employee()
                            {
                                 FirstName = "Bill",
                                 LastName = "Lumbergh",
                                 Title = "Manager",
                                 Department = "Y2K"
                            }
              });

I could also have used named parameters in the constructors in this example.

Andrew Hanlon
  • 913
  • 1
  • 7
  • 7
  • 1
    Good question, but I think its more a wiki question – Ivo Apr 19 '11 at 08:46
  • Your question is tagged "fluent-nhibernate". So are you trying to decide whether to **create** a fluent interface, or whether to **use** fluent nhibernate vs. XML configuration? – Ilya Kogan Apr 19 '11 at 08:58
  • 1
    Voted to migrate to Programmers.SE – Matt Ellen Apr 19 '11 at 09:26
  • @Ilya Kogan, I think it is actually tagged "fluent-interface" which is a generic tag for the fluent interface pattern. This question is not in regards to nhibernate, but as you said only whether to create a fluent interface. Thanks. –  Apr 19 '11 at 09:28
  • 1
    This post inspired me to think of a way to use this pattern in C. My attempt can be found at the [Code Review sister site](http://codereview.stackexchange.com/questions/6254/fluent-interface-design-pattern-in-c). – otto Nov 24 '11 at 14:14

6 Answers6

28

Writing a fluent interface (I've dabbled with it) takes more effort, but it does have a pay-off because if you do it right, the intent of the resulting user-code is more obvious. It's essentially a form of domain specific langauge.

In other words, if your code is read a lot more than it's written (and what code isn't?), then you should consider creating a fluent interface.

Fluent interfaces are more about context, and are so much more than just ways to configure objects. As you can see in the link above, I used a fluent-ish API to achieve:

  1. Context (so when you typically do many actions in a sequence with the same thing, you can chain the actions without having to declare your context over and over).
  2. Discoverability (when you go to objectA. then intellisense gives you lots of hints. In my case above, plm.Led. gives you all the options for controlling the built-in LED, and plm.Network. gives you the things you can do with the network interface. plm.Network.X10. gives you the subset of network actions for X10 devices. You won't get this with constructor initializers (unless you want to have to construct an object for every different type of action, which is not idiomatic).
  3. Reflection (not used in example above) - the ability to take a passed in LINQ expression and manipulate it is a very powerful tool, particularly in some helper API's I built for unit tests. I can pass in a property getter expression, build a whole bunch of useful expressions, compile and run those, or even use the property getter to setup my context.

One thing I typically do is:

test.Property(t => t.SomeProperty)
    .InitializedTo(string.Empty)
    .CantBeNull() // tries to set to null and Asserts ArgumentNullException
    .YaddaYadda();

I don't see how you can do something like that as well without a fluent interface.

Edit 2: You can also make really interesting readability improvements, like:

test.ListProperty(t => t.MyList)
    .ShouldHave(18).Items()
    .AndThenAfter(t => testAddingItemToList(t))
    .ShouldHave(19).Items();
Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
Scott Whitlock
  • 21,874
  • 5
  • 60
  • 88
  • Thank you for the reply, however I am aware of the reason to use Fluent, but am looking for a more concrete reason to use it over something like my new example above. – Andrew Hanlon Apr 19 '11 at 14:13
  • Thanks for the extended reply. I think you have outlined two good rules of thumb: 1) Use Fluent when you have many calls which benefit from the 'pass-through' of context. 2) Think about Fluent when you have more calls than setters. – Andrew Hanlon Apr 19 '11 at 14:46
  • 2
    @ach, I don't see anything in this reply about "more calls than setters". Are you confused by his statement about "code [that] is read a lot more than it's written"? That's not about property getters/setters, it's about humans reading the code vs. humans writing the code -- about making the code easy for *humans* to read, because we typically read a given line of code much more often than we modify it. – Joe White Apr 20 '11 at 11:33
  • @Joe White, I should perhaps rephrase my term 'call' to 'action'. But the idea still stands. Thanks. – Andrew Hanlon Apr 20 '11 at 11:54
  • Reflection for testing is evil! – Adronius Jan 31 '16 at 17:45
  • @Adronius - only a Sith thinks in absolutes. – Scott Whitlock Jan 31 '16 at 22:21
  • [this](https://www.codeproject.com/Articles/640997/Fluent-interfaces-and-Method-Chaining-in-Csharp) article says `If you are creating fluent interfaces for developers then probably you are wasting time. Developers are consistent with creating objects with the new keyword and setting properties.` and in end of article it says when to use fluent code. What you would suggest ? – Shaiju T Sep 08 '17 at 08:36
24

Scott Hanselman talks about this in Episode 260 of his podcast Hanselminutes with Jonathan Carter. They explain that a fluent interface is more like a UI on an API. You shouldn't provide a fluent interface as the only access point, but rather provide it as some sort of a code-UI on top of the "regular API interface".

Jonathan Carter also talks a bit about API design on his blog.

Kristof Claes
  • 3,100
  • 2
  • 21
  • 33
14

Fluent interfaces are very powerful features to provide within the context of your code, when don with the "right" reasoning.

If your aim is to simply create massive one-line code chains as a kind of pseudo-black-box, then you're probably barking up the wrong tree. If on the other hand you are using it to add value to your API interface by providing a means to chain method calls and improve code readability, then with a lot of good planning and effort I think the effort is worth it.

I'd avoid following what seems to becoming a common "pattern" when creating fluent interfaces, where you name all of your fluent methods "with"-something, as it robs a potentially good API interface of its context, and therefore its intrinsic value.

The key is to think of the fluent syntax as a specific implementation of a Domain-specific language. As a really good example of what I'm talking about, have a look at StoryQ, which employs fluency as a means to express a DSL in a very valuable and flexible manner.

Nexaspx
  • 148
  • 4
S.Robins
  • 11,385
  • 2
  • 36
  • 52
  • Thanks for the reply, it's never too late to give a well thought out response. – Andrew Hanlon Dec 01 '11 at 17:27
  • I don't mind the 'with' prefix for methods. It sets them apart from other methods that don't return an object for chaining. E.g. `position.withX(5)` versus `position.getDistanceToOrigin()` – LegendLength Jul 15 '17 at 10:20
5

Initial note: I'm taking issue with one assumption in the question, and draw my specific conclusions (at the end of this post) from that. Because this probably doesn't make for a complete, encompassing answer, I'm marking this as CW.

Employees.CreateNew().WithFirstName("Peter")…

Could easily be written with initializers like:

Employees.Add(new Employee() { FirstName = "Peter", … });

In my eyes, these two versions ought to mean and do different things.

  • Unlike the non-fluent version, the fluent version hides the fact that the new Employee is also Added to the collection Employees — it only suggests that a new object is Created.

  • The meaning of ….WithX(…) is ambiguous, especially for people coming from F#, which has a with keyword for object expressions: They might interpret obj.WithX(x) as a new object being derived from obj that is identical to obj except for its X property, whose value is x. On the other hand, with the second version, it's clear that no derived objects are created, and that all properties are specified for the original object.

….WithManager().With…
  • This ….With… has yet another meaning: switching the "focus" of the property initialization to a different object. The fact that your fluent API has two different meanings for With is making it difficult to correctly interpret what is happening… which is perhaps why you used indentation in your example to demonstrate the intended meaning of that code. It would be clearer like this:

    (employee).WithManager(Managers.CreateNew().WithFirstName("Bill").…)
    //                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //                     value of the `Manager` property appears inside the parentheses,
    //                     like with `WithName`, where the `Name` is also inside the parentheses 
    

Conclusions: "Hiding" a simple-enough language feature, new T { X = x }, with a fluent API (Ts.CreateNew().WithX(x)) can obviously be done, but:

  1. Care must be taken that readers of the resulting fluent code still understand what exactly it does. That is, the fluent API should be transparent in meaning, and unambiguous. Designing such an API may be more work than is anticipated (it might have to be tested for ease-of-use and acceptance), and/or…

  2. designing it might be more work than is necessary: In this example, the fluent API adds very little "user comfort" over the underlying API (a language feature). One could say that a fluent API should make the underlying API / language feature "easier to use"; that is, it should save the programmer a considerable amount of effort. If it's just another way of writing the same thing, it's probably not worth it, because it doesn't make the programmer's life easier, but only makes the designer's work harder (see conclusion #1 right above).

  3. Both points above silently assume that the fluent API is a layer over an existing API or language feature. This assumption may be another good guideline: A fluent API can be an extra way of doing something, not the only way. That is, it might be a good idea to offer a fluent API as an "opt-in" choice.

stakx
  • 2,138
  • 18
  • 29
  • 1
    Thank you for taking the time to add to my question. I will admit that my chosen example was poorly thought through. At the time I was actually looking to use a fluid interface for a querying API I was developing. I oversimplified. Thanks for pointing out the faults, and for the good conclusion points. – Andrew Hanlon Aug 14 '13 at 21:08
2

I like the fluent style, it expresses intent very clearly. With the object initaliser example you have after, you have to have public property setters to use that syntax, you don't with the fluent style. Saying that, with your example you don't gain much over the public setters because you've almost gone for a java-esque set/get style of method.

Which brings me to the second point, I'm not sure if I'd use the fluent style in the way you have, with lots of property setters, I'd probably use the second version for that, I find it better when you have a lot of verbs to chain together, or at least lots of doings rather than settings.

Ian
  • 5,462
  • 22
  • 26
  • Thanks for your reply, I think that you have expressed a good rule of thumb: Fluent is better with many calls over many setters. – Andrew Hanlon Apr 19 '11 at 14:44
1

I wasn't familiar with the term fluent interface, but it reminds me of a couple of APIs I've used including LINQ.

Personally I don't see how modern features of C# would prevent the usefulness of such an approach. I would rather say they go hand in hand. E.g. it's even easier to achieve such an interface by using extension methods.

Perhaps clarify your answer with a concrete example of how a fluent interface can be replaced by using one of the modern features you mentioned.

Steven Jeuris
  • 5,804
  • 1
  • 30
  • 52