Tuesday 28 April 2015

Using defined macro vs personalized Jolie service

When designing software solution using microservices  one finds himself to wander how do handle repetitive code.  This is particularly true when one uses microservices for data handling and data mapping; where often it is required to transform data from a format to another for example:
  1. Date Format
  2. Double Value Format 
  3. Other Alphanumerical manipulation  
Jolie language provides  to the programmer already with some rather powerful primitives to manipulate such data but is not uncommon to have to personalize some behavior. And this is where the dilemma araises. Do I go for 
  1. A series of  macros defined by the primitive define 
  2. Or do I create a service with a number of exposed operation
Now this post does not aim to set a standard or either to propose a methodology for microservices coding in Jolie, Its only aim is to share a personal checklist when taking a coding decision on repetitive code .
Let's look  to an example of date transformation
   
define transformDate{

    if (is_defined(__date)){

requestSplit= __date;
requestSplit.length = 4 ;
splitByLength@StringUtils (requestSplit)(resultSplitYear);
year = resultSplitYear.result[0];
requestSplit= resultSplitYear.result[1];
requestSplit.length =2;
splitByLength@StringUtils (requestSplit)(resultSplitMonth);
month = resultSplitMonth.result[0];
day = resultSplitMonth.result[1];
__transformedDate =day+"-"+month+"-"+year
}
}


Now this section of code could be defined with in an iol file and included by several services and used in this way

__date = value_original_date
transformDate
value_new_date = __transformedDate

Now let us see the same functionality implemented with a service

type DateTransformRequest:string

type DateTransformResponse:string

interface TransformInterface {
RequestResponse:
 transformDate (DateTransformRequest)(DateTransformResponse)
}

and with an implementation that looks like

inputPort TransformerInputPort{ 
  Location:"socket://localhost:8099" 
  Interfaces:TransformInterface
  Protocol:sodep 
}
main{
transformDate(request)(response){
  //the code that does it here
}]{nullProcess}


Now let us go down to the topic of the post how can we compare the two implementations

Define implementation

Pro
Con
Need to restart all the services if there a change to be implemented

Yes
No network resources
Yes

Shorter time of implementation
Yes

Clear error tractability

No
Network deploy

No

and for the Jolie service implementation

Jolie Service implementation

Pro
Con
Need to restart all the services if there a change to be implemented
No

No network resources

No
Shorter time of implementation

No
Clear error traceability
Yes

Network deploy
Yes


Now the reader may be tempted to object to such a limited arbitrary check list and he or she would be right to do so, but my aim was not to give a definitive answer but more indicate a methodology of thinking.
Now let us step back to the drawing board and consider the following questions.

  1. Do I need to re-use the code several time and across several implementations
  2. My hardware infrastructure will be subject to  changes
  3. Do I need trace possible errors specializing error raising and handling
  4. Do I need to use complex data type  

If the answer to all these questions is yes is my opinion that would be better to opt for a Jolie Service Implementation approach for the following reason:
  1. In both implementation the cross usability is possible but the Jolie service implementation is favorable for :
    1. In case of code changes I need to change in a single place 
    2. If I need to use in a new project I do not have to copy specific implementation but refer to an interface and leave the implementation stable
  2. This point is often underestimated during the design phase of the project but in microservices architecture has a huge impact ; also in this case the Jolie Service Implementation is favorable because:
    1. Its naturally more adaptable to infrastructure changes ( the service can be deploy where ever )
    2. If there is a need of splitting the microservices implementation over several machine, in the case of the define base implementation we will find ourself duplication the implementation on several machine , with all the problems concerning code duplication
  3. The error handling  it is essential in any software paradigm , but it is even more important in SOA architecture where the high level of concurrent execution would almost impossible to trace errors. In the case of the Jolie Service Implementation the possible error are definable at level of interface making in my opinion simpler the use of the functionalists
  4. /* define implementation */
    define myDefine{
       /*some code*/
       throw (someError)
       /* some other code */
       throw (someOtherError) 
    }
    /* Use of interface  */
    interface myInterface{
    RequestResponse:
    myOperation (requestType)(responseType) throws someError , someOtherError
    }  
    1. As the code above tries to exemplify the user of the functionalists  would   find easier to identify the possible error to catch via interface instead of having to scan the implementation
  5. Similarly to the issue of the fault handling the use of complex types is aided massively by the use of  a Jolie Service Implementation approach where we can define complex types in a clear way instead of having to reverse engineer the code of the define
I hope you will find my post somehow useful to define define recurrent code in jolie

No comments:

Post a Comment