In den letzten Jahren haben die Anforderungen an die Backend-Architektur stark zugenommen. Um diesen Anforderungen gerecht zu werden, setzen immer mehr Firmen auf eine Enterprise-Architektur, welche auch den Ansprüchen von Google und Amazon gerecht werden könnte. Hauptsache, es besteht die Möglichkeit in alle Himmelsrichtungen zu skalieren, denn die nächste AdWords Kampagne bringt sicherlich ein paar Millionen Anwender auf die Seite.
Auch bei Servivum wollten wir uns diese Flexibilität bewahren und hatten daher bei der ersten Implementierung unserer App auf eine Microservice-Architektur gesetzt. Allerdings haben wir uns im Verlauf der Umsetzung dazu entschieden unsere App als Monolith umzusetzen. Gerne möchten wir unsere Erfahrungen teilen und euch somit hoffentlich bei der Entscheidung, welche Architektur für euch die Richtige ist, unterstützen.
Übersicht der Bereiche
Bei Servivum haben wir aktuell drei Bereiche, welche größtenteils automatisiert sind. Dazu zählen die Verwaltung von E-Mail-Accounts & Weiterleitungen, Domains & DNS, sowie die Abrechnung, zu der auch das Vertragswesen gehört.
Diese Bereiche sind allein von der Thematik her gut voneinander abgekapselt, so dass die Entscheidung zur Umsetzung auf Basis einer Microservice Architektur gar nicht so abwegig ist. Somit waren wir allerdings zu Anfang gleich bei sechs Services, welche wir für die Realisierung unserer App benötigten, wenn man die Frontend-App und das API-Gateway mitzählt. Wobei man dazu sagen muss, dass wir für das API-Gateway Kong verwendet haben, wodurch hier nur wenig Implementierungsaufwand anfiel. Die Arbeit, bei der jeder für sich an einem Service entwickelt – ohne Abhängigkeiten zu anderen Services – war durchaus sehr angenehm und einfach zu handhaben. Allerdings sind wir als kleines Team aus Entwickler*innen auf Herausforderungen gestoßen, für welche wir zum gegebenen Zeitpunkt keine Lösungen hatten. Hinzu kommt, dass es kaum Unternehmen aus dem Enterprise-Segment gibt, welche offen über ihre Architektur sprechen oder über Lösungen, die sie gefunden haben, um bestimmte Probleme anzugehen.
Geschwindigkeits- und Flexibilitäts-Einbußen durch Microservice-Architektur
Mit dem Aufbau der Microservice-Architektur haben wir dann genau das erreicht, was wir eigentlich vermeiden wollten. Die Arbeit an einem komplexen Software-Gebilde, welches die Entwicklung neuer Funktionen verlangsamt hat. Gerade als kleines Team aus Entwickler*innen mussten wir viel Zeit in die Verwaltung, Konfiguration und Probleme zwischen den Diensten investieren. Das fängt damit an, dass es aufwendiger war Fehler zu finden. Das Debugging über mehrere Dienste hinweg ist nicht nur zeitintensiver, sondern auch nerviger. Auch Anpassungen oder nachträgliche Änderungen sind mit mehr Arbeit verbunden. Oft merkt man erst während der Entwicklung, dass der Frontend-App noch Daten oder Endpunkte fehlen, welche zur Verfügung gestellt werden müssen.
Zusätzlich bleibt es nicht nur bei einer Kommunikation zwischen der Frontend-App und den dahinterliegenden Diensten. Früher oder später benötigt ein Service Daten eines anderen Services. Die einfachste und schnellste Lösung wäre einen Endpunkt für eine Anfrage zur Verfügung zu stellen. Allerdings wird hierfür eine andere Art der Authentifizierung zwischen den Diensten benötigt und hinzu kommt, dass man nun stark gebundene Abhängigkeiten zwischen den Services hat, welche schwieriger zu handhaben sind. Ausfallsicherheit ist das nächste Thema, welches sehr viel Arbeit verursacht. Wenn der Billing-Service für die monatliche Abrechnung hungrig nach Informationen ist und dann ein anderer Dienst die Arbeit verweigert muss sichergestellt werden, dass nicht die ganze Abrechnung fehlerhaft ist. Hier gibt es sicherlich mehr oder weniger kritische Komponenten, welche auch mal ausfallen oder nicht antworten können, dennoch muss immer sichergestellt werden, dass am Ende niemand vergessen oder Informationen einfach unterschlagen werden.
Ein weiterer Aspekt, der vor allem kleine Teams betrifft, ist das Springen zwischen den Diensten. Ein Microservice bei uns war jeweils ein Git-Repository. Und da jede Entwickler*in an mehreren Services gearbeitet hat, musste auch öfter mal hin und her gesprungen werden, um eine Funktion fertigzustellen. Das hat sich besonders stark bei der Frontend-App und dem Billing-Service gezeigt. Also Services, welche besonders auf Daten der anderen angewiesen waren.
Zurück zum Monolith
Nachdem die Zufriedenheit der Entwickler*innen aufgrund der angesprochenen Probleme nicht mehr unseren Wünschen entsprach, hatten wir uns dazu entschieden die App auf Basis von Laravel als Monolith zu entwickeln. Natürlich gibt es auch hier ähnliche Anforderungen wie bei Microservices. Ausfallsicherheit zum Beispiel. Allerdings müssen die Tools dafür nur einmal eingerichtet werden und das Monitoring und Logging einer Anwendung fällt wesentlich leichter aus, als das vieler kleiner Services. Gerade als kleines Team ist das Entwickeln einer App somit schneller durchzuführen. Der Fokus liegt dabei mehr auf der Umsetzung neuer Funktion und nicht auf der Herstellung einer funktionierenden Umgebung.
Hinzu kommt, dass die Microservices bei uns alle auf Laravel oder Lumen und somit auf PHP basierten. Die Technologien & Frameworks, welche wir eingesetzt haben, bestanden somit aus einer homogenen Masse und mussten nicht kompliziert durch irgendwelche Hacks oder unter Einsatz bestimmter Libraries zusammengeführt werden. Natürlich darf man die Wahl der Architektur nicht nur schwarz-weiß malen. Auch die Monolithische Architektur hat ihre Nachteile. Änderungen im Projekt sind zwar schneller durchgeführt, allerdings kann man sich auch hier einiges „verbasteln“ und das Projekt mutiert zu einem unpflegbaren Monster aus Spaghetti-Code. Hier sind die Entwickler*innen dazu aufgefordert die entsprechende Sorgfalt beizubehalten und nicht nachlässig bei der Entwicklung zu werden.
Nie – Nie wieder Microservices
Die Arbeit an einem Monolithen bringt uns als kleines Team einige Vorteile. Wir sind schneller mit der Entwicklung neuer Funktionen. Wir können die wenigen Ressourcen besser einsetzen. Und wir ziehen vor allem viel Wissen aus der bisherigen Umsetzung. Dazu gehören zum Beispiel Zusammenhänge zwischen den verschiedenen Bereichen zu verstehen. Auf welche Daten müsste zum Beispiel ein Billing-Service überhaupt zugreifen können. All dieses Wissen werden wir in Zukunft gebrauchen können, sollten wir die Möglichkeiten haben, auf eine Microservice Architektur zurück zu wechseln.
Schlusswort
Es gibt viele verschiedene Architekturen, die je nach Unternehmensform und Größe ihre Daseinsberechtigung haben. Mehrere Services bringen mehr Aufwand mit sich. Aufwand, welchen man vor allem mit einem größeren Team stemmen kann. Hier gilt es herauszufinden, welche Architektur am besten zur Struktur passt. Nicht nur die Größe und Mittel eines Teams spielen eine Rolle. Auch die Technologie, welche verwendet wird oder verwendet werden muss. Stark divergierende Tech-Stacks lassen sich einfacher in einer Service-Architektur umsetzen als in einem Monolithen. Dennoch setzen viele Unternehmen oder Startups gleich auf eine Microservice Architektur, obwohl nie evaluiert wurde, ob das für den entsprechenden Anwendungsfall Sinn macht. Es sollte sich also vor der Wahl ausreichend Gedanken dazu gemacht werden, wo der technische Unterschied zwischen den Services liegt und ob eine kompliziertere Architektur den Aufwand rechtfertig oder ob man nicht doch lieber mit einer App startet, welche ggf. zu einem späteren Zeitpunkt auseinandergezogen wird.
Und was ist eure Meinung?
Wir möchten gerne mit euch ins Gespräch kommen. Habt ihr Ideen, Fragen oder Anregungen zu diesem Thema? Aus welchen Gründen habt ihr euch für die eine oder andere Architektur entschieden. Setzt ihr dabei auf Managed Services oder verwaltet ihr eure Architektur selbst? Schreibt uns doch via Mail oder auf Twitter. Wir freuen uns eure Meinungen.
Bild von Clint Adair