Kolumne: Stropek as a Service

Monolith oder Flickenteppich – Serverless Microservices revolutionieren die Cloud
Kommentare

Bezeichnet man heute eine Softwarelösung aus technischer Sicht als Monolith, ist das selten als Kompliment gemeint. Der Trend geht zu immer loserer Kopplung, zu kleinen autonomen Services, die erst im Zusammenspiel einen echten Nutzen für die Endanwender bieten.

Man verspricht sich von diesen so genannten Microservices höhere Flexibilität und rasche Innovation. Schließlich kann jeder Service aufgrund seiner losen Kopplung unabhängig weiterentwickelt oder wenn notwendig mithilfe einer neuen Basistechnologie sogar neu entwickelt werden.

Microservices üben einen besonderen Reiz auf Softwarehersteller aus, die im Lauf der Jahre technische Schulden angehäuft haben und heute auf veralteten starren Codebasen sitzen. Alle Komponenten sind ineinander verwoben, es fehlen automatisierte Tests, die ursprünglichen Entwicklerinnen und Entwickler sind nicht mehr im Team, für eine komplette Neuentwicklung fehlen die Ressourcen und der Ruf der Kunden nach neuen Features konkurriert mit Restrukturierungsprojekten. Ich kenne viele Firmen, die in dieser Zwickmühle gefangen sind. Einige sind am Markt sogar sehr erfolgreich, weil ihre Software im Lauf der Jahre funktional dazugelernt hat und heute den Bedarf der Kunden perfekt abbildet. Technisch stecken sie aber in WinForms, ASP.NET Web Forms, C++ mit MFC, VB6, .NET 4 und Co. fest. Innovation ist für sie wie Mikado spielen – greift man an einer Stelle etwas an, wackeln zwangsläufig viele andere Stellen, die man besser nicht hätte angreifen sollen.

Das zweischneidige Schwert der engen Kopplung

Monolithen haben aber auch ihren Reiz. Das Wort „Monolith“ bedeutet laut Wikipedia „kompakt“ oder „aus einem Guss“. Bezeichnet ein Benutzer eine Software mit diesen Adjektiven, ist das durchaus ein Kompliment. Die Teile greifen wie geschmiert ineinander, alles passt gut zusammen.

Auch Softwareentwickler kennen die Vorteile einer monolithischen Lösung. Der gesamte Code ist in einer Projektmappe zusammengefasst. Debugging wird dadurch leichter. Ein Funktionsaufruf ist massiv viel schneller als der Aufruf eines Web-API. Compiler und damit verbundene Tools können eine ganze Menge Fehler durch statische Codeanalyse entdecken, ohne dass man dafür auch nur eine Zeile Testcode schreiben müsste. Viele kommerzielle Entwicklungsumgebungen bieten nützliche Funktionen, mit denen man im Code navigieren und durch statische Analyse Architekturdiagramme erzeugen kann.

Dazu kommt, dass Software, die von außen als Monolith wahrgenommen wird, intern durchaus Struktur haben kann. Module, Paketmanager, Dependency Injection, Interfaces, Basisklassen – moderne Programmiersprachen und Frameworks enthalten viele Konzepte, um große Softwarelösungen zu gliedern und interne Abhängigkeiten zu managen.

Wie Monolithen zu Problem werden

Wie wird ein Monolith also zum Problem? Die Gründe, die ich bei meiner Arbeit mit Softwareherstellern wahrnehme, sind vielschichtig. Man kann sie aber auf einen gemeinsamen Nenner zurückführen: Softwarealterung. Hier drei typische Beispiele, die veranschaulichen, was ich meine:

  • Kunden wehren sich gegen Updates. Stabilität wird viel höher bewertet als Modernisierung und technische Weiterentwicklung. Irgendwann sitzt man auf steinalten Komponenten und kann sich eine Aktualisierung aus Zeitmangel oder Ressourcenengpässen nicht mehr leisten.
  • Technische Strukturen oder interne Richtlinien erzwingen eine Alles-oder-nichts-Kultur. Auf eine neue Frameworkversion darf man nur umstellen, wenn alle den Umstieg mitmachen. Irgendwann bewegt sich nichts mehr, und die Programmiertalente laufen frustriert davon.
  • Um Kunden kurzfristig bedienen zu können, werden neue Funktionen nicht sauber in die Architektur integriert. Für automatisierte Tests ist sowieso keine Zeit. Irgendwann steht man vor einem großen Durcheinander, in dem sich niemand mehr traut, etwas zu ändern.

Bei all diesen Beispielen liegt die Wurzel des Problems nicht rein in der Technik. Es ist eine Kombination aus unternehmerischen Entscheidungen, organisatorischen Rahmenbedingungen und technischen Fehlern. Besonders kritisch ist die Situation meiner Erfahrung nach in Firmen, bei denen Software nicht im Mittelpunkt des Interesses steht. Die Tatsache, dass Software altert, ist einem Managementteam ohne entsprechender softwaretechnischer Ausbildung oder Erfahrung schwer zu vermitteln. Erst wenn es spät ist und die Probleme unübersehbar sind, wird nach Lösungen gerufen.

Software Architecture Summit 2017

The Core of Domain-Driven Design

mit Carola Lilienthal (Workplace Solutions)

Distributed Systems

mit Kyle Kingsbury (Independent Consultant)

Micro- und Nanoservices – das andere Extrem

Alle großen Cloud-Provider haben den Bedarf von Kunden nach lose gekoppelten, kleinen Services erkannt und Angebote erstellt, die als Serverless Microservices bezeichnet werden. Amazon Serverless Framework, Microsoft Azure Functions und Google Cloud Functions sind nur drei Beispiele für solche Dienste in der Cloud. Serverless heißen sie, weil man überhaupt keinen Gedanken mehr an Anzahl oder Größe der Server verschwenden muss. Der Cloud-Provider übernimmt die Skalierung, und abgerechnet wird meistens nach tatsächlichem CPU- und Speicherbedarf.

