Vermeidung typischer Fehler in Prozessmodellen durch Design Patterns

by Christian Mächler

BPM
15. April 2024 6 Minuten

Anhand des am häufigsten angetroffenen Problems bei der Prozessautomation veranschaulichen wir den Nutzen von Design Patterns.

Design Patterns und Anti Patterns

Design Patterns (Entwurfsmuster) sind Baupläne, die aufzeigen, wie ein bestimmtes Problem zuverlässig gelöst werden kann. Sie können beliebig kombiniert und in Modelle eingefügt werden. Design Patterns sensibilisieren einem auch auf mögliche Probleme und können helfen, komplexe Prozesse in übersichtliche Bausteine herunterzubrechen. Während es in anderen Bereichen (z. B. objektorientierte Programmierung) eine Fülle an etablierten Design Patterns gibt, ist dies in der Prozessmodellierung quasi noch Neuland.

Das Gegenteil des Design Patterns ist das Anti Pattern, es beschreibt Dinge, die vermieden werden sollten. Unter anderem parallele Gateways mit exklusiven zusammenführen (Tokens würden nicht konsumiert werden).

Übersicht zu den Praxisbeispielen

  1. Update eines Timers: der am häufigsten angetroffene Fehler bei der Automation eines Prozesses.
  2. Updatable Timer Pattern: ein Design Pattern zur Lösung des Problems.
  3. Update eines Boundary Timers: verallgemeinert das vorherige Problem.
  4. Complete 1 of N Pattern: ein vermeintlich unabhängiges Design Pattern, welches mit Vorsicht zu geniessen ist.
  5. Updatable Boundary Timer Pattern: kombiniert das «Updatable Timer Pattern» und das «Complete 1 of N Pattern» zu einem neuen Design Pattern und löst damit das generalisierte Problem.
Zu den BPMN-Files auf GitHub

Update eines Timers

Das folgende Modell ist eine abstrahierte Version des Problems aus der Praxis. Wesentlich ist dabei der Timer, welcher auf ein in einer Variable releaseDate gespeichertes Datum wartet. Das Prinzip bleibt gleich, auch wenn die Variable für den Timer je nach Workflow-Engine anders gesetzt wird. Der Prozess ist ausführbar und funktioniert, doch wieso werden Variablen-Updates vom Timer ignoriert?

Problem

Beim Erreichen eines Timers wird dieser sofort evaluiert und der Zeitpunkt für die Fortsetzung des Prozesses gespeichert. Falls dies bereits vorbei wäre, ginge es direkt weiter. Nach der Berechnung des Weiterausführungszeitpunkts haben Variablen-Updates keinen Einfluss mehr auf den Timer. Im Modell ist auch nicht ersichtlich, dass sich das Release-Datum ändern könnte. Das folgende Design Pattern löst das Problem und visualisiert die Möglichkeit von Timer-Updates. Aufgrund dieser Veranschaulichung im Modell ist es vorteilhaft dies schon früh zu berücksichtigen und nicht erst bei der Automation.

Updatable Timer Pattern

Die Design Patterns in diesem Artikel sind bewusst allgemein gehalten und auf das wesentliche reduziert. Sie sind nicht Lösungen zu den präsentierten Problemen, sondern Bausteine dazu. Zur Lösung des obigen Problems muss der Timer durch das folgende Design Pattern ersetzt werden. Start- und Endevents sind jeweils nicht Teil des Patterns, sondern zeigen auf, wo der Flow hereinkommt und wieder hinausgeht.

Updatable Timer

Dieses Design Pattern nutzt die Eigenschaften des ereignisbasierten Gateways, welches den Fluss in Richtung des zuerst eintreffenden Events weiterführt. Unmittelbar auf das ereignisbasierte Gateway dürfen also nur Ereignisse folgen. Timer werden beim Erreichen des Gateways evaluiert, so wie wenn der Timer selbst erreicht worden wäre. Message-Events erlauben Variablen-Updates in bestimmten Prozess-Instanzen an genau diesem Punkt im Prozess und sonst nicht. Falls der Prozess nun beim ereignisbasierten Gateway wartet, kann mit einer Message ein Update der Datums-Variable vorgenommen werden. Danach führen wir den Fluss wieder zurück auf das ereignisbasierte Gateway, dadurch wird der Timer erneut evaluiert (neue Timer-Instanz, alte verworfen, als der Fluss in die andere Richtung weiterging) und es können weiterhin Nachrichten geschickt werden. Sobald der Timer ausgelöst wird, geht der Fluss in diese Richtung weiter und es können der Prozess-Instanz keine solchen Messages mehr gesendet werden.

Updatable Timer2

Eine komprimierte Version des Patterns. Es entspricht nicht den Design-Guidelines, auch wenn es übersichtlicher erscheinen mag.

Update eines Boundary Timers

Was ist mit Boundary Timers, wie können wir diese updaten? Es ist nicht möglich, ein ereignisbasiertes Gateway als Boundary Event einzusetzen. Wir benötigen ein neues Design Pattern zur Lösung dieses Problems, eines mit zwei möglichen Ausgängen.

Problem2

Complete 1 of N Pattern

Dieses Design Pattern erlaubt die Erstellung verschiedener Tasks, wovon nur einer abgeschlossen werden kann. Es funktioniert ähnlich wie ein ereignisbasiertes Gateway mit Tasks statt mit Events. Es sollte nie mehr als einer der Tasks ein User Task sein. Ansonsten kann es vorkommen, dass User gleichzeitig an verschiedenen Tasks arbeiten, jedoch nur einer seinen Task abschliessen kann, sprich die Arbeit der anderen war umsonst. Isoliert betrachtet scheint das Pattern nicht sehr sinnvoll, es kann sich dennoch als nützlicher Baustein erweisen.

Complete1of N

Zuerst erstellen wir einen Sub-Prozess, damit wir Tokens einfach konsumieren können, ohne den restlichen Prozess zu beeinflussen. Das parallele Gateway erzeugt für jeden seiner Ausgänge ein Token, das dann beim jeweiligen Task wartet. Nach Abschluss eines Tasks müssen unmittelbar danach (gleiche Transaktion) alle Tokens im Sub-Prozess zerstört werden, ansonsten wäre es möglich mehr als einen Task abzuschliessen. Dies geschieht entweder mit einem Terminate End Event, wonach es normal weiter geht (happy Path) oder mit interrupting Boundary Events, welche die vom Endevent im Sub-Prozess geworfenen Errors oder Escalations auffangen. Mit verschiedenen Escalations oder Errors können so separate Ausgänge definiert werden, um je nachdem welcher Task abgeschlossen wurde, anders zu reagieren.

Updatable Boundary Timer Pattern

Mit dem zuvor erarbeiteten Design Pattern ist es möglich den Boundary Timer vom Task zu separieren und trotzdem die Funktionalität zu erhalten: Es kann immer noch entweder der Task abgeschlossen oder der Timer ausgelöst werden, aber nicht beides. Weil der Timer jetzt kein Boundary Timer mehr ist, können wir ihn problemlos durch das Updatable Timer Pattern ersetzen und erhalten somit das Updatable Boundary Timer Pattern.

Updatable Boundary Timer

Schlusswort

Mit den praktischen Beispielen konnten wir hoffentlich die Vorteile von Design Patterns aufzeigen und die Begeisterung dafür wecken.
Es würde uns freuen, wenn auch im BPMN-Bereich nach und nach eine Bibliothek mit etablierten Design Patterns entstünde.