{"id":41,"date":"2009-07-28T20:52:13","date_gmt":"2009-07-28T20:52:13","guid":{"rendered":"http:\/\/euve3303.vserver.de\/stefan\/blog\/?p=43"},"modified":"2011-12-01T21:50:45","modified_gmt":"2011-12-01T20:50:45","slug":"workflow-engine-einmal-anders","status":"publish","type":"post","link":"https:\/\/cogito-ergo-blog.de\/blog\/2009\/07\/28\/workflow-engine-einmal-anders\/","title":{"rendered":"Workflow-Engine einmal anders"},"content":{"rendered":"<p style=\"margin-bottom: 0cm;\">Schon in einigen Projekten war die Herausforderung bestimmte Abl\u00e4ufe oder auch \u201eProzesse\u201c hochskalierbar, verl\u00e4sslich ausf\u00fchren zu k\u00f6nnen. Dabei kam dann von den einen Projektverantwortlichen schnell der Ruf nach einer Workflow-Engine, von den anderen eher das Gegenteil: \u201eBlo\u00df keine Workflow-Engine &#8230;\u201c.<\/p>\n<p style=\"margin-bottom: 0cm;\">Ich selbst bin auch nicht unbedingt ein Freund von \u201egraphischer Programmierung\u201c oder geschw\u00e4tzigem XML, was fast schon Programmiersprache sein will, aber in fast jeder<br \/>\nHinsicht unhandlicher ist als eine \u201enormale\u201c Programmiersprache wie <a href=\"http:\/\/www.scala-lang.org\/\">Scala<\/a> oder Java.<\/p>\n<p style=\"margin-bottom: 0cm;\">Aus diesem Grund reizte mich die Idee einen alternativen Ansatz zu versuchen. Da ich, wie gerade schon erw\u00e4hnt, kein Freund von \u201ein XML programmieren\u201c bin, sollte die<br \/>\nBeschreibung des \u201eProzesses\u201c &#8211; das Prozessmodell \u2013 in Java erfolgen.<\/p>\n<p style=\"margin-bottom: 0cm;\">Hier bietet sich das <a href=\"http:\/\/de.wikipedia.org\/wiki\/Zustand_(Entwurfsmuster)\">State-Pattern<\/a> an, welches eine Prozessablauf mit Hilfe von Zustandsobjekten und einem Kontext beschreibt. Konkret werden also nur Interfaces bzw. abstrakte Basisklassen ben\u00f6tigt, die von einem konkreten Prozess implementiert<br \/>\nwerden. Dazu der \u201eContract\u201c der den Ablauf \/ die Semantik beschreibt und schon kann ein \u201eProzess\u201c statt in XML in Java geschrieben werden.<\/p>\n<p><!--more--><\/p>\n<p style=\"margin-bottom: 0cm;\">Allerdings kann man nun einwenden, dass das normale Ausf\u00fchrungsmodell einer JVM mit Threads nicht die gleichen Vorteile bietet wie eine Workflow-Engine.<\/p>\n<p style=\"margin-bottom: 0cm;\">Inspiriert von den Ans\u00e4tzen von <a href=\"https:\/\/dalma.dev.java.net\/nonav\/maven\/index.html\">Dalma<\/a> und <a href=\"http:\/\/commons.apache.org\/sandbox\/javaflow\/\">Javaflow<\/a> oder auch den Arbeiten von Doug Lea (FJTasks) ist aber auch auf einer Java VM mehr m\u00f6glich, als einfach f\u00fcr jeden Prozess<br \/>\nund jede seiner Nebenl\u00e4ufigkeiten einen neuen Thread zu starten.<\/p>\n<p style=\"margin-bottom: 0cm;\">W\u00fcrde man das tun, w\u00e4ren diese bei den eingangs genannten Anforderungen sicher bald aufgebraucht (viele Prozessinstanzen, wom\u00f6glich viele davon nur wartend).<\/p>\n<p style=\"margin-bottom: 0cm;\">Auch mit der Skalierbarkeit haben viele Workflow-Engines gewisse Probleme, weil sich die Arbeit schlecht \u00fcber einen Cluster verteilen l\u00e4\u00dft. Aber auch hier gibt es im Standard<br \/>\nJava gute L\u00f6sungans\u00e4tze, wie z.B. <a href=\"http:\/\/www.gridgain.com\/\">GridGain<\/a>.<\/p>\n<p style=\"margin-bottom: 0cm;\">Ein weiterer Aspekt, den Workflow-Engine bedienen, ist Prozesspersistenz. Prozesse, die auf der Engine ablaufen, lassen sich persistieren. Damit ist der Ablauf unterbrechbar, wiederherstellbar und nachvollziehbar. Wenn allerdings Prozesse normale durch normale Java-Objekte dargestellt werden, dann lassen sie sich auch mit einfachen ORM Mitteln persistieren.<\/p>\n<p style=\"margin-bottom: 0cm;\">Zu guter letzt sind die meisten Prozesse immer auf irgendwelche Services angewiesen, die von ihnen aufgerufen werden, oder Calls an die Prozesse absetzen. Hierzu soll<br \/>\nf\u00fcr das Java basierende Prozessmodell ein Container \/Application-Server zum Einsatz kommen. Meine Wahl fiel auf <a href=\"http:\/\/www.springsource.org\/\">Spring<\/a>, wobei sicher auch andere L\u00f6sungen denkbar w\u00e4ren.<\/p>\n<p style=\"margin-bottom: 0cm;\">Das Rezept f\u00fcr <em>meine <\/em>Workflow-Engine lautet also:<\/p>\n<ul>\n<li>\n<p style=\"margin-bottom: 0cm;\">Prozesse sind Java-Klassen, die nach dem State-Pattern einen Ablauf implementieren.<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">Diese Klassen sind typischerweise Spring-Beans, die vom Container \u201eServices\u201c konsumieren.<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">Die Klassen sind Serializable und damit \u201eRemoting\u201c-f\u00e4hig f\u00fcr GridGain.<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">Die Klassen tragen (optional) Persistenz-Annotationen, welche die Engine daf\u00fcr nutzt den Prozesszustand zu persistieren.<\/p>\n<\/li>\n<\/ul>\n<p style=\"margin-bottom: 0cm;\">Heraus kommt eine L\u00f6sung,<\/p>\n<ul>\n<li>\n<p style=\"margin-bottom: 0cm;\">die hochskalierbar ist, weil Prozesse \u00fcber GridGain auf einem Cluster von Nodes verteilt werden k\u00f6nnen.<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">die den gewohnten Komfort einer IOC-Umgebung genie\u00dft, bei der nach Belieben \u201eServices\u201c genutzt werden k\u00f6nnen (nat\u00fcrlich nicht nur Webservices).<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">die den Prozesszustand nach jedem Prozessschritt mit Hilfe eines Persistenzproviders wie z.B. Hibernate persistiert.<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">die Prozesse einfach als Java-Programm beschrieben, welches mit einfachsten Mitteln und voller IDE Unters\u00fctzung entworfen werden kann.<\/p>\n<\/li>\n<\/ul>\n<p style=\"margin-bottom: 0cm;\">Besonders den letzten Punkt m\u00f6chte ich noch einmal unterstreichen: Man kann es gar nicht hoch genug bewerten, wie viele Vorteile sich allein dadurch ergeben, dass man in<br \/>\nder gewohnten Umgebung arbeiten kann:<\/p>\n<ul>\n<li>\n<p style=\"margin-bottom: 0cm;\">kein Lernen einer Prozessbeschreibungssprache (in XML).<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">alle M\u00f6glichkeiten und Konstrukte einer Programmiersprache wie Java.<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">die gewohnte IDE.<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">simples Debuggen und Testen (noch besser zu unterst\u00fctzen durch Mocks und eine spezielle Engine, die ein lokales Debuggen direkt erm\u00f6glicht).<\/p>\n<\/li>\n<li>\n<p style=\"margin-bottom: 0cm;\">Einfachstes Wiederverwenden von vorhandenem Code oder vorhandenen Services (meist sind keinerlei \u201eWrapper\u201c oder \u201eAdapter\u201c notwendig).<\/p>\n<\/li>\n<\/ul>\n<p style=\"margin-bottom: 0cm;\">Wie die L\u00f6sung konkret aussieht, werde ich wohl heute nicht mehr zusammenschreiben, deshalb wird\u2019s demn\u00e4chst hier ne Fortsetzung geben &#8230;<\/p>\n<p style=\"margin-bottom: 0cm;\">\n","protected":false},"excerpt":{"rendered":"<p>Schon in einigen Projekten war die Herausforderung bestimmte Abl\u00e4ufe oder auch \u201eProzesse\u201c hochskalierbar, verl\u00e4sslich ausf\u00fchren zu k\u00f6nnen. Dabei kam dann von den einen Projektverantwortlichen schnell der Ruf nach einer Workflow-Engine, von den anderen eher das Gegenteil: \u201eBlo\u00df keine Workflow-Engine &#8230;\u201c. &hellip; <a href=\"https:\/\/cogito-ergo-blog.de\/blog\/2009\/07\/28\/workflow-engine-einmal-anders\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"_links":{"self":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/41"}],"collection":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=41"}],"version-history":[{"count":4,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/41\/revisions"}],"predecessor-version":[{"id":10071,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/41\/revisions\/10071"}],"wp:attachment":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=41"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=41"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=41"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}