Should you be able to define new abstractions in a Domain Specific Language?
Fowler has a post about DSL, which contain the following:
The first is in language design. I was talking with a language designer who I have a lot of respect for, and he stressed that a key feature of languages was the ability to define new abstractions. With DSLs I don't think this is the case. In most DSLs the DSL chooses the abstraction you work with, if you want different abstractions you use a different DSL (or maybe extend the DSL you're using). Sometimes there's a role for new abstractions, but those cases are the minority and when they do happen the abstractions are limited. Indeed I think the lack of ability to define new abstractions is one of the things that distinguishes DSLs from general purpose languages.
I disagree with the statement that this is an exception. This is something that come up again and again in a DSL. You start with a given concept of what you want to do, and you give it to the users. Rinse & repeat a couple of time and you have a language that the users can start play with.
The main problem is that not giving the users that facilities for abstraction usually mean that they will work around your system, or that the DSL scripts that you will have will suffer from copy & paste, unnecessary complexity, etc.
A trivial example would be how to define customer roles. You want to be able to process orders based on customer role, and as such, it is important to be able to define how you choose a customer. Not only that, but even the customer selection criteria should be abstracted.
Here are a few examples:
- Bad customer:
- Bad credit rating
- OR More than 5 returns last year
- OR More than 5 helpdesk calls last 6 months
- Silver Customer
- More than 5 purchases
- Gold Customer
- Total purchases over 5,000$
- Preferred customer:
- Not a bad customer
- Gold customer
We want to define roles using other roles. Because that is how the business thinks about it. We naturally create abstractions for ourselves, because this is how we think.
If we need to go back to the development team for each new abstraction, we have a heavy weight process that the users will work around.
Most of my DSL contains some form of user define abstractions, usually in the form of:
define bad_customer: customer.HasBadCredit or customer.TotalReturnsIn(1.year) > 5 or customer.TotalHelpdeskCallsin(6.months) > 5 define silver_customer: customer.TotalPurchases > 5 define gold_customer: customer.TotalPurchasesAmount > 5000 define preferred_customer: gold_customer and not bad_customer
This is usually user editable, and we plug this into the intellisense of the system. In one project, I even provided a refactoring support, Extract Business Term (bound to CTRL+ALT+V, go R#!)
Abstractions are important, and building them into the language is just as important. You want to empower the users to extend your language, even if it a language that is very limited in scope. Because you give them the option to take the language to realms that you never dreamed on.