abstracted from the DSL users, so they
can focus on building the business
functionalities and using the syntax
and semantics of the domain.
In our example, the combinator
orElse of PartialFunction hides all
details of composing multiple strategies of the cash-value calculation logic.
Also, the DSL can be extended for composition with custom logic without any
incidental complexity. Thus, the user
can focus on implementing the custom abstractions.
We have discussed in detail how to
embed a DSL into its host language
and make use of the type system to
model domain-specific abstractions.
You can also design embedded DSLs
using dynamically typed languages
such as Groovy, Ruby, or Clojure.
These languages offer strong meta-programming facilities that allow
users to generate code during compile time or runtime. DSLs developed
using these features also lead to enhanced developer productivity, since
you get to write only the core business
functionalities using the DSL, and the
verbose boilerplates are generated by
the language infrastructure. Consider
the following example of defining a domain object in Rails:
// pf is the user supplied custom
logic
lazy val cashValue = { pf: Cash-
ValueCalculationStrategy =>
pf orElse cashValueComputation
}
This DSL is very intuitive: it invokes
the custom strategy that the user sup-
plied. If it fails to find a match, then it
invokes our earlier strategy. Consider
the case where the user defines a cus-
tom strategy for the Tokyo market and
would like to use it instead of the de-
fault fallback strategy:
of the exposed API.
val pf: CashValueCalculation-
Strategy = {
case Tokyo => { trade =>
//.. custom logic for Tokyo
}
}
Now the user can do the following
to supply the preferred strategy to the
calculation logic:
val trade = //.. trade instance
cashValue(pf)( trade.market)(trade)
Conclusion
The main value DSLs add to the development life cycle of a project is to encourage better collaboration between
the developers and business users.
There are multiple ways to implement
DSLs. Here, I discussed one that uses
embedding within a statically typed
programming language. This allows
you to use the infrastructure of the
host language and focus on developing domain-friendly linguistic abstractions. The abstractions you develop
need to be composable and extensible,
so the user can build larger abstractions out of smaller ones. Finally, the
abstractions need to speak the domain
vocabulary, closely matching the semantics the domain user uses.
Our example uses the rich type system of Scala and its powerful functional abstractions to design a DSL that is
embedded within the type system of
the host language. Note how we express domain-specific rules (such as
the need for the calculation logic to
vary with specific markets) declaratively, using only the constraints of the
static type system. The resulting DSL
has the following characteristics:
˲ ˲ It has a small surface area so that
it’s easier to comprehend, troubleshoot, and maintain.
˲ ˲ It is expressive enough to make the
business user understand and verify
the correctness.
˲ ˲ It is extensible in that it allows custom plug-in logic (which may include
domain-specific optimizations) to be
composed into the base combinator in
a completely noninvasive way.
class Trade < ActiveRecord::Base
has _ one :ref _ no
has _ one :account
has _ one :instrument
has _ one :currency
has _ many :tax _ fees
## ..
validates _ presence _ of :account, :instrument, :currency
validates _ uniqueness _ of
:ref _ no
..
end
Related articles
on queue.acm.org
no Source Code? no Problem!
Peter Phillips, George Phillips
http://queue.acm.org/detail.cfm?id=945155
Languages, Levels, Libraries, and Longevity
John R. Mashey
http://queue.acm.org/detail.cfm?id=1039532
Testable System Administration
Mark Burgess
http://queue.acm.org/detail.cfm?id=1937179
Productivity and DSLs
An embedded DSL encourages pro-
gramming at a higher level of abstrac-
tion. The underlying infrastructure of
the host language, the details of the
type system, the lower-level data struc-
tures, and other concerns such as re-
source management are completely
This example defines a Trade ab-
straction and its associations with
other entities in a declarative way. The
methods has _ one and validates _
presence _ of express the intent
clearly without any verbosity. These are
class methods in Ruby6 that use meta-
programming to generate appropriate
code snippets during runtime. The
DSL that you use for defining Trade
remains concise, as well as expressive,
while all incidental complexities are
abstracted away from the surface area
References
1. ghosh, D. DSLs in Action. Manning Publications, 2010.
2. odersky, M., spoon, l., Venners, B. Programming in
Scala. artima, 2010.
3. fowler, M. Domain Specific Languages, addison
Wesley, 2010.
4. fowler, M. Introducing Domain-specific languages.
Dsl Developer’s conference, 2009; http://msdn.
microsoft.com/en-us/data/dd727707.aspx.
5. scala; http://www.scala-lang.org.
6. thomas, D., fowler, c., hunt, a. Programming Ruby
1. 9. Pragmatic Press, 2009.
7. coplien, J. o. Multiparadigm Design in C++.
addison-Wesley Professional, reading, Pa, 1988.
8. evans, e. Domain-Driven Design: Tackling Complexity
in the Heart of Software. addison-Wesley Professional,
reading, Pa, 2003.
Debasish Ghosh ( dghosh@acm.org) is the chief
technology evangelist at anshinsoft, where he specializes
in leading delivery of enterprise-scale solutions for clients
ranging from small to fortune 500 companies. he is the
author of DSLs In Action (Manning, 2010) and writes a
programming blog at http://debasishg.blogspot.com.
© 2011 acM 0001-0782/11/07 $10.00