Why use a DSL?
Recently, I was stuck in an airport with some reservation problems. As a gate agent navigated the airline's computer system using the graphical menus, my hopes of making the flight diminished. Then an expert agent showed up, and she knew just what commands to use. She got behind the menus and started interacting with a text-driven interface that was rather terse, but gave her more commands to work with, and ultimately more control of the application. In no time she got me on my way.
A GUI makes an average user productive, but can slow down an expert user or a user very fluent with your application and its domain. You don't want to make the novice productive and slow down an expert in the process. I am not discouraging the use of GUIs; I am merely pointing out that the GUI is not always the most productive alternative.
The future of DSLs |
---|
Martin Fowler argues that applications will eventually come to use several small and limited DSLs instead of one big general-purpose language. Ola Bini argues that "three language layers will emerge in large applications": A small, stable layer on which the rest of the application is built; a substantial dynamic layer where most functionality lies; and a third domain layer, built using DSLs. |
Richard Pawson and Robert Matthews introduced the concept and framework that they called Naked Objects, in which they auto-built a thin object-oriented user interface (OOUI) from a domain model. The OOUI exposed the behavior of domain objects so that users could interact with them directly. This type of user interface is well-suited for applications that organizations use internally. Such a UI is a tad crufty but the simplicity means you can create it more quickly. And, with proper training, users can access all of the application's capabilities, because the underlying domain model is exposed.
The goal of DSLs is similar -- to provide a highly effective interface that allows users to interact with your application. The interface can be graphical or textual.
A DSL is highly expressive, simple, and concise at the same time. This can help the user of an application be more productive. A DSL is designed to be very intuitive and fluent for a domain expert to use (more about this in the second article in this series). It is designed with the convenience and productivity of users -- the domain experts, within the context of the domain -- in mind.
External and internal DSLs
A DSL may be classified as external or internal, depending on how it is designed and implemented.
An external or free-standing DSL is designed to be independent of any particular language. As an author of such a DSL, you pretty much decide on the syntax. You are on your own when it comes to defining the grammar and parsing the syntax. You can use any language and tools to implement your DSL -- you could use Java and ANTLR, for instance. You have the complete flexibility to choose the syntax -- both the pleasure and pain of developing and implementing the language are all yours. (Speaking from experience, I had the "immense pleasure" of working with lex and yacc to maintain a grammar for a keyword input file -- an external DSL -- in a project I worked on years ago.)
An internal or embedded DSL, on the other hand, is designed and implemented using a host language. The good news is you don't have to worry about grammar, parsers, and tools to do the heavy lifting. However, you are constrained by the host language, and your DSL is influenced by its host's flexibility, limitations, and idiosyncrasies. The challenge with an internal DSL is to tactfully design the language so that the syntax is within the confines of what the host language allows, yet is as expressive, concise, and fluent as you desire.
The two different kinds of DSLs both have pluses and minuses. An external DSL gives you the liberty to design the syntax of your language in exactly the way you like. You can select the language's symbols, operators, constructs, and structure as you please to fit your domain. On the downside, you have to define the grammar for your language. You also have to create a compiler to parse and process the syntax and map it to the semantics you expect. An external DSL gives you a lot of flexibility, but you have to take the time to do the hard work of compiling it.
An internal DSL rides on the syntax of a host language, so you don't spend any time or effort worrying about compiling or parsing. You do need to spend a significant amount of time and effort designing the syntax of your DSL, however, as you are largely constrained by the host language. You want to chose a host language that is highly flexible and has as few restrictions and idiosyncrasies as possible. To effectively implement an internal DSL, you have to exploit the metaprogramming capabilities of your host language.
Today, external DSLs give you better control than internal DSLs when validating DSL syntax. Because you take the effort to define the grammar for your external DSL, that effort also serves to validate the syntax. This is harder to do with an internal DSL because the code is often processed dynamically. You will have to do extensive error checking and do the validation yourself.