Strangler Pattern: Herausforderungen bei der Umstellung auf Spring Boot

Montag, 7.10.2019

JAVA-EE-Header-Blog-Serie_viadee

Im ersten Teil der Blogreihe wurde ausführlich berichtet, wieso sich Spring Boot mittlerweile als De-facto-Standard im Enterprise-Java-Umfeld etabliert hat. Trotzdem lassen sich bewährte JEE-Anwendungen nicht einfach in das Spring-Ökosystem überführen. Schrittweise steuerbar und risikoarm wünscht man sich eine Migration: Das gelingt mit dem Strangler Pattern auch für JEE-Anwendungen – ein Erfahrungsbericht. 

Die Migration einer veralteten Anwendung in eine neue Umgebung ist Alltag und bringt doch Herausforderungen mit sich. Die Erkenntnis ist weder neu noch überraschend. Der Begriff "Legacy System" ist etabliert und als ernsthafte Herausforderung in der IT-Welt angesehen. Das sogenannte "Strangler Pattern"1 ist ein mögliches Vorgehensmodell, um eine alte monolithische Anwendung in eine moderne Anwendung zu transformieren. Analog zur Würgefeige (Strangler Fig2), die sich so lange um einen alten Baum schlingt, bis dieser abgestorben ist, ist die Idee, das alte System nach und nach in ein neues System zu transformieren, bis das alte System gänzlich ersetzt ist und abgeschaltet werden kann. Der vermutlich größte Vorteil des Strangler Patterns ist, dass das alte System nicht auf einmal abgeschaltet wird, sondern die Migration nach und nach vorangetrieben wird. Das Tagesgeschäft wird also weniger beeinträchtigt.

Das Strangler Pattern als Vorgehensmodell

In einem großen Migrationsprojekt wenden wir das Strangler Pattern an und transformieren eine monolithische JEE-Anwendung in Spring-Boot-Services. Die Migration ohne "Big Bang" war hierbei eine kritische Voraussetzung, weshalb wir uns unter anderem für das Strangler Pattern als Vorgehensmodell entschieden haben. Wir hatten natürlich trotzdem mit einigen Hürden zu kämpfen, die sich uns auf dem Weg zur neuen modernen Anwendung in den Weg stellten. Diese Hürden waren nicht unbedingt vom Strangler Pattern verursacht: Die Migration eines Legacy Systems beinhaltet immer Überraschungen. Jeder, der sich im Code einer großen monolithischen Anwendung schon einmal umgeschaut hat, kennt das Gefühl, nicht zu wissen, was der Code im Gesamtzusammenhang macht. Eine schier unübersichtliche Konstruktion verschiedener Systeme, die über unterschiedlichste technologische Wege kommunizieren, bei der nicht immer auf den ersten (oder zweiten oder x-ten) Blick erkennbar ist, welche Prozesse abgebildet sind und wie Daten plötzlich von A nach B kommen, bleibt eben zu jedem Zeitpunkt eine Büchse der Pandora. Und trotzdem haben wir viel gelernt, sowohl technologisch als auch methodisch haben wir immer wieder wertvolle Erkenntnisse sammeln können. Und gerade deswegen möchten wir hier einige Hürden abseits des Happy Path skizzieren.

Wuergefeige
Die Überlebensstrategie einer Würgefeige kann Vorbild für die Migration von Legacy Systemen sein.

Die ursprüngliche Motivation für das besagte Migrationsprojekt war vielfältig. Die veraltete Laufzeitumgebung war nicht mehr mit einer neuen Java-Version lauffähig, gleichzeitig wuchsen die Anforderungen an die Skalierbarkeit der Anwendung und deren Weiterentwicklung wurde zunehmend aufwendiger.

