How to Build Good Workflow Applications


In this short tutorial I will provide you with a few basic design patterns helping you to build a really good Business Process Management System based on Imixs-Workfow. For these patterns it does not matter if you build a app just with the Imixs-Workflow core engine or if you use Imixs-Office-Workflow. All patterns explain very basic concepts which will help you a lot in understanding to build and maintain your business application. So lets start!

Pattern-1: Put your Business Logic into the Model

Imixs-Workflow is a BPMN Workflow eingine. BPMN gives you the perfect place to describe your business process including the work-flow, responsibilities and business rules. Even if you are an experienced Java developer, try to describe your business process in the BPMN model first.

The advantage of putting processing logic into the model is that you can easily change this logic later without the need to code, compile and deploy your app again. This is the core idea of low-code development which helps you to speed up coding and implementing a business application.

Maybe you think about setting the Access Level of a process instance with a piece of java code:

if (workitem.getItemValueDouble("budget")>10000) 
   workitem.setItemValue("$readaccess","manager-role");
else
   workitem.setItemValue("$readaccess","team-role");

But this is a hard coded role dificullt to change later. The same can be achieved with a BPMN conditional event in a much more elegant way:

Find out more about conditional events here.

Pattern-2: Use Plugins to Validate, Convert and Aggregate

Plugins provide a cross-model-functionality. This means, a Plugin is executed in every Event part of the processing-life-cycle. Therefore, Plugins are best suited to process recurring general checks and conversions of item values. Remember, the plugin execution is usually independent of the process instance.

Plugin code should be fast and not to complex. Complexity should be part of your model, not of your code.

public class MyPlugin extends AbstractPlugin {
  @Override
  public ItemCollection run(ItemCollection workitem, ItemCollection event)
                                          throws PluginException {
    // validate and aggregate
    double budget=workitem.getItemValueDouble("budget");
    if (budget <= 0) {
      throw new PluginException(MyPlugin.class.getName(),"INPUT ERROR",
                    "Please enter the Budget.");
    } else {
      // aggregate by rounding 
      workitem.setItemValue("budget", Math.round(budget));
    }
   } 
 }   

In this example it does not matter in which status the process instance is. We just want to ensure that a budget is always given and rounded to integer values. Of course you can do the same in a business rule directly in the model, but it is not efficient to put generic validations into every single event element.

Pattern-3: Put Edge Cases Into Adapters

The Imixs-Workflow Adapter API is another powerful part of the Imixs microkernel architecture. An Adapter class can execute business logic and adapt the data of a process instance. In difference to the Plugin the Adapter is bound directly to a BPMN Event and is only executed when the event is triggered. This gives you a better control to implement edge cases of business logic. An Adapter is used also to implement complex business logic.

public class DemoAdapter implements org.imixs.workflow.SignalAdapter {
  // inject services...
  @Inject
  ModelService modelService;
  
  @Override
  public ItemCollection execute(ItemCollection document, ItemCollection event) throws AdapterException {
    ....
  }
}

You can use CDI, EJB and all other Jakarta EE APIs. So in all cases a Plugin is to generic use SignalAdapters instead.

Pattern-4: Don’t Use Bean Validation

Yes, Bean Validation is a great thing and Imixs-Workflow is based on Jakarta EE Framework so it is possible to use beans to validate your data. But these beans have one disadvantage: They are tightly coupled to a specific programm situations like a form submit or a rest api call. The BPMN business logic can be much more complex and triggered form a web form as also via the Imixs Rest API. This can make it more complex and the final implementation is often not transparent to the processing life-cycle.

Make use of the Plugins and Adapters instead as explained before.

Pattern-5: Don’t Use Hard Coded Model Queries

Try to avoid hard coded model query in your Java classes. This often happens in Plugin Code if you want to run your Java code only in specific situations depending on the current status of a process instance.

public class MyPlugin extends AbstractPlugin {
  @Override
  public ItemCollection run(ItemCollection workitem, ItemCollection event)
                                          throws PluginException {
    // Avoid this
    if (workitem.getTaskID() == 5000) {
      //.....
    }
   } 
 }   

Try to use SingnalAdapters instead.

Pattern-6: Don’t use CDI Events to Intensely

The Imixs-Workflow Engine provide a Cross-Function-API based on CDI Events. This API allows you to intercept the Processing Life-Circle directly and can be helpful in some situations. In fact, Imixs-Workflow is using CDI events for example to synchronize user data or generate event log entries. But in a complex business workflow it is not always fully transparent when a CDI Event will be process from different components and this can result in strange side effects. So it is not a good pattern to use CID events to validate or update the data of a process instance. Use instead the Plugin and Adapter APIs.

Pattern-7: Separate External APIs into Microservices

Imixs-Workflow supports a great Microservice-Architecture and a powerful Rest-API. Make use of this architecture in all cases you need to integrate external APIs.

Normally, you would first add an external API via a Maven dependency and then implement it in a plugin or adapter class. Yes, this works, but it also creates unnecessary dependencies in your core application. A better way to connect external APIs is to implement them in a separate microservice and then establish a communication via the Imixs Event-Log API. This makes your application lean and more maintainable as you avoid a big single monolithic application artefact.