Als Entwickler hat man die Wahl aus unterschiedlichen Programmiersprachen und Frameworks. Man kann das beste Werkzeug für den jeweiligen Job und das individuelle Vorwissen wählen. Statt einer monolithischen Lösung erstellt man kleine Logikbausteine (aka Functions), die auf Events wie Web Requests, Messages in einer Queue oder Webhooks reagieren, eine klar begrenzte Aufgaben übernehmen und selbst wieder Events feuern, an denen die nächsten Functions hängen. In gewissem Sinn stellt diese Event-driven Architecture in Verbindung mit Serverless Microservices den Gegenpol zu einem in sich geschlossenen Monolithen dar.

Auch wenn ich die Vorteile des Ansatzes durchaus nachvollziehen kann, sehe ich die Gefahr, die Dinge zu übertreiben. Hier exemplarisch einige Beispiele für Nachteile, die sich meiner Erfahrung nach ergeben, wenn man als SaaS-Anbieter versucht, ausschließlich auf die oben beschriebenen Serverless Microservices zu setzen:

  • Netzwerklatenz kann zu Performanceproblemen führen, da jeder Serviceaufruf über HTTP oder einen Service Bus unvergleichlich viel langsamer ist als ein Methodenaufruf.
  • Typprüfung zur Entwicklungszeit gibt es an den Schnittstellen zwischen Microservices meistens nicht. Im besten Fall kann man sich mit Swagger-Metadaten abhelfen. Oft programmiert man jedoch rein auf Basis von (hoffentlich aktueller) Dokumentation und verlässt sich darauf, dass man informiert wird, wenn sich etwas ändert. Fehler treten vielfach erst zur Laufzeit auf. Man braucht ein ausgefeiltes Logging- und Telemetriesystem, um sie rasch erkennen, lokalisieren und beheben zu können.
  • Automatische Integrationstests, die etwas größere Logikblöcke testen, sind mit Microservices ungleich schwieriger.
  • Man geht eine Wette auf eine bestimmte Cloud ein. Will man seine Software im eigenen Rechenzentrum oder dem eines Kunden betreiben, steht man vor einer großen Herausforderung.
  • Zwischen den Services muss man sich um Authentifizierung kümmern (z. B. Tokens, Shared Secret). Im Monolithen wäre es einfach ein Funktionsaufruf innerhalb eines Prozesses.

Der Sweetspot von Serverless Microservices

Die Wahrheit liegt wie so oft in der goldenen Mitte. Ein nennenswert komplexes Softwaresystem rein auf Basis von sehr kleinen Serverless Microservices zu entwickeln, ist schwierig und führt zu einer Menge Probleme. Mit dem riesigen, im Lauf der Zeit chaotisch gewachsenen Monolithen wird man aber auch nicht glücklich. Die Kombination beider Ansätze führt zum Erfolg:

  • Die Kernfunktionen eines Softwaresystems sollten meiner Ansicht nach in Form sorgfältig gestalteter, nicht zu klein strukturierter Services mit zugehörigem Web-API entwickelt werden. Statt eines großen Monoliths bekommt man eine überschaubare Anzahl kleinerer Komponenten. Ich persönlich halte mich bezüglich Größe an folgende Faustregel: Ein Microservice sollte so klein sein, dass ein einzelnes agiles Team mit erfahrenen Mitgliedern es in wenigen Monaten neu bauen und anschließend autonom betreiben könnte.
  • Die Abgrenzung zwischen den Monolithen sollte businessorientiert erfolgen (Bounded Contexts) und weniger technisch getrieben sein.
  • Die Teilsysteme kommunizieren zwecks Interoperabilität über plattformunabhängig Protokolle wie RESTful Web-APIs oder AMQP.
  • Bei wichtigen Geschäftsfällen kann jedes Teilsystem Events in Form von Web- oder Service Hooks veröffentlichen. Interessierte Komponenten können sich zur Laufzeit und ohne Codeänderung als Eventempfänger registrieren.
  • Serverless Microservices ergänzen die Kernkomponenten und bilden Geschäftsprozesse ab, die häufigen Änderungen unterliegen (z. B. Unterstützung einer Marketingkampagne, die ein paar Wochen läuft) oder kundenspezifisch (z. B. Schnittstellen) sind. Auf diese Weise helfen sie, die Kernkomponenten schlank und dadurch leichter wartbar zu halten.

Fazit

Serverless Microservices sind in meiner Firma im Lauf der letzten Jahre ein unverzichtbares Werkzeug geworden, wenn es darum geht, rasch auf geänderte Anforderungen zu reagieren oder individuell auf Kunden zugeschnittene Varianten unserer Software zu erstellen. An der grundsätzlichen Art und Weise, wie man den Kern größerer Softwareprodukte entwickelt, rütteln sie aber nicht. Sie sind eine Ergänzung und tragen dazu bei, dass uns die einzelnen Komponenten angesichts der sich rasch ändernden Anforderungen nicht über den Kopf wachsen.

Lesen Sie alle Ausgaben der Kolumne „Stropek as a Service„!
In der Kolumne greift Rainer Stropek spannende Aspekte wie die Finanzierung, den Customer Lifetime Value, aber auch wichtige Themen wie Billing, Kundenbindung durch Qualität oder APIs auf – alles aus der Sicht eines Unternehmers, der seit 20 Jahren in der IT-Branche tätig ist und seit fünf Jahren intensive Erfahrungen mit SaaS gesammelt hat.

 

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -