I think the term ‘Domain Specific Language’ (DSL) is starting to become over-used and is being applied to things that aren’t really languages at all.
A Tale of Two Designers
When I think about explaining DSLs to people, the examples that spring to mind are languages like SQL, Regular Expressions, maybe even BNF, or CORBA IDL. And if I think about Why these languages exist, I imagine that somewhere, at some time, somebody thought:
I’m going to design a new language that is specifically crafted for solving this particular problem.
I like DSLs. Or maybe it would be more accurate to say I love them. They are powerful, expressive, and allow people who are eager to describe a solution or encode information (be they programmers or otherwise) to escape the complexities of imperative paradigms and Von Neumann thinking, permitting a strong focus on the actual problem.
In contrast to the above, the way in which I’ve most frequently seen the term DSL used of late is from people thinking something more like this:
I’ve written a library of code, and I’m going to expose the API for that library so that code that uses the API is very succinct and readable.
I might also make it possible to write code against the API that looks less like code and reads more like English.
It’s the prolific use of ‘DSL’ to describe this type of project that I’ve become increasingly irritated by.
What’s Your Goal?
I see three main distinctions between these two approaches: the starting point, the end result, and the client.
For the first designer, the starting point is designing a language around the problem, the end point is the language itself and the client is anyone who wants to solve a problem in the domain of that language and is able to learn the language.
For the second designer, the starting point or idea is a library of code (not a language) and the end point is an API (not a language). Finally, and perhaps most importantly, the client of this designer is not anyone who want to solve a problem in this domain, but only people who write code in the programming language(s) that their library targets.
If I were pressed to provide names for these two ideas, I would call them the language-oriented approach and the code-oriented approach. In fact, the term language-oriented programming is already in use, and is pretty much what I’m talking about here when I look at the first designer.
Is Every Good API a Language?
I have no problem with the aims of the second designer here – I think those aims are great! APIs should definitely facilitate client code that is succinct and readable. But does allowing succinct and readable use of a library instantly render the API of the library to be a language? Isn’t that just… good code?!
I’m happy to concede that, with the flexibility permitted by programming languages like Scala and Ruby, there is the opportunity for someone to use language-oriented thinking to first design a language and then fully implement it using the compiler or interpreter of an existing programming language. However, when a search for repositories mentioning DSL on GitHub returns over 23,000 results, I’m skeptical that many of these projects have invented a new language.
The key practical problem I have with the library-as-DSL idea is that it’s usually a leaky abstraction. In my mind, to label something a DSL is to imply you’ve provided a language for solving a problem. However, if in order to use the DSL one also needs to learn a programming language, then what the library provides isn’t really a language for solving the problem, but just an extension to an existing language – usually a general-purpose 3GL programming language. These programming languages are not specific, nor are their features constrained to the domain of the problem, but knowledge of the programming language will usually be a prerequisite for being able to use such libraries.
Here are some of my ideas for how you can spot the difference between what is a DSL and what isn’t. The more of the following questions to which you can answer ‘Yes’, the more likely it is that I would think what you’ve created is a DSL. The more of them to which you answer ‘No’, the more likely it is that I would think you’re misusing the term if you applied it to your library.
- Did you start your project by designing the language rather than writing code?
- Is your language narrow in the scope of problems it aims to help solve?
- Is your DSL specified in its entirety in a single document? (not source code)
- Is your DSL described somewhere other than in generated API documentation?
- Could I write solutions in your DSL without knowing another programming language?
- Would a domain expert who is not a programmer be able to make sense of a solution written in your DSL without knowledge of the language spec.?
Personally, I think we’d do well to come up with another name for the (excellent) practice of creating APIs for libraries that make for succinct, readable client code, and then to keep this concept separate from DSLs. There are definitely similarities here to the Fluent Interface pattern, though it seems to be quite specifically about method chaining. I’m going to offer the suggestion of expressive interface, though I’m totally open to other suggestions.
Of course, language is a dynamic thing and it’s entirely possible that the common understanding of ‘DSL’ has moved on from what I understood it to be when I first came across it a decade ago and I’m just the stubborn one who prefers what it used to mean. I’m very interested to know what other people think, though, so let me know whether you agree or not.
Image credit: Clown Talk (c. 1905) by Ana y Esteban