Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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.

share|improve this question

migrated from stackoverflow.com Apr 19 '11 at 12:51

This question came from our site for professional and enthusiast programmers.

1  
Good question, but I think its more a wiki question –  Ivo Apr 19 '11 at 8: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 8:58
1  
Voted to migrate to Programmers.SE –  Matt Ellen Apr 19 '11 at 9: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. –  ach Apr 19 '11 at 9: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. –  Otto Harju Nov 24 '11 at 14:14

6 Answers 6

up vote 19 down vote accepted

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();
share|improve this answer
    
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. –  ach 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. –  ach Apr 19 '11 at 14:46
1  
@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. –  ach Apr 20 '11 at 11:54

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.

share|improve this answer
    
Thanks a lot for the info links and the UI on top of API is a nice way of looking at it. –  ach Apr 19 '11 at 14:16

I'm a little late but thought I'd weigh in on this...

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.

share|improve this answer
    
Thanks for the reply, it's never too late to give a well thought out response. –  ach Dec 1 '11 at 17:27

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.

share|improve this answer
    
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. –  ach Aug 14 '13 at 21:08

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.

share|improve this answer
    
Thanks for your reply, I think that you have expressed a good rule of thumb: Fluent is better with many calls over many setters. –  ach Apr 19 '11 at 14:44

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.

share|improve this answer
1  
Thanks for the reply - I have added a basic example to help clarify my question. –  ach Apr 19 '11 at 14:16

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.