Der erste Schritt bei der Migration à la Strangler Pattern war in unserem Projekt die konsequente Trennung verschiedener Schichten, konkret haben wir die fachliche Logik ganz gezielt von Schnittstellen und der JEE-Infrastruktur gelöst. Aus jeder JEE-Bean wurde also sorgfältig die Fachlogik herausgeschnitten und für Interfaces und Transfertypen wurden extra API-Artefakte geschaffen. Insgesamt hat sich dadurch die Zahl der Module und Artefakte erst einmal erhöht bzw. ganz konkret mindestens verdreifacht. Aus jedem ursprünglichen Artefakt wurden drei einzelne Artefakte: API, Impl und Domain (die Fachlogik). Dadurch konnten wir veraltete Bibliotheken wie beispielsweise org.jboss.ejb3 oder das veraltete JNP-Protokoll3 strikt abkapseln.
spring migration
Dies ermöglicht das gezielte Umziehen der Fachlogik; die Infrastruktur und Schnittstellen können vorerst komplett erhalten bleiben. Die ursprüngliche Software bleibt als Fassade bestehen und leitet Anfragen lediglich als REST-Aufrufe an die neue Software weiter. Die daraus resultierende Komplexität muss allerdings transparent und kontinuierlich kommuniziert werden, da sonst schnell der Überblick verloren geht. Besonders relevant ist dies, da gleichzeitig die Anwendung weiterentwickelt wird und die Gefahr besteht, dass Code an falscher Stelle abgelegt wird. Neben der kontinuierlichen Kommunikation in das Entwicklungsteam muss der Fortschritt auch beständig zu Fachseite und Management kommuniziert werden, da von außen lange Zeit erstmal keine Veränderung erkennbar ist.

Migration von innen nach außen

Die zu migrierenden Komponenten müssen strikt von innen nach außen umgezogen werden, das heißt, es dürfen nur Komponenten migriert werden, die keine Abhängigkeiten zum veralteten Monolithen haben. Resultierend daraus werden zuallererst Komponenten komplett ohne interne Abhängigkeiten migriert. Diese stellen (natürlicherweise) den Kern der Anwendung dar und sind in besonders vielen fachlichen Prozessen kritisch. Wir können also nicht auf die Erfahrung aus den Migrationen zig anderer (unkritischer) Komponenten zurückgreifen. Konkret bedeutet das einen erhöhten Testaufwand und eine Zitterpartie beim ersten initialen Rollout der Anwendung.

Im Folgenden wird beispielsweise der CustomerService sowohl vom AccountService als auch vom OrderService verwendet. Wenn es da also zu Fehlern kommt, werden potenziell auch die Prozesse der beiden vorgelagerten Services dadurch beeinflusst. Trotzdem würde in diesem Beispiel zuallererst der CustomerService migriert, da dieser keine Abhängigkeiten hat. Anschließend könnte man den AccountService migrieren, da dieser nur Abhängigkeiten auf den CustomerService hat, dieser aber schon migriert wurde und daher in der neuen Anwendung schon zur Verfügung steht. Zuallerletzt könnte man den OrderService migrieren, da auch dieser dann nur von Komponenten in der neuen Anwendung abhängig ist.
spring migration

Fallstricke und Hürden

Im Spring Framework gilt grundsätzlich das Prinzip "Convention over Configuration". Auch wenn es nicht so vorgesehen ist, kann man potenziell viel konfigurieren. Im vorhandenen JEE-Container wurden bereits technische Belange wie Clustering, JMS-Broker und Transaction Management betrieben und jede Abweichung war quasi ausgeschlossen. Daher musste dieser schon vor langer Zeit konfigurierte JEE-Container also gründlich durchleuchtet werden, um die Spring Boot-Anwendung anschließend angemessen konfigurieren zu können. Oft haben wir erst kleinere POCs geschrieben, um garantieren zu können, dass wir für jeden Anwendungsfall gewappnet waren. Ein stetes Abwägen zwischen "dem JEE-Container ähnlicher" und "in Spring Boot so üblich" war die Folge. Entscheidungen wurden aber so bewusster getroffen. Das war aufwendig, aber nachhaltig, da verschiedene Vor- und Nachteile offen diskutiert werden mussten.

Eine weitere Hürde war die mittlerweile üppige Sammlung an Abhängigkeiten der Anwendung, die teilweise mit sehr alten Versionen verwendet wurden. Da manche Abhängigkeiten nicht mehr ohne weiteres aktualisiert werden konnten, mussten wir vor der eigentlichen Migration erst einmal ordentlich analysieren, welches Versionsupdate mehr oder weniger Aufmerksamkeit brauchte. Das artete teilweise in mittelgroße Nebenprojekte aus, da sich eine Java-API geändert hatte, die im kompletten Code verstreut benutzt wurde. Bei einer Komponente ergab die Analyse leider auch, dass eine Migration sich einfach nicht lohnen würde und es keine sinnvolle Zieltechnologie dafür gab.

In unsere Hände spielten uns die vor Ort üblichen regelmäßigen und flexiblen Rollouts. Gut ausgearbeitete Deployment Pipelines waren schon vorhanden, die JEE-Anwendung konnte also von uns selbst auf Knopfdruck aus- oder zurückgerollt werden. Da das Strangler Pattern aber vorsieht, die neue Anwendung über einen gewissen Zeitraum parallel zur alten Anwendung zu betreiben, mussten wir von Anfang an genauso gute und flexible Deployment Pipelines für die neue Anwendung zur Verfügung stellen. Darüber hinaus lag und liegt auch der Betrieb beider Anwendungen in unserer Abteilung; sehr eingespielte DevOps-Prozesse mussten also infrage gestellt und neu organisiert werden. Diesen Punkt haben wir initial etwas unterschätzt. Insgesamt können wir hier eine sehr steile Lernkurve vorweisen, haben aber mittlerweile nach anfänglichen Turbulenzen ruhiges Fahrwasser erreicht.

Insgesamt war diese Migration ein unheimlich spannendes Projekt. Die sehr abwechslungsreichen und vielfältigen Aufgabenstellungen haben uns einen tiefen Einblick in Java Enterprise-Anwendungen erlaubt. Gemeinsam konnten wir alle Herausforderungen meistern und sind nun gespannt auf die weiteren Schritte. Als nächstes Etappenziel muss die alte Software noch abgeschaltet werden, die Konsumenten der Schnittstellen und anliegende Systeme müssen also in die Lage versetzt werden, mit der neuen Welt zu sprechen. Das Strangler Pattern erlaubt es uns aber, diese Schritte nach und nach anzugehen. Das verringert den Druck und somit können wir uns auf die wesentlichen Punkte konzentrieren. Noch werden wir eine Zeit lang mit beiden Anwendungen arbeiten, aber dennoch sind wir auf einem guten Weg.


 

DIESER BEITRAG IST TEIL EINER SERIE:
Teil 1: Java EE ist tot – es lebe Spring (Boot)!
Teil 2: Im Griff der Würgefeige: Herausforderungen bei der Spring Migration
Teil 3: Mein JEE-API im Application-Server ist weg. Was nun?
Teil 4: Weg von Java EE - so gelingt die Migration

CTA - Anmeldung zur Blog-Serie - Das Leben nach JAVA EE


Quellen:
1) https://martinfowler.com/bliki/StranglerFigApplication.html
2) https://en.wikipedia.org/wiki/Strangler_fig
3) https://docs.jboss.org/author/display/AS71/Remote+EJB+invocations+via+JNDI+-+EJB+client+API+or+remote-naming+project




 


zurück zur Blogübersicht

Diese Beiträge könnten Sie ebenfalls interessieren

Keinen Beitrag verpassen – viadee Blog abonnieren

Jetzt Blog abonnieren!

Kommentare

Pia Diedam

Pia Diedam

Pia Diedam ist seit 2017 Beraterin bei der viadee. Sowohl im Kundeneinsatz als auch im internen Bereich Testautomatisierung beschäftigt sie sich schwerpunktmäßig mit der Java-Entwicklung.