Nov 12 2009

Is my code Fluent?

As developers, we all have a duty to write elegant code, or at least "try". This notion is certainly subjective and I do not intend to either name all the approaches to achieving elegance nor the merits for doing so, but for this Post just assume it's true. In the last couple of years there has been a lot of movement towards a pattern commonly referred to as Fluent. While not a new pattern, this recent resurgence has really provided a lot of advantage to the community by injected a much needed dose of elegance, and in the managed code space this is even easier than ever. So what is Fluent anyways?

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code.
- Wikipedia (http://en.wikipedia.org/wiki/Fluent_interface)

There are a lot of Posts out there on this subject so I will not bore you by regurgitating the same type of material. What is needed is a succinct example of two practical patterns you can use to implement Fluent interfaces on your own. With that said, I would encourage you to read Martin Fowler's description of Fluent as a Domain Specific Language (DSL). Lets start with the most commonly suggested pattern, which generally involves making Business Objects or Domain Entities natively Fluent.

public sealed class FluentComment
{
    public string CommentedBy { get; private set; }
    public string Comment { get; private set; }
    public string CommentorsEmail { get; private set; }
    public ushort Rating { get; private set; }

    public FluentComment By(string commentorsName)
    {
        CommentedBy = commentorsName;
        return this;
    }

    public FluentComment Says(string comment)
    {
        Comment = comment;
        return this;
    }

    public FluentComment RatedYou(ushort rating)
    {
        Rating = rating;
        return this;
    }

    public FluentComment CanBeContactedAt(string commentorsEmail)
    {
        CommentorsEmail = commentorsEmail;
        return this;
    }

    public void SubmitComment()
    {
        //Validate and Save comment to repository
    }
}
 

Here is how you would use our new Fluent interface:

var comment = new FluentComment();
comment.By("Joe")
        .Says("Very elegant!")
        .RatedYou(1)
        .CanBeContactedAt("joe@AnEmailAddress.info")
        .SubmitComment();

Here are some key things to note:

  • Fluent is essentially a Method-chaining pattern.  You can see that each Fluent method returns the instance being called after applying actions and/or data inside the same instance
  • We expose not only the Fluent methods, but also properties to expose instance data being maintained by the object. The names of properties should avoid using the same Fluent taxonomy (e.g. terminology) and adopt a naming convention that is complementary but more appropriate for typical property access

As you can see in the above pattern, making interfaces Fluent can lead to the addition of a lot of code, and once you have made this investment it can make it difficult to back out. This pattern can also be difficult to achieve if you are trying to back a Fluent approach into an existing code base.

So what if you want to add Fluent to an existing product? Here comes the second pattern. In this approach we take advange of Extension Methods added to .NET 3.0. Lets assume you have the following existing Business Object:  

public sealed class NonFluentComment
{
    public string CommentedBy { get; set; }
    public string Comment { get; set; }
    public string CommentorsEmail { get; set; }
    public ushort Rating { get; set; }

    public void SubmitComment()
    {
        //Validate and Save comment to repository
    }
}

Using Extension Methods, we add the same Fluent support shown in the first pattern. 

public static class FluentCommentExtensions
{
    public static NonFluentComment By(this NonFluentComment instance, string commentorsName)
    {
        instance.CommentedBy = commentorsName;
        return instance;
    }

    public static NonFluentComment Says(this NonFluentComment instance, string comment)
    {
        instance.Comment = comment;
        return instance;
    }

    public static NonFluentComment RatedYou(this NonFluentComment instance, ushort rating)
    {
        instance.Rating = rating;
        return instance;
    }

    public static NonFluentComment CanBeContactedAt(this NonFluentComment instance, string commentorsEmail)
    {
        instance.CommentorsEmail = commentorsEmail;
        return instance;
    }
}

Once again, usage is exactly the same:

var comment = new NonFluentComment();
comment.By("Joe")
        .Says("Very elegant!")
        .RatedYou(1)
        .CanBeContactedAt("joe@AnEmailAddress.info")
        .SubmitComment();

This second pattern has a lot of advantages, and I would suggest using this pattern even when you are building something from scratch, since it makes the code a lot more flexible.

  • The application of a Fluent interface is completely separate and as a result can be treated as a separate area of concern. This will make changing, extending, or removing Fluent features a lot easier
  • The division of Fluent from the Business Object makes testing each area in isolation a lot easier
  • If you intend to follow an IoC pattern AND you do not indent any one concrete implementation to have to implement your fluent expectations, then this pattern is ideal

One last note. If this starts to feel like you're following a CSLA pattern for your Domain Entities, you're not insane. It does feel very similar, although; strictly speaking; you can continue to follow other patterns such as Domain Driven Design (DDD) and still achieve Fluency. Take DDD as an Example. To submit your Domain Entity (or Value Object) to the associated Domain Repository inside your Fluent interface, you could do something like this (note: this is using a Provider as the Domain Repository):

public void SubmitComment()
{
    Comments.Provider.Submit(this);
}
   

or

public void SubmitComment(string providerName)
{
    Comments.Providers[providerName].Submit(this);
}
   

Technically speaking, you are still following the DDD Pattern above and you have maintained Fluency.

So that's all there is to it. If you do a little Googling you will find a wealth of information on when it is worth following this pattern. I hope this helps someone.

Tags:

Comments

1.
trackback DotNetKicks.com says:

Is my code Fluent?

You've been kicked (a good thing) - Trackback from DotNetKicks.com

2.
pingback blog.cwa.me.uk says:

Pingback from blog.cwa.me.uk

The Morning Brew - Chris Alcock  » The Morning Brew #523

3.
pingback topsy.com says:

Pingback from topsy.com

Twitter Trackbacks for
        
        Smelser.NET | Is my code Fluent?
        [smelser.net]
        on Topsy.com

4.
Erik Forbes Erik Forbes United States says:

I don't know why I hadn't though to use extension methods this way. Thanks =)

Comments are closed