Was man vom Microservice-Hype (mindestens) mitnehmen sollte

2 Kommentare

Gerade in den letzten Wochen wird wieder intensiver über Microservices diskutiert, insbesondere nachdem Martin Fowler seinen „Monolith First“-Ansatz veröffentlichte und sich viele Kritiker des Microservices-Ansatz bestätigt fühlten. Stefan Tilkov hat eine gute Antwort darauf gegeben, und ja, beide Posts sind sehr lesenswert. Tatsache ist jedoch auch, dass jedes Software-System seine ganz eigenen Anforderungen hat, und dass es die (unsere) Kunst ist, für dieses spezielle Software-System die optimale Architektur zu entwickeln, und dass eine Aussage wie „Starte immer mit einem Monolithen“ eine dogmatische Aussage ist, die nicht immer richtig sein kann. Das stellt auch Sander Mak in seinem Post gut heraus. Genauso, wie die Aussage, dass Microservices besser sind als Monolithen, nicht allgemeingültig richtig sein kann.

In den Diskussionen auf Twitter und Co. geht es häufig um Technik. Microservices werden abgelehnt, weil die Leute einfach nur den Overhead der verteilten Kommunikation auf ihre monolithischen Projekte aufrechnen. Monolithen werden abgelehnt, weil sie in Zeiten von Docker, Cloud und Co. einfach nicht mehr zeitgemäß seien. Vielleicht sollten wir einmal einen Schritt zurücktreten und Technik Technik sein lassen. Was kann man vom Microservice-Hype mitnehmen, das nicht nur für Microservices wichtig ist?

Warum sind große Projekte langsam und scheitern überdurchschnittlich häufig?

Zu viele Abhängigkeiten. Abhängigkeiten führen zu Kommunikationsbedarf. Kommunikation bedeutet Meetings, Meetings bedeutet unproduktive Zeit für die Teilnehmer. Kommunikation bedeutet Potenzial für Missverständnisse. Abhängigkeiten bedeuten Wartezeiten auf Leistungen anderer.
Ein weiterer Grund sind ungeklärte Verantwortlichkeiten. Wenn sich keiner verantwortlich fühlt, macht es keiner, wenn sich zu viele verantwortlich fühlen, werden Dinge parallel doppelt gemacht. Beides führt wieder zu erhöhtem Kommunikationsbedarf.

Was kann man tun, um das Problem in den Griff zu bekommen?

Abhängigkeiten minimieren und klare Verantwortlichkeiten schaffen.

Ist das nicht eine triviale Aussage?

Die Aussage mag trivial sein. Und doch ist die Umsetzung alles andere als trivial. Schauen wir uns mal einen Zustand an, den man in vielen Unternehmen so oder zumindest teilweise so vorfinden kann.
 
BlogpostMitnehmenSpinnennetz
 
Jeder Kasten stellt eine Software-Komponente dar. Dieses Diagramm sagt nichts darüber aus, wie diese Komponenten technisch kommunizieren, ob sie in einem Prozess laufen oder nicht etc. Das ist für unsere Überlegungen zunächst auch nicht wichtig. Gehen wir mal vereinfacht davon aus, dass jede Komponente von einem eigenen Team betreut und entwickelt wird. Die Linien zwischen den Komponenten stellen synchrone Abhängigkeiten dar, sie legen sich wie Spinnennetz über das System und sorgen dafür, die Beweglichkeit des Gesamtsystems stark einzuschränken. Für jede Linie fällt Kommunikation zwischen Teams an, Schnittstellenabsprachen, Fachlichkeit, die es zu diskutieren gilt. Noch nicht eingezeichnet sind mögliche Frameworks, übergreifende technische Frameworks, aber auch fachliche Frameworks, die weitere gemeinsame Absprachen erfordern.
Wenn man die Fachbereiche noch hinzunimmt, sieht das dann so aus.
 
BlogpostMitnehmenSpinnennetzFach
 
Auch die Fachabteilungen haben für die Implementierung eines Anwendungsfalls nicht ein Team als Ansprechpartner, sondern mehrere. Häufig wird außerdem die Datenbank als Integrationsschicht angesehen und Tabellen werden von mehreren Low-Level-Services angesprochen, so dass kleine Änderungen des Datenmodells ebenfalls komplexe Abstimmungen zur Folge haben.

Dass es nicht einfach ist, in so einem System schnell neue Features in Produktion zu bringen, ist klar.

Was kann man nun tun, um das lähmende Abhängigkeitsgeflecht so gut es geht aufzulösen?

Statt in Schichten sollte organisatorisch in Vertikalen gedacht werden.
 
BlogpostMitnehmenVertikale
 
Hier haben Teams die komplette Verantwortung für GUI, Logik und Persistenz für eine bestimmte Fachlichkeit. Der Umfang der Vertikalen kann beispielsweise über das Werkzeug der Bounded Contexts ermittelt werden, und die Anzahl der Vertikalen sollte nicht festgeschrieben sein, es kann sich sehr wohl die Situation ergeben, dass neue Vertikale entstehen. Ein Team kann je nach Umfang auch für mehrere Vertikale verantwortlich sein. Diese Graphik sagt außerdem nichts darüber aus, wie viele Artefakte gebaut werden oder wie diese betrieben werden. Sie können sich sehr wohl in einen gemeinsam betriebenen Monolithen integrieren, genauso kann es aber auch innerhalb der Vertikalen mehrere Anwendungen geben, die evtl. für unterschiedliche Schichten zuständig sind. Es geht erst einmal nur um die Organisation. Wenn Features in einem bestimmten Bereich umgesetzt werden sollen, haben die Fachbereiche klare Ansprechpartner, die für die Gesamtumsetzung verantwortlich sind. Abhängigkeiten zwischen den Vertikalen möglichst lose zu implementieren, ist unsere Kunst, Werkzeuge und Pattern dafür sind beispielsweise

  • Datenduplikation über Events. Wenn wir in Vertikale A Daten aus dem Zuständigkeitsbereich von Vertikale B benötigen, so duplizieren wir diese Daten in Vertikale A, indem wir auf Domain Events der Vertikale B horchen, die uns damit über Änderungen informiert. Wichtig ist, dass es immer nur einen Hüter der Daten gibt.
  • Absolute Vermeidung von synchroner Kommunikation. Zwischen Vertikalen wird nur über asynchrone Events kommuniziert. Die Kommunikation zwischen Teams wird so reduziert. Das Team, das für die Vertikale A zuständig ist, informiert über Änderungen in ihrer Domäne mit entsprechenden Events. Ob ein anderes Team diese nutzt oder nicht, interessiert das Team nicht.
  • Verlinkung in der GUI. Abhängigkeiten können auch erst direkt in der GUI aufgelöst werden. So kann ein Vertragssystem einen Link in ein Partnersystem haben, wenn es den benötigt.
  • Absolute Vermeidung von fachlichen Frameworks. Frameworks sollen die Produktivität von Entwicklern verbessern, indem sie den Entwicklern Funktionalität zur Verfügung stellen, die sie nicht mehr selbst implementieren müssen. Fachliche Frameworks sind da allerdings sehr häufig kontraproduktiv, sie müssen in der Regel für jeden neuen Use Case angepasst werden und erfordern so Kommunikationsbedarf, Wartezeiten oder Workarounds. Gleichmacherei verschiedener Fachlichkeiten über zentrale fachliche Frameworks funktioniert nicht.
  • Vermeidung eines kanonischen Datenmodells. Objekte sind in unterschiedlichen Kontexten einfach unterschiedlich, das gilt es zu akzeptieren und damit so gut es geht umzugehen. Ein kanonisches Datenmodell sorgt für erheblichen Kommunikationsbedarf, Wartezeiten und Workarounds.
  • Bewusste Verwendung von technischen Frameworks. Technische Frameworks haben eine Aufgabe: die Produktivität der Entwickler verbessern. Es ist nicht die Aufgabe von Frameworks, den Entwickler absichtlich einzuschränken. Wenn man so an das Thema Frameworks herangeht, sind bewusst erstellte technische Frameworks / Libraries okay.
  • Toleriere Redundanz. Das Don’t Repeat Yourself – Prinzip (DRY) ist häufig so tief in uns verankert, dass wir es übertreiben. Es ist immer besser, etwas zweimal zu implementieren, als zwei Dinge, die eigentlich sehr unterschiedlich sind, gemeinsam zu abstrahieren.

Wenn ein Unternehmen organisatorisch so aufgestellt ist, hat es gegenüber der vorigen Situation schon gewonnen. Features können leichter mit weniger Kommunikation unabhängiger umgesetzt werden.

