The split brain of DSLs
Why it isn’t enough for a DSL to just capture the domain.
This week I gave the talk for my ISOLA 2021 paper Programming vs. that thing subject matter experts do. Here’s a video of that presentation.
One of the audience members pointed out that the point I am making in the presentation — that DSLs should be accessible to subject matter experts (SMEs) — is valid, and that the languages should be designed exclusively to suit their needs, even if that means that the models SMEs create with the language are not directly usable as input to generators, interpreters or analyzers. This is really very much in contrast to my view. My idea of DSLs is that the subject matter people create models with these languages, and that we can then directly use these models as “software ingredients”. In most cases this means that the models are executable through generation or interpretation.
So this means that it is not the only goal of a DSL to faithfully and efficiently capture the core abstractions of a domain. It is necessary for a DSL to do that, but it is not sufficient for a good DSL. So which other considerations are there?
Things to consider when building DSLs
One is rather obvious: the abstractions must be precise and rich enough to make the language executable after processing it with a generator or interpreter (I consider analysis as just another form of execution in this text). So the models might contain some information that the generator needs, but which are seen as unnecessary by the SMEs. Sure, you might be able to concern-separate them syntactically, but they need to be somewhere in the model. Or you might sometimes express something in a way that is not completely intuitive to SMEs, because it is more precise or less ambiguous than what they might want to specify intuitively.
Software Engineering Best Practices
Things like separation of concerns, cohesion and (de-)coupling, modularization, avoidance of duplication and its counterpart, reuse, are really important once your models become big (and yes, your models will become big if you build DSLs for real-world domains and organizations!). Your SMEs might not (initially) understand why this is useful, but you have to do something to keep complexity in check.
Sometimes some parts of your model must not be seen by certain groups of people (think: vendor-supplier relationships). This means you might have to separate some parts of the model into a different artefact so that you can only pass along that part (e.g., separate interface from implementation to allow you to just pass the interface to a supplier). Again, some of your SMEs might not really care about this, but you still have to consider it. A related issue, at least if you’re working in a file-based environment is the granularity of locking and/or merge; this might also force you to add means of physically separating things that might otherwise be expressed with one language construct.
Yet another concern that inferes with “make it fit perfectly with the subject matter” are the capabilities of your DSL tool. For example, it might not support certain kinds of syntax that might be native or useful for the domain. Or the tool might not support a particlar collaboration mechamism. Or it might not scale in some way and you have to design your language “around” that scalability limit. Lots of things like that in practice with most real-world tools!
So you’ve come up with this really elegant abstraction, and you’ve added some kind of inheritance and aspect-orientation to your language in order to avoid duplication, but … it’s really above the head of most of your SMEs. What do you do?
Last but not least, there is style. As an engineer who prides themselves in designing and building “good” languages, you might want to make sure that your language isn’t “ugly”, and that it is stylistically consistent. For example, mixing something Lisp-like (reduced syntax, few keywords, great composability of language concepts) and Cobol-like (elaborate syntax with lots of keywords, not-so-great composability) is probably not a good idea.
What to do if these contradict?
How do you work around contradictions between these concerns? Let’s start with the simplest one. If you run into tool limitations, you might want to consider changing the tool to one that suits your situation better. Kinda trivial, but many people don’t do it (“BUT IT MUST BE TEXT!11!!”)
In many cases the software engineering best practices contradict with user skills. As I have discussed in my talk, many SMEs have problems with “advanced” abstractions such as modularity, interfaces or inheritance. Education and training helps. So does tool support or pairing with more technical people for joint “cleanup sessions”. But in the end, if they don’t (want to) understand them, then you can’t use the abstractions. Sometimes that’s frustrating, but hey, the customer is always right. A similar thing applies to style. Sure, style isn’t “objective”, but I’ve had customers with really strange taste :-)
Executability and taking care of these non-functional concerns are really at the heart of the audience member’s critique when I gave my talk. Why bother the SMEs with this stuff when it’s not really part of the core subject matter? Here’s the thing: I can’t get SMEs to use DSLs (instead of the less formal/strict/structured tools they have been using so far, often for years and decades) if they don’t get direct benefits in return. These benefits are error checking, visualizations, simulation, and tests. In other words, stuff you only get when you are precise and structured. So this really isn’t negotiable in my opinion: a DSL will only be used (at scale) if it is precise and thus, usually executable. If I cannot square this with the skills or wishes of my SMEs, then a DSL is not the right path for theim.