Stylish, fashionable, youth BPM development at Camunda

    image

    BPM development is not easy. This is due to the fact that the process must be readable and understandable to the customer, and not only correct from a technical point of view.

    Not all tools for developing business processes allow you to find a compromise between a clear description and technical functionality. Many advanced development tools and process descriptions often have one more drawback: they are so cool, powerful, and complex that, while they were being made, technologies took a big step forward and development with such a tool became irrelevant.

    2018 fundamentally changed our approach to the development of business processes. Below is about how this approach has evolved and how we have changed.

    Instead of a prologue


    Our department is engaged in the development of business processes - from the smallest and smallest to large and extremely profitable. Until recently, we used a product from IBM for development, which allows us to quickly launch a working business process in production.

    IBM BPM is a powerful platform that includes a rich set of features, such as a description of the processes themselves, UI forms, and integration modules. In addition, this platform has a rather low entry threshold, which allows novice developers to immediately immerse themselves in the project. But this product also has drawbacks that, if they do not inhibit development, then certainly do not contribute to speed and quality:

    • There is no sane version control. IBM BPM simply does not provide the ability to properly store processes (code) in the repository and uses its own repository, which does not know about a concept such as merge, for example.
    • Developing in Java 6. Perhaps at the time of this writing, it is already possible to develop in Java 7, but in 2019 this is a little comfort.
    • IBM BPM is spinning on WebSphere, as a result, developers need to be patient with each update of their module. In addition, this is an additional headache for administrators who periodically have to bring this monster back to life if it hangs.
    • The development of integration modules in the environment of Integration Designer, which in fact is obscured not for the better Eclipse.
    • There is no normal unit testing capability.
    • The high cost of the platform.

    These shortcomings, in addition to the purely technical inconvenience of development, have created yet another problem, which is perhaps much more serious than all of the above. In the days of Java 12, Kotlin, microservices and other fashion trends and pieces, all these nuances very demotivate the team. It's hard to experience the joy of developing in the ever-hanging Integration Designer for Java 6 in 2019.

    image

    With all these limitations, it’s hard to stay afloat. A little less than a year ago, there was an offer to try the Camunda engine to describe business processes. To begin with, a not very large, but rather important process for registering terminals for legal entities was selected.

    Since we completely rewrote it, there was almost no old code, we could practically not limit ourselves to anything, and therefore we chose Kotlin as the development language. It was interesting to try this new language, which was heard mostly for positive reviews. On some other projects in our department there was a successful implementation experience. The final stack turned out like this: Camunda, Spring Boot 2, Kotlin, Postgre.

    What is Camunda?


    image

    Camunda is an open-source business process modeling platform that is written in Java and uses Java as a development language. It is a set of libraries that allow you to perform the described processes. To integrate Camunda into a project, just add a few dependencies. To store processes, you can choose in-memory or persistent DBMS - depending on the tasks. We chose Postgre, because the story is important to us for "debriefing." By default, the platform deploys to H2.

    Development consists of two parts: creating a flow process in a special Camunda Modeler utility and writing java code that processes the process steps described in the diagram. In order to call java code from the process, it is enough to implement the JavaDelegate interface, raise this Bean (you can specify delagate by the full name, but through the Bean it is more convenient and flexible) in the context and specify its id at the desired process step. At Kotlin, the delegate looks even more succinct. The logic of the delegates is quite simple: they subtracted something from the context, performed some actions and put it back into context.

    image
    Camunda Modeler popup window

    Java delegate example:


    import org.camunda.bpm.engine.delegate.DelegateExecution;
    import org.camunda.bpm.engine.delegate.JavaDelegate;
    public class JavaExampleDelegate implements JavaDelegate {
        @Override
        public void execute(DelegateExecution execution)  {
            String someVar = (String) execution.getVariable("someVariable");
            // some actions
            execution.setVariable("otherVariable", "otherValue");
        }
    }
    

    Kotlin delegate example:


    import org.camunda.bpm.engine.delegate.DelegateExecution
    import org.camunda.bpm.engine.delegate.JavaDelegate
    class KotlinExampleDelegate: JavaDelegate {
        override fun execute(execution: DelegateExecution) {
            val someVar = execution.getVariable("someVariable")
            //some code
            execution.setVariable("otherVariable", "someValue")
        }
    }
    

    In the delegate, you can describe business logic, integration, and everything that your heart desires.

    We try to create a layer in the form of a business component with logic, and use the delegate only as a link to the flow of the process, so as to mix the code and the process as little as possible.

    In most cases, this approach is convenient and works successfully. Interaction with the process occurs through DelegateExecution, which allows, for example, to work with context, incidents, and so on.

    Is that what we wanted?


    At the very beginning, when choosing a tool, we were looking for a solution with the following features:

    • Recovery of the process exactly from the place where the failure occurred, and it is desirable that it be out of the box.
    • Some GUI where you can see what happens to the process in general.
    • The ability to write unit tests not only for logic and integration, but also for the process itself.
    • Java 8 and above.
    • Developed community.

    Camunda is fine with error recovery and analysis.

    A well-readable trace, the ability to set the number of attempts to take a step before falling, a custom handler when falling - for example, if during a fall we want to change the status of some entity to Error. The latter is easy to do just by implementing DefaultIncidentHandler. True, there is a funny moment when this handler works: the error recovery code is triggered every time you enter the process step. I can’t say that this is a superbug or a problem. Rather, you just need to remember and consider this when developing.

    We solved it like this:

    override fun resolveIncident(context: IncidentContext) {
            val incidentList = Context.getCommandContext().incidentManager.findIncidentByConfiguration(context.configuration)
            if (incidentList.isNotEmpty()) {
                // некоторый код при восстановлении инцидента
            }
    }
    

    Camunda has a GUI and it’s not bad.

    But if you want a little more, for example, migration of instances between process versions, then you will have to work hard. The default UI has only minimal functionality, but there is a very powerful Rest API that allows you to create your own admin panel - cool and sophisticated.

    It was along the path of our admin panel that we went. Our business process architect in a rather short time saw it down, including the functions of viewing the history of already completed processes, migration between versions, and so on.

    Camunda's Rest is really powerful and lets you do just about anything with processes. For example, you can start a process using / process-definition / key / aProcessDefinitionKey / start with such a simple request:

    {
      "variables": {
        "aVariable" : {
            "value" : "aStringValue",
            "type": "String"
        },
        "anotherVariable" : {
        "value" : true,
        "type": "Boolean"
        }
      },
    "businessKey" : "myBusinessKey"
    }
    

    The example is taken from the official documentation, which contains an extensive description of the various cases of using this API.

    For unit testing, we use the usual Junit. Plus there is a rather interesting library for testing the process itself - 'org.camunda.bpm.extension', name: 'camunda-bpm-assert'. With it, you can describe tests to verify the flow process.

    This is quite convenient, since it is often more difficult to search for problems with bugs in flow than in code. Such testing protects, for example, from inaccurate refactoring and really helped us several times.

    The need for Java 8 has partially disappeared, since the use of Kotlin on many processes eliminated the need for the G8. Kotlin fits in very well with the project and allows you to focus only on writing business logic. It's hard to believe, but basically everything that Kotlin says about coolness is true. Entities with a large number of fields, which are known for almost all applications with integrations, now do not look so scary, and the mappings between entities have become much more readable. Often criticized null safety really works and helps out in most cases.

    Community at Camunda is quite developed. This is evidenced by the fact that new libraries on GitHub are constantly appearing for testing and metrics.

    It's nice that Camunda integrates perfectly with Spring. Add the necessary dependencies, a couple of annotations and a couple of configuration beans - in fact, that's all the integration! As a result, we write a regular spring application that everyone is used to, adding the flow of a business process. The interaction takes place through the Java API, which allows you to manipulate processes from java code.

    For example, you can start the process with just one command:

    runtimeService.startProcessInstanceByKey(
                        "MyTestProcess",
                        "MyBusinessKey",
                        mapOf(
                                "key1" to "value1",
                                "key2" to "value2",
                        )
    )
    

    Here MyTestProcess is the Id-shnik of the process, not the instance. MyBusinessKey is a unique key for a running process instance. We usually use some business value for this field - for faster navigation between instances and search.

    In about the same way, you can wake up a “sleepy” process.

    Noticeable minuses or any problems that we encountered, especially cannot be recalled. As a result, for a fairly short period of time, it turned out to be a completely working process and safely bring it into production. Other processes are being implemented on the platform and quite successfully. Now on Camunda we have launched about 15 applications on which about 100 thousand processes spin at a time.

    image

    Instead of an epilogue


    Here are a few resources that have been helpful in implementing the stack described above. I recommend that you read them if you are interested in additional information on the topic.


    Also popular now: