Tuesday 11 August 2020

Speak the language of domain - part 2

While researching for post - speak-language-of-domain i spent some time building external DSL and experimented with parser and compiler.

Parser & compiler are important components for external DSL because it converts external DSL to executable.


We will take a few examples of external DSL and look at what is required to build a full solution.

Rule Engine

I will use below DSL as external dsl and try to convert it into an executable.  



We allow users to upload dsl files and change the behavior of the system at runtime based on rules in the dsl file. Such a type of feature will make the system very flexible and powerful.
Remember Peter Parker principal "With great power comes great responsibility" , so use such things in the production system at your risk!
     


external DSL pipeline


Loading a DSL file is a trivial thing , it can be uploaded to the system using a web interface. 

Once a file is uploaded then it needs to be parsed, this is where things become little interesting and many built in libraries are available to parse files and extract tokens but in this example we will do simple parsing and code generation.

For parsing template files that will be used, content of the DSL file is put in template file before compilation. 

For this example I am going to use the template file.


Above template file has 2 variables $REPLACE & //CODE, these two variables are replaced during the parsing and code generation phase.

$REPLACE - will contain some random value to give a unique name to the block of code that needs to be compiled. 

//CODE - will contain DSL code submitted by the user.

Once tokens are replaced we are ready for compilation.

For compilation we will use JavaCompiler  API, this api gives a programmatic interface to JVM compiler. Very powerful API for doing something in running VM.

 Code snippet for compiling code using JavaCompiler interface.


Once code is compiled then using the java reflection rule can be loaded.

Code snippet for DSLLoader 


Once the rule is loaded from DSL then it is straightforward to update the current VM to use the newly created rule.

DSL code is type safe, all the checks are done at compile time and it is highly optimized code because it has no reflection or other magic, so it will benefit from all the hotspot compiler.

For DSL creator perspective these rules can be tested in sandbox before using it production.

Few things that can be improved are error messages when DSL has compilation error, right now it is just showing java error messages and it will not be that user friendly for non java programmers. 

Trading System

In earlier post below internal DSL was used.

newOrder(equity("IBM"), (order, ts) -> {
order
.buy(100)
.at(126.07d);

ts.execute(order);
});

newOrder(equity("GOOG"), (order, ts) -> {
order
.sell(100)
.at(1506.85)
.partial();

ts.execute(order);
});

Lets have external DSL for this.

buy 100 IBM stocks at 122.06
This has few keywords(i.e buy, stocks , at) related to trading domain and also has few parameter related to order like 100 (i.e unit) , IBM ( i.e stock) , 122.06 ( i.e price).
For this example it is easy to write as parser that will create order object.
Refer to Parser for more details on how text is parsed and order object is created.

All the code used in this post is available at DSL