Another great presentation at Architecture & Design world was Neal
Ford's presentation on Domain Specific Languages (DSLs) . As the title
suggests Neal gave examples both in static languages (Java) and Dynamic
ones (Groovy, Ruby).
One interesting observation Neal made was
that humans tend to create DSLs in real life whenever they (ok, we :))
have any non-trivial interaction or behavior. Neal gave sevaral
examples such as the Starbuck's order taking ("Venti Iced Decaf with
whip...") , musicians and a few others.
The next important point
was contrasting ("classic") APIs and DSLs. The main difference is that
the context is implicit and not repeated
A key technique for
building DSLs Neal mentioned was Fluent Interfaces. Fluent Interfaces
means modeling the API so that lines of code are readable English-like
sentences. The fluency comes from the easier readability by the
interface user.
Fluent Interfaces, now that's a novel idea -
what would a fluent interface look like, hmm, wait, I have an idea.
Here are 3 samples that come to mind
DIVIDE x BY z GIVING y ROUNDED
INSPECT data REPLACING ALL "foo" BY "bar
READ someFile AT END SET eof TO TRUE If you haven't guessed the statements above are in ...Cobol (by the way pardon the caps that's Cobol conventions..)
So ok, it isn't a new idea, but it is interesting to see it is making a comeback
Anyway
one area where we see a lot of fluent interfaces emerging is
configuration (mainly as an alternative to those lengthy XML files).
For instance the following is an excerpt of configuring
Restlet components (taken from my
Edge Component pattern paper):
Builders.buildContainer()
.addServer(Protocol.HTTP, portNumeber)
.attachLog("Log Entry")
.attachStatus(true, "webmaster@mysite.org", "http://www.mysite.org")
.attachHost(portNumber)
.attachRouter("/orders/[+")
.attach("/getAll$", getAllRestlet).owner().start();
.attach("/getLast$", getLastOrderRestlet).owner().start();
Note that this example also uses another fluent interface/DSL technique which is method chaining.
Dynamic languages make it even easier to write DSLs since they provide a lot of extension capabilities (see my previous post on
OCP in Ruby), are less strict about types, allow reopening classes etc.
Oneexample for a Ruby DSL is
RSpec which is a framework to support
Behavior Driven Development (BDD) in Ruby - The example below shows an excerpt for defining specifications for an
eight-ball game
require 'eight_ball'
describe Eight_ball do
before(:each) do
@eight_ball=Eight_ball.new
end
.
.
.
it "should lose if 8-ball sinked in pocket other than called" do
[1,2,3,4,5,6,7].each ( | val | @eight_ball.sink(:player =>"Player1", :Ball=> val)
@eight_ball.call(:player => "Player1", :pocket => :upper_left)
@eight_ball.sink(:player => "Player1", :Ball => 8, :pocket =>:middle_left)
@eight_ball.game_status.should == :ended
@eight_ball.player_status("Player1").should == :lost
end
end
By the way Joe Ocampo
built a very nice port for rbehave (another Ruby BDD framework) to .NET 3.5 by extending NUnit which has a very Ruby-like syntax
Anyway, the DSLs demonstrated by Neal provide a very good example
of the difference between dreaming big and actually doing stuff in the
small. The counter example for that are "Software Factories". As I
wrote here
about a year and half ago Software
Factories is not a new idea - see for example "Software reuse: From
Library to Factory" by M. L. Griss (published in 1993(!)) which talks
about "Software Factories" and "Domain Specific kits": components,
frameworks, glue languages etc. The current Microsoft incarnation of
Software Factories takes a similar approach focusing on Domain Specific
Languages, Frameworks but also adding important aspects like multiple
viewpoints, patterns and designers. The idea is that building on
modern technologies, as well as learning from the mistakes from sister
approaches to code generation (OMG's MDA, in case you are wondering)
will enable us to build something that is useable.
Microsoft
seems to be taking some steps in the right direction (GAT is probably
the best example). Nevertheless there is still a long way to go before
we can realize the dream of "factories" for vertical applications
Unlike
small code based DSLs - the modeling based approaches of software
factories, MDA etc. aim too high and thus provide much less value or
suffer too much from the generation gap (the code generated is too
generalized or far off from the actual need of the solution). Another
problem with software factories/ MDA DSLs is the modeling (i.e.
diagrams) - they say a picture is worth a thousand words. This is true
if you treat models as sketches you can raise the level of abstraction
by as much as you want and convey ideas with less clutter. However when
you need to make the model very specific so it would allow code
generation - you get to a stage where it is more convenient to do it in
code and rely on generated or pre-built DSL or framework
Lastly you can
download Neal's presentation (in PDF form) from
his site