Click here to monitor SSC
  • Av rating:
  • Total votes: 15
  • Total comments: 8
Tom Fischer

Fluent Code in C#

11 July 2013

In LINQ, the 'fluent' method syntax  flows logically and intuitively, and allows them to be combined simply, because each method returns the appropriate type of object for the next. Can this fluent technique be extended as an API style to make it easier to develop C# team-based applications for enterprises?

One of the more interesting by-products of LINQ is the interest it has generated in the use of ‘fluent code’. But what is “fluent code”? In this article, I’ll briefly introduce the theory before exploring this popular programming paradigm. We will discuss some techniques and considerations for implementing a fluent interface in the enterprise, illustrated by a demonstration application

The Fluent Interface

Several years ago, in 2005, the object-oriented programming expert Martin Fowler published his essay on the ‘fluent interface’. He described an approach for building software with more readable code that could be more easily maintained by developers because it is easier to read, and discover how to use, than a traditional API that contains functions with a number of parameters. While the fluent interface might have been an idea ahead of its time when the technique was first published, one now sees terms employed to describe code, such as, “fluid coding”, “fluent style” and “fluent API”, which suggest its time has arrived

What exactly constitutes a fluent interface? Fowler describes the way that processes are defined by creating the various objects and then wiring them up together by means of an internal domain-specific language (DSL). The intention is to produce an API that is readable and flows. He suggests using method chaining, with nested functions and object scoping. There are several approaches to implementing this depending on the language that is used. Java has supplementary classes or libraries to do this. Ruby and Scala have an inbuilt fluent interface. For C# and VB, there is LINQ. The LINQ (Language-Integrated Query) snippet below exemplifies the concept. It converts a few data operations into a statement.

            var recentBigOrders = OrderList

                .Where(o => o.Amount > 1000 && o.Date >= DateTime.Now.AddDays(-5))

                .OrderBy(o => o.Amount)

                .Take(10)

                .Select(o => o.Customer);

The chaining of several methods to produce an IEnumerable collection stands out as the most interesting characteristic of this query. Before LINQ, a C# programmer who required a list of Customers with recent and large orders would have likely needed to write several lines of code.

From what I’ve said so far, the importance of the underlying context may not be obvious. By definition every chained LINQ command knows that the object it consumes and returns contains IEnumerable data with operations exposed by IQueryable . This understanding of the context allows the programmer to combine several SQL-like methods into one statement for building a dataset. For example, the above Where accesses each OrderList record via IEnumerable’s GetEnumerator , as well as adding filtering to other commands (OrderBy , Take and Select ) via IQuerable’s Expression .

Domain knowledge constitutes a subtler, non-technical, requirement for successfully implementing a fluent interface. If the developers who are using the fluent interface are not well versed in knowledge about the business domain, then they are not going to make things simpler to use by combining enigmatic methods. If the domain methods are not understood by the developers before they implement the fluent interface, then they will elucidate nothing by chaining them together. Can you imagine developers who are unacquainted with filtering and grouping data finding comfort with LINQ’s Where and GroupBy methods?

In summary, fluent code typically involves three properties: chained methods; a context; and common knowledge of the business domain.

Fluent Code Demo

While LINQ stimulates interest in fluent interface designs as a code consumer, it does not yield tremendous insight into their implementation. This section walks through enhancing an imaginary preexisting order processing application programming interface (API) by adding a fluent interface.

Why Bother?

I suspect that you will find code resembling this in many enterprises. There isn’t anything particularly wrong with it. Some might rate the supporting API quite highly since it allows developers to process orders without undue fuss.

          // Create the order

 

            var orderLines = new List<IOrderLineItem>

                {

                    new OrderLineItem {ProductId = 123, Quantity = 2, UnitPrice = 2.99},

                    new OrderLineItem {ProductId = 234, Quantity = 1, UnitPrice = 9.99}

                };

            var order = new Order

                {

                    CustomerId = 98765,

                    OrderLineItems = orderLines

                };

 

            // Apply taxes

 

            var taxCalculator = new TaxCalculator();

 

            if (taxCalculator.Apply(order))

                taxCalculator.Calculate(order);

 

            // Validate and process the order

           

            if (order != null && order.OrderLineItems != null)

            {

                var orderProcessor = new OrderProcessor();

                orderProcessor.Process(order);

            }

 

Despite the reasonableness of this code, it seems awkward for such a well-defined activity as processing orders. Why do developers need to spin up so many objects and write so much code for such a basic activity? Wouldn’t it make it easier to augment the order processing API with a fluent interface? Here is an example of what such a fluent interface might look like.

            var orderEngine = OrderEngine

                .Initialize()

                .Customer(98765)

                .AddLineItem(

                    new OrderLineItem {ProductId = 123, Quantity = 2, UnitPrice = 2.99 })

                .AddLineItem(

                    new OrderLineItem {ProductId = 234, Quantity = 1, UnitPrice = 9.99 })

                .Process();

How

We begin creating our fluent interface with our preexisting order processing API, as well as an appreciation for the enterprise developers’ order processing business knowledge. Based on that information, we can start coding the fluent interface. We stop when our developers find the new interface easier to use than the existing API.

Let’s describe what we need to code, phrased in fluent interface terminology. We need to define the order processing context and then incorporate the chained methods for order processing.

Step 1: Context

Our first attempt at creating the context begins with the new class OrderEngine. Within it, we reference and instantiate the essential order-processing classes from the API as shown below.

   public class OrderEngine

    {

        public ITaxCalculator TaxCalculator { get; internal set; }

        public IOrderProcessor OrderProcessor { get; internal set; }

        public IOrder Order { get; internal set; }

        public List<Func<IOrder, bool>> ValidateFunctions { get; internal set; }

 

        public static OrderEngineInitialize()

        {

            // Instantiate dependencies

            var orderEngine = new OrderEngine

            {

                Order = new Order(),

                TaxCalculator = new TaxCalculator(),

                OrderProcessor = new OrderProcessor(),

                ValidateFunctions = new List<Func<IOrder, bool>>()

            };

            orderEngine.Order.OrderLineItems = new List<IOrderLineItem>();

 

            // Set the order Id

            orderEngine.Order.OrderId = (new Random()).Next();

 

            // Add a simplistic null check

            orderEngine.ValidateFunctions.Add(o => o != null && o.OrderLineItems != null);

 

            return orderEngine;

        }

    }

 

Our only significant change from the original order processing code is to add support for augmenting validation via the ValidateFunctions property. As we will shortly see it allows OrderEngine to apply more the current non-null object checks.

At this point one could fairly describe OrderEngine as some form of a factory software pattern. Not until we add supporting extension methods does it achieve fledgling fluent interface status.

Step 2: Chained Methods

The OrderEngineExtension static class includes extension methods that allow developers to easily configure, enhance, and modify an OrderEngine instance. The first two methods establish the customer and what they bought.

   public static class OrderEngineEntensions

    {

        public static OrderEngine Customer(this OrderEngine @orderEngine, int customerId)

        {

            @orderEngine.Order.CustomerId = customerId;

 

            return @orderEngine;

        }

 

        public static OrderEngine AddLineItem(

           this OrderEngine @orderEngine, IOrderLineItem orderLineItem)

        {

            if (@orderEngine.Order == null)

                @orderEngine.Order = new Order();

 

            if (@orderEngine.Order.OrderLineItems == null)

                @orderEngine.Order.OrderLineItems = new List<IOrderLineItem>();

 

            @orderEngine.Order.OrderLineItems.Add(orderLineItem);

 

            return @orderEngine;

        }

 

While these two methods are simple, they have already made it easier for those developers using the interface to code an order. For example, AddLineItem ensures that the OrderEngine accepts the provided orderLineItem with throwing any exceptions. By adding null checks and automatic instantiation of OrderEngine , developers are subsequently neither obliged to write such code nor to worry about it.

The next extension method, Process, allows us to complete orders. If the code seems familiar, it is. The algorithm essentially mimics that of the original code for processing an order. Our fluent interface simply stuffed the gore into one method that developers no longer fret over.

       public static OrderEngine Process(this OrderEngine @orderEngine)

        {

            // Can't instantiate an order for processing; need an order with details.

            if (@orderEngine == null|| @orderEngine.Order == null)

                throw new InvalidOperationException("Processing not provided an Order.");

 

            if (@orderEngine.TaxCalculator != null

                && @orderEngine.TaxCalculator.Apply(@orderEngine.Order))

                    @orderEngine.TaxCalculator.Calculate(@orderEngine.Order);

 

            // Run thru any validation checks

            @orderEngine.Order.Valid = true;

 

            if (@orderEngine.ValidateFunctions != null)

            {

                foreach(var validateFunction in@orderEngine.ValidateFunctions)

                    @orderEngine.Order.Valid =

                        @orderEngine.Order.Valid

                            && validateFunction(@orderEngine.Order);

            }

 

            // Process the order

            @orderEngine.Order.DateProcessed = null;

 

            if (@orderEngine.Order.Valid)

                @orderEngine.OrderProcessor.Process(@orderEngine.Order);

 

            return @orderEngine;

        }

The following methods go beyond coding the basic order process. They’re in the spirit of building a fluent interface that allows developers to easily alter the default behavior of OrderEngine as expressed in the Initialize method. The first method facilitates swapping out the ITaxCalculator .

        public static OrderEngineUsing(

           this OrderEngine @orderEngine, ITaxCalculator taxCalculator)

        {

            @orderEngine.TaxCalculator = taxCalculator;

 

            return @orderEngine;

        }

       

The next one allows for incorporating additional custom validation checks when order processing.

        public static OrderEngine AddValidateFunction(

            this OrderEngine @orderEngine, Func<IOrder, bool> validationFunction)

        {

            if (validationFunction == null) throw new ArgumentNullException("validationFunction");

           

            if (@orderEngine.ValidateFunctions == null)

                @orderEngine.ValidateFunctions = new List<Func<IOrder, bool>>();

 

            @orderEngine.ValidateFunctions.Add(validationFunction);

 

            return @orderEngine;

        }

 

Taken together, these two methods simplify the trials and tribulations of working with a new tax feature. For example, imagine some orders require the magnificent TaxCalculatorV2. Unfortunately this incredible ITaxCalculator enhancement may create tax credits, and the business prefers not to lower the order total for any reason. Fortunately, our nascent interface handles this situation quite nicely as shown with orderEngineTaxing .

          var orderEngineTaxing = OrderEngine

               .Initialize()

               .Customer(56789)

               .Using(new TaxCalculatorV2())

               .AddValidateFunction(o => o.Tax > 0)

               .AddLineItem(

                    new OrderLineItem {ProductId = 123, Quantity = 2, UnitPrice = 2.99 })

               .AddLineItem(

                    new OrderLineItem {ProductId = 234, Quantity = 1, UnitPrice = 9.99 })

               .Process();

 

            var order = orderEngineTaxing.Order;

            Console.WriteLine("Order Id = "+ order.OrderId);

 

Step 3: Implicit Conversion (Optional)

There is something about the last code snippet that you can easily have missed: it shows that accessing an Order object is clunky. Why should a developer have to work through an OrderEngine ’s Order property to get at an Order ? Wouldn’t it be in the spirit of the fluid interface pattern to make such calls more intuitive? We can do this by adding the implicit operator to the Order class as shown below.

   public class Order: IOrder

    {

        public intOrderId { get; set; }

        public intCustomerId { get; set; }

 

        public List<IOrderLineItem> OrderLineItems { get; set; }

        public doubleTotalSale { get; set; }

        public doubleTax { get; set; }

 

        public boolValid { get; set; }

        public DateTime? DateProcessed { get; set; }

 

        public static implicit operator Order(OrderEngineorderEngine)

        {

            if (orderEngine == null)

                return new Order();

 

            return orderEngine.Order as Order;

        }

    }

 

Developers may now grab an Order with the down-side of having to abandon the magic of var variable typing.  If that loss seems acceptable, then the below certainly eases their coding burden.

          // Typing order as var generates a compile error.

            // var order = orderEngineTaxing;

            Order order = orderEngineTaxing;

            Console.WriteLine("Order Id = " + order.OrderId);

Step 4: Unit Tests (Optional)

Fluent interfaces do not alter the reality of unit testing: Nonetheless, writing tests with their help minimizes the woes of setup and configuration. Wouldn’t developers prefer to code the following test when working with an ITaxCalculator ?

          var orderEngineTest = OrderEngine

               .Initialize()

               .Customer(1111)

               .Using(new MockRepository().DynamicMock<ITaxCalculator>())

               .AddLineItem(

                    new OrderLineItem {ProductId = 2222, Quantity = 3333, UnitPrice = 44.44 })

               .Process();

 

            var testOrder = orderEngineTest.Order;

 

            Assert.IsNotNull(testOrder);

            Assert.IsTrue(testOrder.OrderId > 0);

Considerations

‘Coming up with a nice fluent API requires a good bit of thought.’

Martin Fowler 2005

Most “how to” technology articles gloss over real world implementation pitfalls. This one is no exception. However, you’re more likely to encounter a vexing design roadblock when implementing a fluent interface than a technical one. The problem is that the fluent interface is neither design pattern nor framework. It is a style of API; and as such suffers the same challenges you’d face when designing any API. Of course, the fluent interface introduces its own additional flavor of API design challenges.

Imagine our demonstration API several months later. After a few revisions of OrderEngine the typical code for placing an order resembles the following snippet.

            try

            {

                orderEngine = OrderEngine

                     .Initialize()

                     .Configure(OrderEngineConfiguration.Load())                  

                    .Customer(customerId)

                    .Using(

                        new TaxCalculatorFactory(saleDate, countryCode))

                    .AddLineItem(

                        new OrderLineItem

                            { ProductId = 123, Quantity = 2, UnitPrice = 2.99 })

                    .UpdateInventory()                                                               

                    .Process(ProcessingOptions.Async);

            }

            catch(OrderValidationException)

            {

                // Handle invalid orders

            }

 

Like the non-fluent order processing code shown earlier in this article there is nothing particularly good or bad about the above code. Nonetheless, it suggests a few commonly occurring deficiencies in its fluent-interface API design.

Gratuitous Extensions

API Design Guidelines

If unfamiliar with the challenges of writing an effective application programming interface (API) for .NET, MSDN provides a great starting point. The Cwalina and Abrams “Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries” book remains an impressive reference for beginners and experts alike.

At first glance, the new Configure method with its OrderEngineConfiguration parameter resembles a stroke of genius in object-oriented design. It allows developers to properly configure their instance of OrderEngine . By why do they need to do this? Couldn’t OrderEngine handle such mundane instantiation chores?

It isn’t easy to answer this question without talking to the developer that wrote this new extension method. Maybe without a significant refactoring effort, the act of changing OrderEngine initialization broke too many consuming applications? And maybe the developer didn’t have the time to refactor? Whatever the reason, it’s likely that Configure was unnecessary.

Context Confusion

The last two chained methods raise questions about the revised OrderEngine’s context. Developers now need to write more code and know more about placing orders then they did with the initial fluent interface. Has the order-processing context become needlessly confusing?

For example, why do developers now need to call UpdateInventory? What happens if they do not include this method? At first glance it looks superfluous, couldn’t a method like Process be called internally. Speaking of Process , why was the enumeration ProcessingOptions.Async added? Does it reflect some new order handling mechanics? If so, should developers care? And if they do care do they need to write different code for a synchronous ProcessingOption option?

Exception Mismanagement

Wrapping OrderEngine in a try/catch block highlights one of the more daunting design challenges of the fluent interface style. How does one handle runtime exceptions? Under the older declarative line-by-line style, developers trapped issues such as dodgy orders. Fluent interfaces typically assume responsibility for such pests. What happens if they don’t catch them?

The OrderEngine’s response to handling unforeseen validation issues appears to be a try/catch block. One suspects that there is a better solution. For example, developers could validate orders before processing them, or perhaps check the order state afterwards. Nonetheless, both of these tacks demand additional code, despite being esthetically more pleasing.

The Viscous Interface

You may find the latest release of OrderEngine to be a victim of a gratuitous extension, confused context, or mismanaged exception handling. It is certainly safe to question the ease of use of the API. For whatever reason, it seems to have lost its fluid nature. How does a fluent interface transform into a viscous mess?

Field experience suggests that fluent interfaces that are updated without vigilance will degrade over time; so quietly, in fact, that those developers that consume the API do not notice. The enterprise only becomes aware of the problem when developers who are unfamiliar with the API arrive, and complain about unwrapping the abstraction formally known as fluent. By then it’s too late though, the API is another example of code suffering from severe technical debt.

Too Big to Fluent?

The demonstration nature of OrderEngine deprives us the opportunity of implementing one of the more common design failures. Fluent interfaces may grow unwieldy with updates and new requirements to remain developer friendly. The API resembles a version of the infamous god class anti-pattern as the context struggles to handle too many scenarios and situations.

Experience managing configurations via fluent interfaces offers guidance for handling the bloated API. Many of these interfaces apply a “divide and conquer” strategy, a well-recognized refactoring solution to the god class. The following MSDN code snippet offers an example of such a design.

var builder = new ConfigurationSourceBuilder();

 

builder.ConfigureCaching()

       .ForCacheManagerNamed("MyCache")

       .WithOptions

         .UseAsDefaultCache()

         .StoreInIsolatedStorage("MyStore")

         .EncryptUsing.SymmetricEncryptionProviderNamed("MySymmetric");

Note how the ConfigurationSourceBuilder instance relies on a dedicated caching fluid interface for easing a complex configuration. Interested readers will find other such specialty configuration fluent interfaces, such as ConfigureCryptograpy, ConfigureData or  ConfigureExceptionHandling for the Enterprise Library.

Conclusion

Our review of fluent interfaces in C# covered a few ideas. First, we discussed the concept as an API style for improving the development experience. Second, that while fluent interface is a new idea, it is not technically demanding. And lastly, what building a fluent interface lacks in technical complexity it makes up for in design difficulty.

Tom Fischer

Author profile:

Tom Fischer designs and builds software solutions upon the Microsoft stack. And every so often he writes and presents some of the things he's learned in his trade over the past dozen years. His last such talk was at the OWASP AppSec USA 2011 conference in the Twin Cities, Minnesota."

Search for other articles by Tom Fischer

Rate this article:   Avg rating: from a total of 15 votes.


Poor

OK

Good

Great

Must read
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: Nice article
Posted by: Torsten (not signed in)
Posted on: Sunday, July 14, 2013 at 5:08 AM
Message: Always nice to see how to use something already known (here: extension methods) to create something new (here: fluent interface). Also good writing.

Thank you!

Subject: Chaining and fluent interfaces in C++
Posted by: AndyDent (view profile)
Posted on: Wednesday, July 24, 2013 at 10:27 PM
Message: I started using chaining after reading of the technique in 1994 in "The Design and Evolution of C++" http://www.stroustrup.com/dne.html where it was discussed as a viable alternative to keyword arguments. The ease of implementing chaining in C++ is why the standards committee didn't approve keyword arguments.

I used it very effectively in the composition interface of the 1997 OOFILE report writer where it made an easy way for people to add different formats to report objects. This API was designed with a mailing list as focus group, aimed at usability of the API. The chained interface was very popular.

Subject: Great intro to fluent design
Posted by: msorens (view profile)
Posted on: Friday, July 26, 2013 at 1:05 PM
Message: Really enjoyed your article, Tom. Just wanted to point out there are a couple minor rendering issues: Initialize() and Using() both need a space before the method names in their definition. We have to keep the editors on their toes!

Subject: Editing Errors?
Posted by: Tom Fischer (view profile)
Posted on: Friday, July 26, 2013 at 1:13 PM
Message: Must confess, the spacing errors were my doing. 
The "good writing" aspect of the article is very much due to the Editor. (This guy is awesome if anyone is thinking of writing for simple talk!)

Subject: @ prefix
Posted by: munter (view profile)
Posted on: Saturday, August 24, 2013 at 12:15 PM
Message: just to humour me, can you explain why the @symbol prefix is needed for the orderengine vars? is orderengine reserved??

Subject: sorry
Posted by: munter (view profile)
Posted on: Saturday, August 24, 2013 at 12:19 PM
Message: ok.. its for calling a var by same name as existing class... i think 😊

Subject: @prefix Naming
Posted by: Tom Fischer (view profile)
Posted on: Saturday, August 24, 2013 at 4:01 PM
Message: You're correct about the naming convention; an idea I picked up from a (clever) developer on my project.

Subject: Fluent syntax
Posted by: v008370 (view profile)
Posted on: Monday, October 07, 2013 at 10:05 AM
Message: I understand the aims Martin alluded to. Why on earth is the code then filled with semi colons, curly brackets and @ signs. I understand this is the environments we use nowadays but the very essence of the language in the code samples goes completely against readable code.

Excellent article all the same, I just can't help but feel we're still going backwards rather than forwards in making code readable and accessible.

 

Top Rated

Acceptance Testing with FitNesse: Multiplicities and Comparisons
 FitNesse is one of the most popular tools for unit testing since it is designed with a Wiki-style... Read more...

Acceptance Testing with FitNesse: Symbols, Variables and Code-behind Styles
 Although FitNesse can be used as a generic automated testing tool for both applications and databases,... Read more...

Acceptance Testing with FitNesse: Documentation and Infrastructure
 FitNesse is a popular general-purpose wiki-based framework for writing acceptance tests for software... Read more...

TortoiseSVN and Subversion Cookbook Part 11: Subversion and Oracle
 It is only recently that the tools have existed to make source-control easy for database developers.... Read more...

TortoiseSVN and Subversion Cookbook Part 10: Extending the reach of Subversion
 Subversion provides a good way of source-controlling a database, but many operations are best done from... Read more...

Most Viewed

A Complete URL Rewriting Solution for ASP.NET 2.0
 Ever wondered whether it's possible to create neater URLS, free of bulky Query String parameters?... Read more...

Visual Studio Setup - projects and custom actions
 This article describes the kinds of custom actions that can be used in your Visual Studio setup project. Read more...

.NET Application Architecture: the Data Access Layer
 Find out how to design a robust data access layer for your .NET applications. Read more...

Calling Cross Domain Web Services in AJAX
 The latest craze for mashups involves making cross-domain calls to Web Services from APIs made publicly... Read more...

Web Parts in ASP.NET 2.0
 Most Web Parts implementations allow users to create a single portal page where they can personalize... Read more...

Why Join

Over 400,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.