Software Architektur: Mehr Flexibilität für Startups

Die Silberrücken arbeiten viel mit Startups zusammen, teilweise weil wir Produkte von Startups in anderen Organisationen einführen, teilweise weil wir Architekturen für Startups entwerfen. Insbesondere letzteres macht mir persönlich sehr grossen Spass, denn es handelt sich an dieser Stelle um Greenfield Projekte, bei denen modernste Architekturstile, Methoden und Technologien zum Einsatz kommen können. So auch in einem aktuellen Projekt, dessen Werdegang ich hier künftig Stück für Stück nachzeichnen möchte. Welcher Startup das ist, das wird noch nicht verraten 🙂

Flexibilität als Erfolgsfaktor

Noch mehr als andere Organisationen sind Startups durch dramatischen Wandel geprägt. Die initiale Geschäftsidee verändert sich im Laufe ihrer Operationalisierung enorm, wenn sie auf die Wirklichkeit der Märkte trifft. Neue Kontakte führen zu neuen Möglichkeiten, die wahrgenommen werden möchten. Um die Entwicklung des Geschäftsmodells zu begleiten, haben sich in den letzten Jahren verschiedene Methoden entwickelt, beispielsweise das Design Thinking, aber auch das klassische Requirements Engineering liefert einen wertvollen Beitrag. Aber egal welche Methoden zum Zuge kommen, ein bleibendes Bedürfnis des Startups bleibt es, sich verändern zu können.

Für mich als Architekt bedeutet dies vor allem einen möglichst flexiblen und belastbaren Entwurf zu entwickeln, der die Veränderung des Geschäftsmodells begleiten kann. Startups sind chronisch knapp bei Kasse und müssen sehr vorsichtig mit ihren Investitionen umgehen. Es wäre schlichtweg ein Desaster, wenn die entwickelte Architektur weggeworfen werden müssten, weil sie nicht mehr zum Business passen. Die Frage ist also welcher Architekturstil am besten passt. Die Antwort ist leider nicht eindeutig, denn es gibt nun mal keine Silver Bullets: welche Architektur für Ihr konkretes Problem am besten ist, muss immer im Kontext bewertet werden. Aber ein Beispiel für einen Architekturstil, der mit Veränderung gut umgehen kann, ist der der nachrichtengesteuerten Architektur.

Nachrichtensteuerung verstehen

In einer nachrichtengesteuerten Architektur wird der Zustand des Systems in Nachrichten hinterlegt, und zwar bei einem Websystem im E-Commerce in einer domänenspezifischen Nachricht, die für Technik und Geschäft gleichermassen bedeutsam und wertvoll ist. Fowler [1] beschreibt ein einfaches Beispiel: Möchte man den Weg eines Schiffes verfolgen, so erzeugt man jedes Mal, wenn das Schiff in einen Hafen einläuft eine Nachricht, die abgespeichert wird. Möchte man den Weg des Schiffes über seine Lebenszeit verfolgen, kann man die Nachrichten später abspielen. Dies ist eine völlig andere Herangehensweise als den Zustandsautomaten eines Systems auf ein SQL Schema abzubilden, wie es traditionell der Fall ist.

Die gesamte Genese des Geschäftsobjekts (im Weiteren auch als Modell bezeichnet) lässt sich aus den Nachrichten rekonstruieren. Werden alle Zustandsveränderungen des Systems in Nachrichten gekapselt, so lässt sich somit der gesamte Systemzustand aus dem Nachrichtenfluss rekonstruieren. Dies hat entscheidende Vorteile für die Architektur, aus den folgenden Gründen:

  • Der Zustand kann zu jedem beliebigen Zeitpunkt wiederhergestellt werden, indem die Nachrichten bis zu einem bestimmten Punkt abgespielt werden, aber nicht darüber hinaus. Dies ist bei der Systemanalyse hilfreich, und auch beim Testing. Zudem ermöglicht es uns, verschiedene Zustandsbäume abzuzweigen, beispielsweise für Was-wäre-wenn-Simulationen. Versionskontrollsysteme wie Git oder Subversion sind prominente Vertreter dieses Architekturstils.
  • Wir können auch schwere Fehler in der Applikation durch Korrekturen am Nachrichtenstrom später korrigieren. Angenommen es gab ein Problem bei der Mehrwertsteuerberechnung, dann können wir diese später durch Manipulation der Nachrichten bereinigen, und die Rechnungen neu drucken.
  • Der Zustand eines Modells und des gesamten Systems kann aus dem Nachrichtenstrom jederzeit rekonstruiert werden. Wenn diese Rekonstruktion effizient gelingt, löst dies das dynamische Skalierungsproblem grosser Storage States. Durch die Nachrichtenorientierte Herangehensweise lassen sich die Zustände von Geschäftsobjekten nämlich effektiv entkoppeln. In Kombination mit einer Microservice Architektur kann so ein hochgradig horizontal skalierbares System entwickeln. Hierzu in einem späteren Blog mehr, denn es kommt darauf an…
  • Die Nachrichten begünstigen die Auditierbarkeit des Systems, denn alle Veränderungen lassen sich nachvollziehen. Die Auditierbarkeit ist eine verbreitete Geschäftsanforderung, die wir bei der Wahl dieser Art von Architektur quasi geschenkt bekommen.

Die Architektur hat aber auch Nachteile, die ich nicht vorenthalten möchte. Ganz allgemein kann man über diesen Stil nämlich auch folgendes sagen:

  • Die Verarbeitung von Nachrichten ist asynchron, was bedeutet, dass am System ausgelöste Änderungen nicht sofort sichtbar werden (und dies müssen wir dann im UX lösen), sondern auch, dass wir Lastspitzen durch die verzögerte Bearbeitung abdämpfen können.
  • Die Asynchronität erhöht die Komplexität des Systems. Wir können nicht mehr bei der Fehlersuche einen isolierten Service analysieren, und das kann die Fehlersuche komplizierter machen. Es ist zudem leicht, den Überblick zu verlieren, weswegen es hier mehr als an anderer Stelle darauf ankommt eine saubere Dokumentation der Geschäftsprozesse vorliegen zu haben. Jeder Prozess sollte eine diskrete Abfolge von Tätigkeiten darstellen, die nicht blockierend hintereinander ausgeführt werden können.
  • Spätere Änderungen an den Modellen spiegeln sich nicht automatisch in die Event Queue. Bei Änderungen an einem klassischen SQL Modell wird dieses eben einmal transformiert und alles ist gut, bei einer nachrichtengesteuerten Architektur muss ich entweder die Modelle versionieren, oder ich schreibe die Events in der Queue um. Werden die Modelle versioniert, entsteht einige zusätzliche Komplexität in der Rekonstruktion eines spezifischen Zustands.

Schnitte der Umsetzung

Bei der Umsetzung dieses Stils gibt es einiges zu beachten, aber das würde den Umfang dieses Blogs sprengen. Ein wesentlicher Faktor ist die saubere Implementierung der Nachrichten, welche gemäss unserem Credo der Isolation so viele Informationen wie notwendig enthalten sollten, aber nicht mehr (um den Speicher zu optimieren). Gleichzeitig sollten wir darauf achten, dass kein Downstream Akteur Callbacks auf andere Services auslösen sollte, um die Nachrichten zu verarbeiten. Dies senkt die Kopplung, erhöht die Resilienz des Systems, und erzeugt weniger Last. Davon ausgenommen sind etwaige Callbacks um das Ende einer Verarbeitung anzuzeigen, falls dies benötigt wird. In diesem Fall sollte die Nachricht einen Link auf den Absender enthalten.

Es gilt generell das Pattern der Command Message für die Nachrichten, die auf dem Zielsystem eine Zustandsänderung verursachen. Ein Beispiel für Nachrichten, die nicht in unser Schema passen, sind Events für die Steuerung des UI, so wie sie im Browser ausgelöst werden. Die Umsetzung einer solchen Architektur erfordert zudem eine Message Queue, auf die man sich verlassen kann. Nutzer von PaaS Umgebungen [3], bei denen Messaging als Plattform Service geboten wird, sind im Vorteil. Die folgende Abbildung zeigt ein Beispiel, wie solch eine Architektur umgesetzt werden könnte. Ich werde in folgenden Blogposts noch mehr Varianten aufzeigen und ein paar Entscheidungswege aufzeichnen. Beim hier angegeben Beispiel fliessen die Nachrichten wie folgt:

Beispiel für eine Nachrichtengetriebene Architektur
Beispiel für eine Nachrichtengetriebene Architektur

 

  1. Ein Benutzer löst eine Domänennachricht aus, beispielsweise indem er sein Profil anpasst und eine neue Lieferadresse angibt. Wir möchten die alte Adresse nicht einfach überschreiben, weil es unter anderem hier und heute Paketsendungen geben könnte, die diese verwenden.
  2. Der Domänendienst (hier als Microservice eingezeichnet) nimmt die Nachricht entgegen, versieht sie mit einigen zusätzlichen Daten (Timestamp) und schreibt sie in die Queue. Der Service kann nun wählen, ob er auf ein Update seines Zustands wartet, oder per Client Compensation den lokalen Zustand sofort aktualisiert.
  3. Ein Event Worker entnimmt der Queue eine Nachricht nach der anderen. Je nach Geschäftsregeln werden die Nachrichten anders behandelt. So kann der Event Worker beispielsweise bei bestimmten Ereignisse eine E-Mail auslösen, die meisten jedoch prüft er auf Korrektheit und schreibt sie in den entsprechenden Storage State. Der Event Worker hat noch andere Aufgaben, die in einem folgenden Blog beschrieben werden.
  4. Der Event Sourcer hat die Aufgabe das Modell des Service aus den Nachrichten im Storage State zu konstruieren. Auch hier gibt es eine Vielzahl von wichtigen Details und weiteren Entscheidungen, die getroffen werden wollen. Snapshotting und Caching sind zwei mögliche Techniken. Am Ende soll unser Microservice einfach den richtigen Zustand in möglichst kurzer Zeit geliefert bekommen.

Ausblick

Eine nachrichtengesteuerte Architektur macht unser System komplexer. Da es sich um eine relativ neue Herangehensweise handelt, die vielen nicht vertraut ist, sind insbesondere zu Beginn Probleme in der Umsetzung zu erwarten. Die Vorteile dieser Art von Architektur sind jedoch gross, und meiner Meinung nach ist es die Formbarkeit des Nachrichtenstroms der zentrale Faktor für einen Startup, das sich verändern können muss.

Sehr gerne schreibe ich später noch mehr zu den Details in der Umsetzung und die weitere Entwicklung des Startups. Wenn Sie hierzu Fragen haben, zögern Sie bitte nicht mit mir in Kontakt zu treten oder einen Kommentar zu schreiben.

Links & Literatur

[1] Martin Fowler, https://martinfowler.com/eaaDev/EventSourcing.html

[2] Daniel Takai, Architektur für Websysteme, 2017, Carl Hanser Verlag, München

[3] Christoph Huber, PaaS evaluieren, https://silberruecken.ch/2018/02/15/paas-evaluieren/

Kommentar verfassen