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.