DSL vs. Fluent interface: Compare & Contrast
Let us take a simple example, scheduling tasks, and see how we can demonstrate the difference between the two. From the perspective of the client, what do we want from a scheduling tasks?
- Define named tasks
- Define what happens when the task is executed
- Define when a task should execute
- Define conditions to execute the task
- Define recurrence pattern
Now, let us look at the fluent interface for this:
new FluentTask("warn if website is not alive")
.Every( TimeSpan.FromMinutes(3) )
.StartingFrom( DateTime.Now )
.When(delegate
{
return WebSite("http://example.org").IsAlive == false;
})
.Execute(delegate
{
Notify(“admin@example.org”, “server down!”);
});
And contrast that with the DSL sample:
task "warn if website is not alive":
every 3.Minutes
starting now
when WebSite("http://example.org").IsAlive is false
then:
notify "admin@example.org", "server down!"
The second version has far less line noise, it a lot more clearer, and allows me to grow my DSL as I get more information, without hitting the language limits.
It also brings to mind another issue, who define these tasks and when?
Most of the time, I use a DSL as a way to setup and configure a runtime engine. I might talk later about imperative vs. declarative DSL. I tend to write my DSL at a different time than the code.
In fact, if you have no need to ever do something externally, and a fluent interface manages to express the ideas that you have clearly enough, than you probably should just use that.
If you need to do things externally, than a DSL is the place to look for. In fact, if you feel the urge to put XML into place, as anything except strict data storage mechanism, that is a place to go with a DSL.