Microservices gehen bezüglich der Unabhängigkeit / Autonomie nun noch ein paar Schritte weiter, indem sie immer in einem eigenen Prozess laufen, Schnittstellen immer unabhängig von Programmiersprachen sind, völlig eigenständig nach Produktion deployt werden können etc. Diese Schritte bringen einige Vorteile und einige Nachteile, und über genau diese Schritte wird in der Blogosphäre besonders gerne diskutiert. Es sind aber nur die letzten 20%. Die wichtigen 80% sind die vertikale Organisationsstruktur. Und von der profitiert jedes Unternehmen.

Zusatz: Pragmatismus vs Theorie

Jeder Anwendungsfall, jede konkrete Architektur ist anders. Der gesunde Menschenverstand wandelt Theorie in Praxis um, und zwar genau so, wie es für den entsprechenden Anwendungsfall am besten passt. Das gilt auch hier. Es gibt viele verschiedene Varianten der Ausgangslage, die die gleiche lähmende Wirkung haben, genauso gibt es Kompromissvarianten der Zielorganisation, die im konkreten Fall besser passen. Der große Lösungsraum macht unseren Job so spannend.

Zusatz: Microservices vs SOA

An vielen Stellen hört man, dass es im Prinzip keine Unterschiede zwischen Microservices und SOA gibt. Wenn man Definitionen betrachtet, die nicht über fünf Zeilen hinausgehen, mag das stimmen. In der Praxis wurde SOA jedoch häufig mit kanonischem Datenmodell, vertikaler synchroner Kommunikation über wiederverwendbare Low-Level-Services und Deployment in einem Monolithen umgesetzt. Weder von der organisatorisch agilen Seite noch von der Betriebsseite hat das irgendetwas mit Microservices zu tun.

Tobias Flohre

Tobias Flohre arbeitet als Senior-Softwareentwickler/Architekt bei der codecentric AG. Seine Schwerpunkte sind Java-Enterprise-Anwendungen und Architekturen mit JEE/Spring. Er ist Autor diverser Artikel und schreibt regelmäßig Blogbeiträge zu den Themen Architektur und Spring. Zurzeit beschäftigt er sich mit Integrations- und Batch-Themen im Großunternehmen sowie mit modernen Webarchitekturen.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentare

  • 14. Juli 2015 von d.hermanns

    Sehr schöner Artikel! Spricht mir sehr aus der Seele. Die absolute Vermeidung synchroner Kommunikation sowie die absolute Vermeidung von fachlichen Frameworks würde ich so in der Praxis jedoch nicht sehen.

    Synchrone Kommunikation sollte aus meiner Sicht die Ausnahme sein, kann aber aufgrund von zeitlichen Anforderungen notwendig werden.

    Die fachlichen Frameworks sind aus meiner Sicht ok, solange sie quasi als eigenständiges, „Open Source“ ähnliches Projekt entwickelt werden. D.h. es gibt separate Releasezyklen. Und jedes Team kann selbst entscheiden, ob der Einsatz hilfreich ist und wann es genau auf eine neue Version gehen kann/möchte.

    • Tobias Flohre

      2. August 2015 von Tobias Flohre

      Schön, dass er Dir gefällt! Bezüglich der synchronen Kommunikation: das habe ich vielleicht etwas stark formuliert. Tatsache ist halt, dass synchrone Kommunikation einfacher zu verstehen ist und dass wir deshalb auch häufig denken, dass synchrone Kommunikation notwendig ist, obwohl sie das gar nicht ist. Und durch synchrone Kommunikation holt man sich eine viel stärkere Kopplung ins Haus. Wenn synchrone Kommunikation tatsächlich die Ausnahme ist, kann ich damit leben.
      Und bezüglich fachlicher Frameworks: da rücke ich nicht von meiner Meinung ab. Ich meine dabei keine technischen Frameworks, die meiner Meinung nach Sinn machen (im Sinne von „Open Source“ – ähnlich und Team entscheidet über Einsatz). Ich rede von echter Fachlichkeit (beispielsweise ein Produkt-Überbau über alle Sparten). Solche fachlichen Frameworks bringen harte Kopplung und jede Menge Abhängigkeiten, die in Workarounds und Unwartbarkeit gipfeln.

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.