Kolumne: Stropek as a Service
Kolumne: Stropek as a Service
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.
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 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:
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.
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:
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:
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.