DSL Patterns - User Extensible Language

One of the common mistakes in a DSL is to create one that solve a demo problem and leave it at that.

As a simple example, let us say that we build a DSL to handle order management. Here is a typical scenario that was talked about during development:

when is_preferred_user and order_amount > 500:
	apply_discount 5.precent

Sounds reasonable, right?

Except, that this isn't really a good way to express a business rule. A common business rule usually have a lot more complexity to it. Here is a good example:

when user.payment_method is credit_card and ((order_amount > 500 and order_amount < 1200) or number_of_payments < 4) and 
user.is_member_of("weekend buy club") and Now.DayOfWeek in (DayOfWeek.Sunday, DayOfWeek.Sutarday)
and applied_discounts < 10: apply_discount 5.precent

At a glance, what the !@$!# does this rule do?

This is a good example of stagnant DSL. It is no longer being actively developed (easily seen by the use of framework terms such as DayOfWeek), and the complexity is growing unchecked.

This is usually the case when the DSL design has not taken into account new functionality, or when it relies on developers to be able to extend the language when needed. Because it requires developer involvement, it is often easier to patch it by complex conditional rather than express the actual business logic in a readable way.

A good way to avoid that is to incorporate known best practices from the development side into our DSL. In other words, we need to allow encapsulation and extensibility in our DSLs. As a simple example, we can allow the following:

condition weekend_club_member:
	user.is_member_of("weekend club memeber")
condition sale_on_weekend:
	Now.DayOfWeek in (DayOfWeek.Sunday, DayOfWeek.Sutrday)
condition good_payment_option: # yes, I know, bad name, deal with it
	((order_amount > 500 and order_amount < 1200) or number_of_payments < 4)

And now the condition becomes:

when user.payment_method is credict_card and good_payment_option and sale_on_weekend 
and weekend_club_member and applied_discounts < 10: apply_discount 5.precent

This is important, because it avoid a language rot and provide the facilities to the end user to add abstraction levels.

Print | posted on Thursday, August 14, 2008 2:58 AM

Feedback


Gravatar

# re: DSL Patterns - User Extensible Language 8/14/2008 4:31 AM Kyle

I really like this. I have done something similar in the past when writing my own small DSL, which was nothing more than a somewhat complex string-processing language. It allowed the user to combine arbitrary functions and variables together in order to create new functions, then use the new functions later. It was a really, really, really clean way of being extensible.


Gravatar

# re: DSL Patterns - User Extensible Language 8/14/2008 10:48 AM Gian Maria

Yes, including directly in the DSL some extensibility points, seems a great way to proceed. It is impossible to anticipate all needs in a DSL, but the ability to extend make it really powerful.

alk.


Gravatar

# re: DSL Patterns - User Extensible Language 8/15/2008 10:21 AM Benny Thomas

Why not make it even more readable:

condition creditcard_transaction:
user.payment_method is credict_card
condition low_discount_applied:
applied_discounts < 10


when creditcard_transaction and good_payment_option and sale_on_weekend and weekend_club_member and low_discount_applied:
apply_discount 5.precent

I like your style but I would like to se a small application build on this.


Gravatar

# re: DSL Patterns - User Extensible Language 8/15/2008 1:26 PM Ayende Rahien

Benny,
Because I am showing a sample and just didn't think about it. :-)
There will be a sample in the book source code.


Gravatar

# re: DSL Patterns - User Extensible Language 8/16/2008 12:21 AM Benny Thomas

Looking forward to reading the book. :-)

Comments have been closed on this topic.