Ralf Westphal bloggte gestern seine Betrachtung der aktuellen Microservice Bewegung. Seine Warnung ist sicher angebracht, und inhaltlich kann ich ihm durchaus zustimmen. Doch ist für mich ein nur nebenbei angesprochener Aspekt grundlegender für die zurückhaltende Betrachtung von Microservices.
Einer der Gründe dafür, dass SOA nicht die Erwartungen erfüllte, war die enge Bindung von fachlicher Abgrenzung an physische (Deployment) Abgrenzung. Analoges ist in der klassischen Mehrschichtwelt gut bekannt unter dem Schlagwort “layers != tiers”.
Genau diese Gleichsetzung sehe ich bei Microservices erneut. Für die anfänglichen Anwender waren sicherlich die Vorteile der Verbindung von Deploymentgrenzen und fachlicher Trennung entscheidend für den Erfolg. So ist dies in die Definition eines Microservice eingeflossen. Durch den momentanen Hype fürchte ich, das dieser Aspekt von vielen anderern Entwicklern unreflektiert übernommen wird, ohne die Auswirkungen zu bedenken.
Was bringt es, einen Microservice zu bauen, der fachliche Abgrenzung und physische Laufzeitabgrenzung vereint? Was ist daran nachteilig?
Positiv ist sicherlich zunächst der Aspekt der fachlichen Abgrenzung überhaupt. Diese ermöglicht eine, passgenauere trennscharfe Entwicklung - bereits durch die Konzentration auf einen Aspekt, erleichtern das Neubauen-statt-Reparieren. Stichwort Bounded Context.
Positiv an der Laufzeittrennung ist die Option der Mehrsprachigkeit / Mehr-‘Runtime’-igkeit. Dieser Aspekt war sicherlich kritisch für den anfänglichen Erfolg von auf Microservices basierenden Systemen.
Positiv ist weiterhin, dass die Implementierung der einzelnen Services völlig unabhängig ist. Hier können jeweils individuell optimale Architekturen / Persistenzstrategien u.ä. gewählt werden.
Negativ ist, dass für einen Austausch zwischen fachlichen Komponenten zwingend Nachrichtenverkehr erforderlich wird, dass ich verteilte Systeme qua default mitdenken muss. Viele Anfragen über fachliche Grenzen hinweg würden sich ohne permanenten Bezug zu einer mit physischem Zustand behafteten Deploymentkomponente beantworten lassen. Doch diese Option passt nicht mehr in den Microservice-Zuschnitt.
Negativ ist die Fixierung auf (reinen) Datenaustausch für fachliche Kommunikation. Dies konterkariert vieles, was mit Domain Driven Design und CQRS in den letzten 10 Jahren erarbeitet wurde. Besonders im Rahmen der REST/HTTP Fixierung bringt die Verheissung des leicht zu wartenden Microservice eine Rückverlagerung des Fokusses des Softwaredesigns von Verben auf Substantive mit sich.
Für den ersten positiven Aspekt ist die physische Trennung nicht erforderlich, der Mehrwert kann auch in anderen Ansätzen mitgenommen werden. Gleiches gilt für die unabhängige Wahl der Implementierung. Beide negative Aspekte sind mit recht hohen ‘Kosten’ behaftet, so dass ich den Einsatz von Microservices zumindest immer sehr kritisch abwägen würde. In jedem Fall besteht die Gefahr, dem “goldener Hammer” auf den Leim zugehen.
Warum sind Microservices aktuell so verlockend? Ich denke, es sind primär folgende Eigenschaften, die sie attraktiv erscheinen lassen: ‘Kleine funktionale Einheiten’ ‘unabhängige Ausführung’ ‘Kommunikation durch Nachrichtenaustausch’ ‘Asynchronität’ ‘Kapselung fachlichen Verhaltens’.
Kommt’s bekannt vor?
Richtig, das ist in etwa eine der ältesten Definition von Objektorientierung. Smalltalk und Alan Kay lassen grüßen. Ja, entlang dieser Leitlinien gebaute Software ist besser verständlich, besser wartbar. Dazu benötige ich aber keine physisch getrennten Prozesse, die sowohl im Betrieb (Monitoring, Deployment, Kompatibilität) als auch unter dem Verteilte Systeme Aspekt Herausforderungen mit sich bringen. Und statt getrennten Betriebssystemprozessen reichen vielleicht Actors a la Erlang?
Und wenn tatsächlich der Betrieb von phyisch verteilten/getrennten Komponenten attraktiv ist? Dann würde ich das aBC Konzept von Udi Dahan ins Feld führen. Dessen “autonome fachliche Komponenten” sind auch Zuschnitte entlang fachlicher Grenzen. Allerdings können Sie jeweils verschieden physische Tiers enthalten. Deren Kommunikation wird nun aber zu einem Implementierungsdetail. Die tatsächlich Integration von verschiedenen Komponenten geschieht durch fachlich motivierte, an CQ[R]S ausgerichtete Schnittstellen. Ob eine Anfrage lokal im physischen Bereich des Aufrufers beantwortet werden kann oder ob ein Rückgriff auf eine andere physische Verteilungseeinheit notwendig ist, liegt im Ermessen der Komponenten bzw. ihres Autors. Auch bei diesem Komponentenansatz kann die tatsächliche Implementierung und Subarchitektur je Komponente individuell gewählt werden. Manche Komponenten enthalten mehrere Tiers. Manche bestehen nur aus einer lokalen Komponente (“Dienst” im Sinne des taktischen DDD). Und manche …. bestehen nur aus einen entfernten Dienst - dieser ist äquivalent zu einem Microservice, der sich hier als Grenzfall einer degenerierten Komponente wiederfindet.
So sehe ich die aktuelle Microservice-Bewegung aus vielleicht etwas anderem Blickwinkel als Ralf auch kritisch. Wo liegt dann der Einsatzzweck für das doch-nicht-Universalwerkzeug Microservice? Mindestens dort, wo ich evtl. sogar vorher existierende fachlich getrennte und polyglotte Teilsysteme verbinden muss. Andererseits: dort werden Microservices sich der Herausforderung stellen müssen, ihre Schnittstellen universal zu definieren… Wie wärs mit XML, gar WDSL? Vielleicht erfinden wir nach OO und Komponenten auch SOA gleich noch mal neu…