SIGMA – The Micro Workflow for Java Developers

GitHub Link : https://github.com/DataRPM-Labs/sigma

Reusability, Extensibility, Scalability and Maintainability (RESM) are the key principles of Software Programming. Design Patterns and Guidelines  help us to achieve the best practices in programming. However, when it comes to ensuring and maintaining a consistent pattern of programming standards across multiple teams of developers contributing towards a product or a set of products in an organisation, it is still a significant challenge.

To meet the fast-changing market demands and to reap the benefits of continuous development and delivery, most of the product development happens as an iterative process. We first work on the MVP and then extend and continue to enhance and extend on top of that. It requires a good amount of experience to foresee this and allow the scope of extension hooks in the design while implementing any functionality.

If these extension needs are not thought through and planned ahead of time, teams end up writing code that deviates design principles and soon the code becomes an unmaintainable myriad of if/else loops and so on.

Moreover, every individual in a team comes from different programming backgrounds and usually follow their preferred way of coding, especially in modularizing and structuring the code, which also plays a significant  role in ending up with a non-uniform code base. Programming frameworks do help to minimise these variations but still a lot depends on a developer’s individual programming style, which makes it difficult for new developers to get ramped up quickly and be productive fast.

A workflow-based development approach in such situations helps tremendously to bring in natural extension points during an implementation, reducing the need to think a great deal about future requirements, as well as to establish a coding approach that can help standardise coding across the board with a very clear readability. We have already seen this being successfully applied to business processes to achieve RESM. A workflow-based approach makes it very easy to define & edit primary process flows #Opensource Click To Tweet Applying the same concepts we have created Sigma – The Micro Workflow for Java Programmers (https://github.com/DataRPM-Labs/sigma), which provides the same flexibility without adding any additional external dependencies. Here are the essential characteristics of Sigma:

  1. Java annotation-based Workflow Engine.
  2. Extremely lightweight.
  3. No external dependency, you just need JDK 1.6 or above to run.
  4. It runs on the same VM where it gets used.
  5. No State Persistence is required, which means you need not configure any persistence store.

 

Some of the key Features are listed below:

  1. Annotation-based Definition.
  2. Ability to define Fixed or Conditional Flow
  3. Ability to create Dynamic Flow Definition, based on Run Time context.
  4. Ability to share data with different States of a Flow.
  5. Execution Thread Pool control.

How to use it:

Let’s consider a user registration flow to an application. Below is the desired expectation of the flow when a user submits the Registration form.

  1. Perform validation on mandatory fields.
  2. Call User Creation API or create an entry in the database.
  3. On Success —
    1. Create a default Profile
    2. Send a verification email to the user and ask to verify.

      4. On Failure —

               1. Send an alert to Support team and Send back helpline number back to the caller.

If you want to implement this using Sigma here is what you have to do:

  1. Define a Workflow Request Object → You can pass all the required information wrapped under this request and send it for execution. And this is where you will be defining the workflow state definitions using annotations. Something like this:

 

UserRegistrationRequest.java

 

@WorkflowRequest

@Context(name = UserRegistrationContext.class)

@Flows(flows = { @Flow(simple = @States(names = { MandatoryFieldValidation.class, UserCreationAPICall.class})),

                @Flow(conditional = {

                    @ConditionalFlow(exp = “context.isUserApiCallStatus() == true”, states = {

                        CreateDefaultProfile.class,SendVerificationEmail.class

                    })}),

                @Flow(conditional = {

                    @ConditionalFlow(exp = “context.isUserApiCallStatus() == false”, states = {

                        SendAlertToSupport.class

                    })})

                })

public class UserRegistrationRequest {

private String userid;

private String password;

private String email;

private String address;       // This can be another pojo

private boolean apiSuccessFlag;

 

/* Removed getters and setter from here for simplicity. You can find the working version under testcases */

}

 

  1. Define a Workflow Context Object → Workflow Context gets passed to every State, which means you can pass objects from one step / state to another using Context.

 

public class UserRegistrationContext extends WorkflowContext<UserRegistrationRequest>{

private boolean userApiCallStatus;

private String userProfileId;

 

/* Removed getters and setter from here for simplicity. You can find the working version under testcases */

}

 

  1. Workflow States → This is where you write the functionality. For example:

public class MandatoryFieldValidation implements WorkflowState<UserRegistrationRequest, UserRegistrationContext>{

 

@Override

public void execute(UserRegistrationContext context) throws WorkflowStateException {

  UserRegistrationRequest request = context.getRequest();

  // Logic to validate attributes

  System.out.println(“-Executing—” + this.getClass().getName());

}

}

 

How to Call Execute → This is how you execute the workflow.

 

@Test

public void runUserRegistrationFlowWithAPISuccess () {

  UserRegistrationRequest request = new UserRegistrationRequest(“user123″, “passxyz”, “user@user.com”, “Address 123″);

  request.setApiSuccessFlag(true);

  try {

    UserRegistrationContext workflowContext = (UserRegistrationContext) new WorkflowEngine()

        .execute(request);

    assertTrue(workflowContext.isSuccess());

    System.out.println(“Print–User Profile Id–” + workflowContext.getUserProfileId());

    assertTrue(workflowContext.getUserProfileId() != null);

  } catch (WorkflowExecutionException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

  }

}

 

What do you gain by using Sigma? 

  1. Breaking the code in such granular states gives the flexibility to introduce new logic without disturbing any of the existing flows. The testing effort reduces as you can control the scope of change to much granular level.
  2. Code readability improves multifold as now by just looking at the Workflow Request Class one can understand the flow straight away. For new developers, it becomes very easy to comprehend the code.
  3. Since each of these microflows are threadpool controlled you can parallelize pretty quickly  with just the help of configuration.
  4. Sigma also provides a Workflow Plan Builder where one can create dynamic Workflow Plans based on the outcome of different states.

GitHub Link : https://github.com/DataRPM-Labs/sigma