Thursday, June 15, 2017

The power of Domain Specific Languages

We are all used to configuration files, whenever they are XML, JSON or simply text based. If this is ok for simple configurations, but it falls short when the complexity increases. The biggest issue is that they cannot provide more than what they are designed for, basically static values.

Let's suppose, for example, that we have an XML configuration file exposing a property like:
  <visible>true</visible>
Ok, simple enough. This property can be true or false. But now what if I want a more dynamic value, like true if I'm in development mode, or false if I'm in production? I'm stuck!

Some configuration systems allows expressions to be evaluated within the configuration text, like:
  <visible>${runtime.development}</visible>
But this is very specific to every configuration system, when it exists. Moreover, this is limited to value replacement. What if I want to define a set of properties based on a condition? Well, some rare systems provide an advanced syntax, like
  <sys:if cond='runtime.development'>
    <prop1>val1</prop1>
    <prop2>val2</prop2>
  </sys:if>
Looks like the venerable XSL :-) This is about inventing a new ugly programming language that nobody knows about. And it is still have limitations, basically what the programmer provided. 

The use of the programming constructs I know would be more appealing to me. What about:
  if(runtime.development) {
    <prop1>val1</prop1>
    <prop2>val2</prop2>
  }
or even better:
  if(runtime.development) {
    prop1 val1
    prop2 val2
  }
This is mixing and matching configuration statements with regular programming ones. This allows a total flexibility on what is possible! We just need a programming language that supports this kind of construction, including the use of a dedicated grammar to provide prop1 and prop2. The programming language, along  with this specific, dedicated grammar, is what is called a Domain Specific Language, aka DSL. 

In the Java world, Groovy is currently the clear leader. It is being used in many systems, with even books written on this very topic. Its parenthesis less syntax when calling a method, the use of closures (similar to java 8 lambdas) make it particularly suited for the job.

They are several places where we are using a Groovy based DSL in Darwino. This is what allows, for example, a very flexible data replication configuration between IBM Domino and the Darwino JSON store. Not only we are providing many predefined data transformations but we let the developer insert custom code almost everywhere.

Recently, we introduced another DSL in our new micro application architecture. In particular, we added triggers and actions, for example to send a notification to mobile devices when a new document has been inserted in a particular database. Or any other action, on any other trigger...

Here is a mock example bellow. If it seems trivial, it shows that some code can be inserted to lookup a user in the LDAP directory to find its mobile id, or calculate the URL of the page to display. This would have been hard to define these custom processing with a simple static configuration file.

DatabaseTrigger {
  database "MyDatabase"
  view "Workflows"
  handler { doc ->
    def approver = LookupUser doc["Approver"]
    def url = calculateDisplayUrl(doc)
    pushNotification {
      ids approver.mobileid
      page url
      text "Purchase Approval Pending"
    }
  }
}

Neat, concise and simple, isn't it? 
In this example, pushNotification is a predefined action but other actions types  are available (sendEmailwatsonWorkNotification...). Moreover, if Darwino does not provide a trigger or a notification you need, then it is very easy for a developer to inject a custom one into the DSL. Just develop it in Groovy or Java and register it. A DSL is very dynamic and extensible.

0 comments:

Post a Comment