Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

In many respects I really like the idea of Fluent interfaces, but with all of th

ID: 642309 • Letter: I

Question

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.

Explanation / Answer

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:

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).
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).
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();

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote