Wenn Sie sich mit der Automatisierung von Prozessen in einer Business Process Engine (BPE) beschäftigen, stehen oder standen Sie vielleicht auch schon vor der Frage, welche Daten Sie als Payload durch den Prozess schleusen.
Dass diese Frage alles andere als trivial und doch manchmal ganz leicht zu beantworten ist, haben wir kürzlich im Projekt erfahren.
Als Payload (engl. für „Nutzlast“) bezeichnet man üblicherweise die Daten, die in einem Prozess von Aktivität zu Aktivität transportiert werden. In vielen Fällen ist die Payload eine XML-Struktur, die den Transport beliebiger Daten zulässt. Eine Aktivität nimmt die Payload, führt darauf eine Operation aus (dies kann alles sein: von einer lokalen XSL-Transformation bis zum Aufruf eines Webservices) und schreibt das Ergebnis zurück in die Payload, worauf die nächste Aktivität dann ihrerseits operiert.
Extrem 1: Payload mit IDs
In unserem Projekt ist die BPE, in unserem Fall die inubit Suite, aufgesetzt auf einer serviceorientierten, mit EJB3 realisierten Architektur, die in einem JBoss Application Server läuft. Geschäftslogik findet nur in der Business Service-Schicht statt, die BPE übernimmt ausschließlich die Prozesssteuerung und orchestriert im Wesentlichen die Business Services, die sie über Webservices aufruft. Die Tatsache, dass die zugrunde liegende SOA in Hinblick auf ihre Schnittstellen sehr homogen ist, hat dazu geführt, dass die Prozesse mit einer sehr schlanken Payload auskommen. Wir schleusen in den meisten Fällen nur die IDs von Fachobjekten durch den Prozess, die dann an die Services gereicht werden.
Dieses Vorgehen stellt gewisse Anforderungen an die Business-Service-Schicht. Diese muss nämlich alle Daten, die sie benötigt, anhand der IDs, die sie vom Prozess bekommt, über Domain Services aus der Datenbank beschaffen und die Änderungen nach der Verarbeitung über Domain Services auch wieder persistieren.
Extrem 2: Payload mit Fachobjekten
Das andere Extrem ist es, komplette Fachobjekte am Beginn des Prozesses einmal über einen Service in den Prozess zu laden und dann in der Payload mitzuführen. Die Objekte werden dann an die Services gereicht, die dann nur noch die Änderungen durchführen und das manipulierte Objekt an den Prozess zurückgeben müssen. Der Prozess muss dann an geeigneter Stelle die Objekte persistieren. In einer heterogenen Welt könnte der Prozess so auch Schnittstellen bedienen, die unterschiedliche Strukturen erwarten, indem die Fachobjekte ggf. in die jeweilige Zielstruktur gemapped werden.
Auf der Service-Schicht würde dieses Vorgehen einerseits Datenbankzugriffe, andererseits remote calls auf die Domain Service-Schicht sparen.
And the winner is…?
Wir haben kürzlich beide Varianten auf ihr Laufzeitverhalten untersucht. Das Ergebnis war eindeutig: Die Ersparnis an Datenbankzugriffen und remote calls wird durch die Verwaltung der Payload in der BPE, bei der große XML-Strukturen häufig in das Filesystem geschrieben und wieder geladen werden, bei weitem neutralisiert. Die Variante mit Fachobjekten war in unseren Tests bis zu fünf Mal langsamer als die Variante mit IDs. Die Ergebnisse bei der Laufzeit waren so eindeutig, dass wir weiterführende Untersuchungen, z.B. in Richtung Netzlast, gar nicht mehr angestellt haben.
Was wir daraus lernen können
Mindestens genauso interessant wie das eigentliche Ergebnis der Untersuchung waren aber die Erkenntnisse, die ich als Nebenprodukt gewinnen konnte. Die eine wie die andere Variante hätte nämlich erheblichen Einfluss auf die gesamte Architektur und das Prozessdesign.
Persistiert jeder Service immer alle Änderungen sofort, braucht man sich keine Gedanken darüber zu machen, zu welcher Zeit man welchen Datenzustand benötigt und wann manuelle Synchpoints aus dem Prozess heraus nötig sind. Möglicherweise reicht es dabei gar nicht aus, am Anfang des Prozesses zu laden und am Ende zu speichern. Gibt es im Prozess manuelle Rückkopplungen mit Mitarbeitern, so muss vor diesen gespeichert werden, damit der Mitarbeiter auf dem aktuellen Stand aufsetzt.
Dazu kommt, dass die Fachobjekte in der BPE, z.B. als XSD, modelliert werden müssen. Existiert in der SOA ein Versionskonzept, das den parallelen Betrieb verschiedener Versionen eines Services erlaubt, so muss dieses in der BPE entsprechend nachgebildet werden. Außerdem wird ein Konzept für den Transport von Fachobjekten über die (Web-)Service-Schnittstellen hinaus notwendig. Setzt man auf abstrakte DTOs (seit EJB3 manchmal als Anti-Patterns verschrien), entsteht zusätzliches Mapping auf der Service-Schicht, das sowohl zur Entwicklungs- als auch Laufzeit Aufwand bereitet. Werden echte JPA-Entitäten verwendet, verliert man die lose Kopplung, die den Charme einer SOA ausmacht, da die (Web-)Service-Consumer direkt von Änderungen an den Entitäten abhängig sind.
Auf der anderen Seite muss man sagen, dass eine Payload, die nur auf IDs operiert, eine homogene Servicelandschaft voraussetzt, in der alle Services mit diesen IDs auch umgehen können und Zugriff auf die Daten haben. Werden Dritt- oder Legacysysteme angebunden, so müssen möglicherweise Fachobjekte durch den Prozess geschleust werden, um diese Systeme zu bedienen.
Fazit
Eine eindeutige Empfehlung für den einen oder anderen Weg kann es an dieser Stelle nicht geben. Ich möchte aber die Sinne dafür schärfen, dass diese Entscheidung durchaus weitreichende Folgen haben kann und gründliche Überlegungen erfordert.