Wednesday, November 25, 2009

RE: The Hidden Costs of Domain-Specific Languages

Today, Johan Den Haan pointed me to a post about "Hidden Costs" of DSLs via twitter.
The post starts with the following statement:
While I am a big fan of Domain-Specific Modeling, I am openly not in favor of Domain-Specific Languages.
... which leaves me puzzled. I'm pretty sure that the DSM guys call their abstractions DSLs as well.
Anyway, the post itself is not particularly interesting, but at the end of it there are a couple of questions about DSLs. This sort of questions which I've heard often and which contain a lot of miss- and preconceptions. Thought it was a good opportunity to answer them.

So here are the questions and my answers:
If we take so much time to master a general purpose language, should we invest a comparable amount of time in limited-use languages (i.e. DSL)?
No, you shouldn't and you won't. DSLs are much easier to learn, since they are limited and focused. The important thing is that you have to understand the domain. But that is necessary in any case, no matter if you translate everything to a general purpose language or write it down like it is meant to be (i.e. using a DSL). If you know the domain very well, but are not able to grasp the DSL, than the DSL might not be that good.
How can we get support for a DSL, apart from its own creators?
How can you get support for an API, apart from its creator? Well, by looking at the code or any existing documentation, or by asking any other users. In many aspects DSLs are comparable to libraries or frameworks.
Where’s community support?
It depends on whether it is a widely used DSL (i.e. there is a community) or one you use and have defined in your one-man project. For the DSLs used in Ruby on Rails there's much community support, for instance. Same for the DSLs we have in Xtext.
Where's the community support for your homegrown libraries?
What happens after the departure of the language’s creator?
It is like with any other artifact in your software system: A DSL definition needs to be clean, understandable and maintainable. If you know that an important team member is leaving the project, make sure she's not taking any exclusive knowledge with her. That is she should coach other people before she lefts.
What’s BNF? Do I need it?
see http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form :-)
DSL critics say really useful DSLs are hard and expensive to create. DSL supporters answer that DSLs are not designed, they evolve. Well, won’t any of those “evolutionary steps” risk breaking the entire development based on that DSL, much like a broken app build?
Useful DSLs can be very simple and at the same time a very complex DSL can be absolutely useless. It's not the complexity of a DSL, which makes it useful, but whether how good it is to solve the problem at hand. KISS and YAGNI are important principles here as well.
When defining concepts and abstractions it is key to find a good compromise between simplicity (abstraction) and re-usability. The simpler a DSL and the higher its potential for reuse the better. You're hitting a sweet spot, then. You start leaving that sweet spot as soon as you add concepts to the DSL which are only used by a small subset of the users. Often it is better to have two simple DSLs in two projects, than putting everything into one big DSL.

Back to the question: I don't think that evolution and design is mutual exclusive. Don't everybody design software systems incrementally these days.
Changing a textual DSL is not a big problem in practice. At least not as long as you have a decent test suite (which you should have no matter if you use DSLs or not). However, managing compatibility and versioning can become quite complicated, but again it's the same as with APIs.
Will the evolution in the language be severe enough to trash what has been done so far?
You can shoot your foot, if you want. But you don't need a DSL to do so.
Can you imagine yourself developing a complex C++ software system while C++ itself was still being designed and developed?

Can you imagine writing a complex C++ software system while the standard libraries are still being designed and developed?
I can imagine, but I am not keen on doing that. That is why we have things like versioning and that is also why people think about compatibility when enhancing public programming interfaces. Such interfaces can be a method signature, but it can also be a syntax of a language. It doesn't matter. If it breaks it breaks. And the designer has to be explicit about the contract of that interface as well as its life cycle.