Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
The Fluent Interfaces or DSLs Conundrum

Maybe I'm just behind the curve on this one, but I don't understand the fascination with building internal DSLs (or the so-called fluent APIs) in C#. The argument is usually that they are expressive and readable but, since these are subjective assessments, I happen to disagree on both counts. They would need to bring some other values to the table to convince me to use them without being annoyed.

I think C# is not well suited for this task and maybe we should just stop trying to imitate what we see in other languages.

The idea that we can create classes named Is or Returns or With just rubs me the wrong way. At the present moment I hope this trend is just a fad. I'm willing to be proven wrong and suddenly "get it." Time will tell.

Take the following snippet using Rhino Mocks.

With.Mocks(mocks).Expecting(() =>
{
    Expect
	.Call(dependency.GetSomething("p1"))
	.IgnoreArguments()      
	.Repeat      
	.Once() 
	.Return("result");
    dependency.DoSomething();
})

Imagine yourself trying to setup this expectations. You know that when calling dependency.GetSomething("parameter") it should return "result". How would you discover that the With class is your starting point? Then look at the lambda code. I'd imagine your first reaction would be to look for a method in Expect that would take both the method call and the result. I'd say your first reaction is appropriate, after all this is still supposed to be C# code.

Maybe the desire behind these fluent interfaces is to make the API have a little more keyword wannabes at the expense of tolerating all the punctuation and ceremony that comes along.

In other languages this type of APIs are more popular because the language lends itself more adequately to this design. I'm not an Objective-C programmer but take a look at this line.

[expect call:[dependency getSomething:@"p1"], repeat:1, returns:@"result"];

Or in Ruby, probably leveraging the method_missing goodness behind the scenes:

dependency.expectCall.getSomething("p1", 
	:ignore_arguments => true, 
	:repeat => :once,
	:returns => "result"
	)

For a Objective-C or Ruby developer the above translations probably read more natural than the C# version for a C# developer.

I'm using Rhino Mocks as an example because it is fairly popular. I'm not trying to pick on it. Just to give another example of a fluent interface, recent versions of NUnit come with the Constraint Model for assertions:

Assert.That( ex3, Is.Not.SameAs( ex1 ) );

Again, classes, properties, and methods being used as quasi-operators, trying to blur the lines between language features and the custom API. But C# fights back and makes clear that it is not open for these kinds of extensions and throws a bunch of punctuation at you. To me this just doesn't feel fluent. It doesn't read like English nor like C#. It's more like some schizophrenic middle-of-the-road compromise.

It's possible that this desire to write fluent interfaces and DSLs becomes just a gateway to a more appropriate language like IronRuby or even Boo (to stay in the .Net universe.) Or, who knows, maybe C# changes to be more friendly to these designs. I will not be surprised if, in a few years, we look back at all these implementations and feel a little embarrassed for trying so hard to recreate an experience that is just not viable. Equally, I will not be surprised if I'm proved wrong, jump on the bandwagon, and regret having ever written this piece.


Posted 05-21-2008 4:03 PM by sergiopereira
Filed under: ,

[Advertisement]

Comments

Jeff Perrin wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-21-2008 8:29 PM

Wholeheartedly agree. Fluent interfaces read relatively nicely, but are brutal when you're just trying to write something. My current project uses Toplink as an ORM, which has a fluent interface for creating expressions/queries to the database. Not a single developer on a team of 45 would say they enjoy writing them.

Reflective Perspective - Chris Alcock » The Morning Brew #99 wrote Reflective Perspective - Chris Alcock » The Morning Brew #99
on 05-22-2008 3:20 AM

Pingback from  Reflective Perspective - Chris Alcock  » The Morning Brew #99

Mike wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-22-2008 6:59 AM

As a demonstration could you provide an example of the rhino mocks snippet above using a non fluent API?

Jak Charlton wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-22-2008 6:59 AM

Fluent interfaces make some code elegant, but like a lot of things, they can be horribly abused. In some cases every method becomes part of a fluent interface, taken to it's logical conclusion, you could code the entire applciation in one single expression.

With power comes great responsibility

sergiopereira wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-22-2008 8:11 AM

@Mike, using a non-existing API:

using(var expect = new ExpectationContext(mocks))
{
	expect.CallOnce(
		dependency.GetSomething("p1"), 
		"result",
		Arguments.Ignore);
	dependency.DoSomething();
}
Jon Rowett wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-23-2008 5:00 AM

just wanted to say i really liked this post, especially the last paragraph!

Bryan Watts wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-23-2008 10:55 PM

C#: Assert.That( ex3, Is.Not.SameAs( ex1 ) );

English: Assert that ex3 is not the same as ex1

-----------

Considering the importance of spaces to tokenization, I view "." as minimally invasive and easily ignored noise.

Words, by nature, work in context. Fluent interfaces capture that concept. Think of it as "inversion of control for program elements." :-)

sergiopereira wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-23-2008 11:22 PM

I.See(We.Should => { Start.Writing(English).With.Extra<Punctuation>) }, Because.It.Is(Barely).Noticeable) || Maybe.Not;

IoC? Only that we are not in control of anything. We are at the mercy of the API designer, which is no different from a regular API.

Bryan Watts wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-23-2008 11:31 PM

English is read by humans. We make great inferences.

Computers make no inferences. They are explicit and so we must translate how we speak to how they interpret. We're not making English harder; we're making assembly bits and bytes easier.

I meant IoC for program elements themselves, their intended usage. Traditionally a method is "DoWith". Contextually, the "With" is implied, meaning you only need write the "Do".

GetXXX is desired because it makes the concept easier for you the developer, not me the API consumer.

sergiopereira wrote re: The Fluent Interfaces or DSLs Conundrum
on 05-24-2008 12:18 AM

Bryan, I agree with you. I'm not challenging the usefulness of fluent APIs or internal DSLs. I actually like them. But not in C# as it stands. I think these APIs in C# bear a lot of undesirable artifacts.

From that perspective, any fluent API in C# already starts in disadvantage when compared to other programming languages.

Maybe a simple thing like named arguments could help C# be more welcoming to this.

The Inquisitive Coder » Blog Archive » Weekly Links 5 wrote The Inquisitive Coder &raquo; Blog Archive &raquo; Weekly Links 5
on 05-24-2008 3:30 AM

Pingback from  The Inquisitive Coder  &raquo; Blog Archive   &raquo; Weekly Links 5

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)