Microservices - Sam Newman - E-Book

Microservices E-Book

Sam Newman

0,0

Beschreibung

Feingranulare Systeme mit Microservices aufbauen Design, Entwicklung, Deployment, Testen und Monitoring Sicherheitsaspekte, Authentifizierung und Autorisierung Verteilte Systeme haben sich in den letzten Jahren stark verändert: Große monolithische Architekturen werden zunehmend in viele kleine, eigenständige Microservices aufgespalten. Aber die Entwicklung solcher Systeme bringt Herausforderungen ganz eigener Art mit sich. Dieses Buch richtet sich an Softwareentwickler, die sich über die zielführenden Aspekte von Microservice-Systemen wie Design, Entwicklung, Testen, Deployment und Monitoring informieren möchten. Sam Newman veranschaulicht und konkretisiert seine ganzheitliche Betrachtung der grundlegenden Konzepte von Microservice-Architekturen anhand zahlreicher praktischer Beispiele und Ratschläge. Er geht auf die Themen ein, mit denen sich Systemarchitekten und Administratoren bei der Einrichtung, Verwaltung und Entwicklung dieser Architekturen in jedem Fall auseinandersetzen müssen. Aus dem Inhalt: Vorteile von Microservices Gestaltung von Services Ausrichtung der Systemarchitektur an der Organisationsstruktur Möglichkeiten zur Integration von Services Schrittweise Aufspaltung einer monolithischen Codebasis Deployment einzelner Microservices mittels Continuous Integration Testen und Monitoring verteilter Systeme Sicherheitsaspekte Authentifizierung und Autorisierung zwischen Benutzer und Service bzw. zwischen Services untereinander Skalierung von Microservice-Architekturen »Microservice-Architekturen besitzen viele interessante Eigenschaften, allerdings sind bei der Umstellung so einige Fallstricke zu beachten. Dieses Buch wird Ihnen helfen herauszufinden, ob Microservices für Ihre Zwecke geeignet sind und zeigt Ihnen, wie Sie die Fallstricke umgehen können.« Martin Fowler, Chief Scientist, ThoughtWorks

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern
Kindle™-E-Readern
(für ausgewählte Pakete)

Seitenzahl: 489

Veröffentlichungsjahr: 2015

Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:

Android
iOS
Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Inhaltsverzeichnis
Impressum
Einleitung
Über den Autor
Kapitel 1: Microservices
1.1 Was sind Microservices?
1.1.1 Klein und darauf spezialisiert, eine bestimmte Aufgabe richtig gut zu erledigen
1.1.2 Eigenständigkeit
1.2 Die wichtigsten Vorteile​
1.2.1 Verschiedenartige Technologien
1.2.2 Belastbarkeit​
1.2.3 Skalierung​
1.2.4 Komfortables Deployment​
1.2.5 Betriebliche Abstimmung
1.2.6 Modularer Aufbau
1.2.7 Austauschbarkeit
1.3 Was ist mit serviceorientierten Architekturen?
1.4 Weitere Verfahren zur Aufspaltung
1.4.1 Programmbibliotheken
1.4.2 Module
1.5 Kein Patentrezept
1.6 Fazit
Kapitel 2: Der fortentwickelte Systemarchitekt
2.1 Unangebrachte Vergleiche
2.2 Das Zukunftsbild eines Systemarchitekten
2.3 Zoneneinteilung
2.4 Ein grundsätzlicher Ansatz
2.4.1 Strategische Ziele
2.4.2 Prinzipien
2.4.3 Praktiken
2.4.4 Prinzipien und Praktiken vereinigen
2.4.5 Ein Praxisbeispiel
2.5 Mindestvorgaben
2.5.1 Monitoring
2.5.2 Schnittstellen
2.5.3 Architektonische Sicherheit​
2.6 Lenkung durch Code
2.6.1 Musterbeispiele​
2.6.2 Maßgeschneiderte Servicevorlagen​
2.7 Technische Schulden​
2.8 Ausnahmebehandlung
2.9 Governance und Steuerung aus der Mitte
2.10 Aufbau eines Entwicklerteams
2.11 Fazit
Kapitel 3: Gestaltung von Services
3.1 Kurz vorgestellt: MusicCorp
3.2 Wodurch zeichnet sich ein guter Service aus?
3.2.1 Lose Kopplung​​
3.2.2 Hochgradige Geschlossenheit​
3.3 Begrenzter Kontext
3.3.1 Geteilte und verborgene Modelle
3.3.2 Module und Services
3.3.3 Verfrühte Aufteilung
3.4 Funktionalitäten des Kontexts
3.5 Schildkröten bis ganz unten
3.6 Kommunikation unter geschäftlichen Aspekten
3.7 Der technische Rahmen
3.8 Fazit
Kapitel 4: Integration
4.1 Die Suche nach der optimalen Integrationsmethode
4.1.1 Zu Ausfällen führende Änderungen vermeiden
4.1.2 Technologieunabhängige APIs verwenden
4.1.3 Services für den Nutzer vereinfachen
4.1.4 Implementierungsdetails verbergen
4.2 Kundendatensätze
4.3 Gemeinsame Nutzung der Datenbank
4.4 Synchrone kontra asynchrone Kommunikation
4.5 Orchestrierung kontra Choreografie
4.6 Aufruf entfernter Prozeduren (RPC)
4.6.1 Kopplung von Technologien
4.6.2 Lokale Aufrufe sind keine entfernten Aufrufe
4.6.3 Fragilität
4.6.4 Ist RPC ein Übel?
4.7 REST
4.7.1 REST und HTTP
4.7.2 HATEOAS​
4.7.3 JSON, XML oder etwas anderes?
4.7.4 Vorsicht vor zu viel Komfort
4.7.5 Nachteile von REST über HTTP
4.8 Implementierung asynchroner ereignisgesteuerter Kollaboration
4.8.1 Verfügbare Technologien
4.8.2 Die Kompliziertheit asynchroner Architekturen
4.9 Services als Zustandsautomaten
4.10 Reactive Extensions
4.11 DRY und die Gefahren der Wiederverwendung von Code im Microservices-Umfeld
4.11.1 Client-Bibliotheken
4.12 Zugriff über Referenzen
4.13 Versionierung
4.13.1 Solange wie möglich hinauszögern
4.13.2 Zu Ausfällen führende Änderungen rechtzeitig erkennen
4.13.3 Verwendung semantischer Versionierung
4.13.4 Mehrere Endpunkte gleichzeitig betreiben
4.13.5 Mehrere Serviceversionen gleichzeitig betreiben
4.14 Benutzerschnittstellen
4.14.1 Zunehmend digital
4.14.2 Voraussetzungen
4.14.3 Aufbau der API
4.14.4 Bausteine der Benutzeroberfläche
4.14.5 Back-Ends für Front-Ends
4.14.6 Ein Hybridansatz
4.15 Integration der Software von Drittherstellern
4.15.1 Fehlende Entscheidungsmöglichkeiten
4.15.2 Anpassungen
4.15.3 Integrationswirrwarr
4.15.4 Auf sich selbst gestellt
4.15.5 Das Strangler-Pattern
4.16 Fazit
Kapitel 5: Die Aufspaltung des Monolithen
5.1 Seams
5.2 Aufspaltung von MusicCorp
5.3 Gründe zur Aufspaltung des Monolithen
5.3.1 Tempo der Änderungen
5.3.2 Teamstruktur
5.3.3 Sicherheitsaspekte
5.3.4 Technologie
5.4 Verwickelte Abhängigkeiten
5.5 Die Datenbank​
5.6 Dem Problem zu Leibe rücken
5.7 Beispiel: Auflösen von Fremdschlüssel-Relationen
5.8 Beispiel: Statische Daten gemeinsam nutzen
5.9 Beispiel: Veränderliche Daten gemeinsam nutzen
5.10 Beispiel: Tabellen gemeinsam nutzen​
5.11 Refactoring von Datenbanken
5.11.1 Die Aufspaltung umsetzen
5.12 Abgrenzung von Transaktionen
5.12.1 Versuchen Sie es später noch mal
5.12.2 Abbruch des gesamten Vorgangs
5.12.3 Verteilte Transaktionen​
5.12.4 Was also tun?
5.13 Berichte
5.14 Datenbanken zur Berichterstellung
5.15 Datenabruf über Serviceaufrufe
5.16 Datenpumpen​
5.16.1 Alternative Ziele
5.17 Ereignis-Datenpumpen​
5.18 Backup-Datenpumpe​
5.19 Benachrichtigung in Echtzeit
5.20 Änderungen verursachen Aufwand
5.21 Erkennen der eigentlichen Ursachen
5.22 Fazit
Kapitel 6: Deployment
6.1 Continuous Integration für Einsteiger
6.1.1 Machen Sie es auch richtig?
6.2 Continuous Integration und Microservices
6.3 Build Pipelines und Continuous Delivery​
6.3.1 Die unvermeidlichen Ausnahmen
6.4 Plattformspezifische Artefakte
6.5 Betriebssystemspezifische Artefakte
6.6 Selbsterstellte Images​
6.6.1 Images als Artefakte​
6.6.2 Unveränderliche Server​
6.7 Umgebungen
6.7.1 Servicekonfiguration​
6.7.2 Zuordnung der Services zu den Hosts
6.7.3 Mehrere Services pro Host
6.7.4 Anwendungscontainer​
6.7.5 Ein Service pro Host
6.7.6 Platform-as-a-Service (PaaS)
6.8 Automatisierung​
6.8.1 Zwei Fallstudien zur Leistungsfähigkeit der Automatisierung
6.9 Physisch wird virtuell
6.9.1 Herkömmliche Virtualisierung
6.9.2 Vagrant​
6.9.3 Linux-Container​
6.9.4 Docker​
6.10 Schnittstelle für das Deployment
6.10.1 Definition der Umgebung
6.11 Fazit
Kapitel 7: Testen
7.1 Testtypen
7.2 Testumfang​
7.2.1 Unit-Tests​
7.2.2 Servicetests​
7.2.3 End-to-End-Tests
7.2.4 Nachteile
7.2.5 Wie viele Tests?
7.3 Implementierung von Servicetests​
7.3.1 Mock-Objekte kontra Platzhalter
7.3.2 Ein intelligenterer Platzhalterservice
7.4 Knifflige End-to-End-Tests​
7.5 Nachteile von End-to-End-Tests
7.5.1 Unzuverlässige und fragile Tests
7.5.2 Wer programmiert die Tests?
7.5.3 Testdauer​
7.5.4 Das große Auftürmen
7.5.5 Die Metaversion
7.6 Abläufe testen, nicht Funktionalitäten
7.7 Abhilfe durch Consumer-Driven Tests
7.7.1 Pact
7.7.2 Konversationen
7.8 End-to-End-Tests: Pro und Kontra
7.9 Testen nach der Veröffentlichung​
7.9.1 Deployment und Veröffentlichung trennen
7.9.2 Canary-Veröffentlichung
7.9.3 MTTR kontra MTBR
7.10 Funktionsübergreifende Tests​
7.10.1 Geschwindigkeitstests
7.11 Fazit
Kapitel 8: Monitoring
8.1 Ein Service, ein Server
8.2 Ein Service, mehrere Server
8.3 Mehrere Services, mehrere Server
8.4 Protokolle, Protokolle und noch mehr Protokolle
8.5 Kennzahlen mehrerer Services
8.6 Servicekennzahlen
8.7 Monitoringung von Pseudo-Ereignissen​
8.7.1 Implementierung des semantischen Monitorings
8.8 Korrelations-IDs​
8.9 Die Aufrufkette​
8.10 Standardisierung
8.11 Zielgruppen
8.12 Wie geht es weiter?
8.13 Fazit
Kapitel 9: Sicherheit
9.1 Authentifizierung und Autorisierung​​
9.1.1 Gängige Single-Sign-On-Implementierungen​​
9.1.2 Single-Sign-On-Gateway​
9.1.3 Fein unterteilte Authentifizierung​
9.2 Authentifizierung und Autorisierung von Services​​
9.2.1 Im internen Netzwerk ist alles erlaubt
9.2.2 Authentifizierung über HTTP(S)​
9.2.3 Verwendung von SAML oder OpenID Connect
9.2.4 Client-Zertifikate​
9.2.5 HMAC über HTTP
9.2.6 API-Schlüssel​
9.2.7 Das Stellvertreterproblem​
9.3 Schutz ruhender Daten​
9.3.1 Wohlbekannte Verfahren einsetzen
9.3.2 Die Bedeutung der Schlüssel
9.3.3 Was soll verschlüsselt werden?
9.3.4 Entschlüsselung bei Bedarf
9.3.5 Backups verschlüsseln
9.4 Gestaffelte Sicherheitsstrategie
9.4.1 Firewalls​
9.4.2 Protokollierung​
9.4.3 Intrusion-Detection-Systeme
9.4.4 Unterteilung des Netzwerks​
9.4.5 Betriebssystem​
9.5 Ein ausgearbeitetes Beispiel
9.6 Datensparsamkeit
9.7 Der Faktor Mensch
9.8 Eine Goldene Regel
9.9 Integrierte Sicherheit
9.10 Externe Prüfung​
9.11 Fazit
Kapitel 10: Conways Gesetz und Systemdesign
10.1 Beweise
10.1.1 Lose und eng gekoppelte Organisationen
10.1.2 Windows Vista
10.2 Netflix und Amazon
10.3 Was kann man damit anfangen?
10.4 Anpassung an Kommunikationswege
10.5 Verantwortlichkeit für Services
10.6 Gemeinschaftliche Verantwortlichkeit für Services
10.6.1 Schwierige Aufspaltung
10.6.2 Feature-Teams
10.6.3 Engpässe bei der Auslieferung
10.7 Interner Open-Source-Code
10.7.1 Aufgaben der Koordinatoren
10.7.2 Ausgereifte Services​
10.7.3 Werkzeugsammlungen​
10.8 Begrenzte Kontexte und Teamstrukturen
10.9 Verwaiste Services?
10.10 Fallstudie: RealEstate.com.au
10.11 Conways Gesetz auf den Kopf gestellt
10.12 Menschen​
10.13 Fazit
Kapitel 11: Microservices skalieren
11.1 Ausfälle gibt es immer
11.2 Wie viel ist zu viel?
11.3 Schrittweiser Abbau der Funktionalität
11.4 Architektonische Sicherheitsmaßnahmen
11.5 Die antifragile Organisation
11.5.1 Timeouts​
11.5.2 Circuit Breaker​
11.5.3 Das Bulkhead-Pattern
11.5.4 Isolierung​​
11.6 Idempotenz​
11.7 Skalierung​
11.7.1 Mehr Leistung
11.7.2 Arbeitslast aufteilen​
11.7.3 Risikoverteilung​
11.7.4 Lastverteilung​
11.7.5 Worker-Systeme
11.7.6 Neuanfang
11.8 Datenbanken skalieren​
11.8.1 Verfügbarkeit des Services kontra Lebensdauer der Daten
11.8.2 Skalierung bei Lesevorgängen​
11.8.3 Skalierung bei Schreibvorgängen​
11.8.4 Gemeinsam genutzte Datenbankinfrastruktur
11.8.5 CQRS
11.9 Caching
11.9.1 Clientseitiges Caching, Proxy und serverseitiges Caching
11.9.2 Caching und HTTP
11.9.3 Caching bei Schreibvorgängen
11.9.4 Caching zur Erhöhung der Belastbarkeit
11.9.5 Den Ursprung verbergen
11.9.6 Möglichst einfach
11.9.7 Cache Poisoning: Ein warnendes Beispiel​
11.10 Automatische Skalierung​
11.11 Das CAP-Theorem
11.11.1 Aufgabe der Konsistenz​
11.11.2 Aufgabe der Verfügbarkeit​
11.11.3 Aufgabe der Partitionstoleranz?​
11.11.4 AP oder CP?
11.11.5 Keine Frage eines Entweder-Oders
11.11.6 Abbildung der Wirklichkeit
11.12 Serviceerkennung
11.12.1 DNS
11.13 Dynamische Registrierung von Services​
11.13.1 Zookeeper
11.13.2 Consul
11.13.3 Eureka
11.13.4 Eigene Serviceregistrierung
11.13.5 Menschliches Interesse
11.14 Services dokumentieren
11.14.1 Swagger​
11.14.2 HAL und der HAL-Browser
11.15 Ein sich selbst beschreibendes System
11.16 Fazit
Kapitel 12: Auf den Punkt gebracht
12.1 Prinzipien​
12.1.1 Geschäftsvorgänge modellieren
12.1.2 Automatisierung kultivieren
12.1.3 Implementierungsdetails verbergen
12.1.4 Dezentralisierung​
12.1.5 Unabhängiges Deployment​​
12.1.6 Ausfälle eingrenzen​
12.1.7 Umfassendes Monitoring​
12.2 Wann sollte man auf Microservices verzichten?​

Microservices

Konzeption und Design

Sam Newman

Übersetzung aus dem Amerikanischen von Knut Lorenzen

Impressum

Bibliografische Information der Deutschen Nationalbibliothek

Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über <http://dnb.d-nb.de> abrufbar.

ISBN 978-3-95845-083-7

1. Auflage 2015

www.mitp.de

E-Mail: [email protected]

Telefon: +49 7953 / 7189 - 079

Telefax: +49 7953 / 7189 - 082

© 2015 mitp Verlags GmbH & Co. KG

Dieses Werk, einschließlich aller seiner Teile, ist urheberrechtlich geschützt. Jede Verwertung außerhalb der engen Grenzen des Urheberrechtsgesetzes ist ohne Zustimmung des Verlages unzulässig und strafbar. Dies gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und die Einspeicherung und Verarbeitung in elektronischen Systemen.

Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften.

Authorized German translation of the English edition of Building Microservices ISBN 9781491950357 © 2015 Sam Newman. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same.

Lektorat: Sabine Schulz

Sprachkorrektorat: Maren Feilen

Coverbild: © Irochka, fotolia.de

electronic publication: III-satz, Husby, www.drei-satz.de

Dieses Ebook verwendet das ePub-Format und ist optimiert für die Nutzung mit dem iBooks-reader auf dem iPad von Apple. Bei der Verwendung anderer Reader kann es zu Darstellungsproblemen kommen.

Der Verlag räumt Ihnen mit dem Kauf des ebooks das Recht ein, die Inhalte im Rahmen des geltenden Urheberrechts zu nutzen. Dieses Werk, einschließlich aller seiner Teile, ist urheberrechtlich geschützt. Jede Verwertung außerhalb der engen Grenzen des Urheherrechtsgesetzes ist ohne Zustimmung des Verlages unzulässig und strafbar. Dies gilt insbesondere für Vervielfältigungen, Übersetzungen, Mikroverfilmungen und Einspeicherung und Verarbeitung in elektronischen Systemen.

Der Verlag schützt seine ebooks vor Missbrauch des Urheberrechts durch ein digitales Rechtemanagement. Bei Kauf im Webshop des Verlages werden die ebooks mit einem nicht sichtbaren digitalen Wasserzeichen individuell pro Nutzer signiert.

Bei Kauf in anderen ebook-Webshops erfolgt die Signatur durch die Shopbetreiber. Angaben zu diesem DRM finden Sie auf den Seiten der jeweiligen Anbieter.

Einleitung

Microservices sind ein Ansatz für verteilte Systeme, die die Nutzung feingranularer Services mit eigenen Entwicklungszyklen fördern, die sich gegenseitig zuarbeiten. Da Microservices vornehmlich im geschäftlichen Umfeld Anwendung finden, werden die bei herkömmlichen abgestuften Architekturen auftretenden Schwierigkeiten umgangen. Microservices nutzen außerdem die während des letzten Jahrzehnts entwickelten Technologien und Verfahren und vermeiden dadurch die Fallstricke, die mit vielen serviceorientierten Architekturen einhergehen.

Dieses Buch enthält eine Reihe konkreter Beispiele dafür, wie Microservices weltweit eingesetzt werden, etwa in Unternehmen wie Netflix, Amazon, Gilt und der REA-Gruppe, die allesamt festgestellt haben, dass ihnen die erhöhte Unabhängigkeit dieser Architektur große Vorteile bringt.

Wer sollte dieses Buch lesen?

Der Anwendungsbereich dieses Buches umfasst ein breites Spektrum, ebenso wie auch die Auswirkungen einer feingranularen Microservice-Architektur vielgestaltig sind. Es soll Leser ansprechen, die an verschiedenen Aspekten des Designs, der Entwicklung, des Deployments, des Testens und der Wartung dieser Systeme interessiert sind. Diejenigen Leser, die bereits damit begonnen haben, sich mit feiner unterteilten Architekturen zu beschäftigen – sei es nun einer vollkommen neuen Anwendung oder der Aufteilung eines bereits vorhandenen, eher monolithischen Systems –, werden viele praktische Ratschläge finden. Und auch denjenigen Lesern, die im Grunde nur wissen möchten, was der ganze Rummel eigentlich soll, wird geholfen, damit sie entscheiden können, ob Microservices für ihre Zwecke geeignet sind.

Der Grund für dieses Buch

Als es vor vielen Jahren zu meinen Aufgaben gehörte, anderen dabei zu helfen, Software schneller fertigzustellen, fing ich an, mich mit Anwendungsarchitekturen zu befassen. Mir war klar, dass automatisierte Infrastrukturen, Tests und kontinuierliche Weiterentwicklungen zwar durchaus hilfreich sind, man aber bald an die Grenzen des Machbaren stößt, wenn das grundlegende Design eines Systems es nicht erlaubt, schnell und einfach Modifizierungen daran vorzunehmen.

Zur selben Zeit experimentierten viele Unternehmen mit feiner unterteilten Architekturen, um vergleichbare Ergebnisse zu erzielen. Gleichzeitig sollten aber auch eine verbesserte Skalierbarkeit, eine größere Unabhängigkeit der Entwicklerteams oder eine vereinfachte Übernahme neuer Technologien ermöglicht werden. Sowohl meine eigenen Erfahrungen als auch die meiner Kollegen bei ThoughtWorks und anderen Unternehmen bestätigten die Tatsache, dass eine größere Zahl eingesetzter unabhängiger Services mit eigenen Entwicklungszyklen unweigerlich zu weiteren Problemen führt, mit denen man sich auseinandersetzen muss. Dieses Buch soll in gewisser Weise eine Art zentrale Anlaufstelle sein und helfen, die breite Palette von Themen, die zum Verständnis von Microservices nötig ist, zu beschreiben. So etwas hätte mir seinerzeit wirklich außerordentlich geholfen!

Zum Stand der Dinge

Das Thema »Microservices« ist einem ständigen Wandel unterworfen. Obwohl die Idee an sich nicht neu ist (auch wenn der Begriff es ist), haben die Erfahrungen der Nutzer auf der ganzen Welt zusammen mit dem Aufkommen neuer Technologien maßgeblichen Einfluss auf die Verwendungsweise. Aufgrund der schnellen Fortentwicklung in diesem Bereich habe ich versucht, mich in den folgenden Kapiteln weniger auf bestimmte Technologien als vielmehr auf die grundlegenden Konzepte zu konzentrieren, und zwar wohlwissend, dass sich Details der Implementierung stets schneller ändern als die dahinterstehenden Ideen. Dessen ungeachtet erwarte ich absolut, dass wir in einigen Jahren noch besser verstehen werden, wann der Einsatz von Microservices angebracht ist und wie sie vernünftigerweise eingesetzt werden.

Aufbau des Buches

Der Aufbau dieses Buches orientiert sich vornehmlich an den behandelten Themen. Sie können daher direkt zu einem bestimmten Thema springen, das Sie am meisten interessiert. Ich habe mich bemüht, wichtige Begriffe und Konzepte gleich in den ersten Kapiteln zu erläutern und gehe davon aus, dass selbst Leser, die sich als recht erfahren einschätzen, in jedem Kapitel noch etwas von Interesse entdecken. Grundsätzlich empfehle ich Ihnen, sich Kapitel 2 anzusehen, das einen Eindruck von der Tiefe des Themas vermittelt und umreißt, wie ich im weiteren Verlauf des Buches vorgehe, falls Sie sich mit den nachfolgenden Inhalten eingehender beschäftigen möchten.

Ich hoffe, ich habe die Kapitel für Leser, denen das Thema neu ist, in der richtigen Reihenfolge angeordnet, damit das Buch in sinnvoller Weise von vorn bis hinten durchgelesen werden kann.

Hier ein Überblick über den Inhalt des Buches:

Kapitel 1– Microservices Wir beginnen mit einer Einführung in das Thema Microservices, in der die wesentlichen Vorteile, aber auch einige der Nachteile dargestellt werden.

Kapitel 2– Der fortentwickelte Systemarchitekt In diesem Kapitel kommen die Schwierigkeiten zur Sprache, denen man als Systemarchitekt gegenübersteht, weil man Kompromisse eingehen muss. Außerdem wird erörtert, was bei der Verwendung von Microservices alles zu beachten ist.

Kapitel 3– Gestaltung von Services Hier werden die Grenzen der Microservices erkundet. Um uns auf das Wesentliche zu konzentrieren, kommen dabei Verfahren des vom Anwendungsbereich geprägten Designs (Domain-Driven Design​, D​DD) zum Einsatz.

Kapitel 4– Integration An dieser Stelle beschäftigen wir uns eingehender mit bestimmten Auswirkungen der Technologien und erörtern, welche Arten der Zusammenarbeit von Services am nützlichsten sind. Des Weiteren werden wir auf die Themen Benutzerschnittstelle und Integration vorhandener und seriengefertigter Produkte (Commercial off-the-shel​f ,​ COTS) eingehen.

Kapitel 5– Die Aufspaltung des Monolithen In vielen Fällen richtet sich das Interesse auf die Microservices, um sie in großen, nur schwer änderbaren monolithischen Systemen sozusagen als Gegenmittel einzusetzen. Genau dieser Ansatz wird in diesem Kapitel ausführlich untersucht.

Kapitel 6– Deployment Das Buch ist zwar weitgehend theoretischer Natur, allerdings wurde kaum ein anderes der behandelten Themen so sehr durch die jüngsten technologischen Neuerungen beeinflusst wie das Deployment. Dieser Aspekt wird hier eingehender betrachtet.

Kapitel 7– Testen Dieses Kapitel geht dem Thema Testen auf den Grund – einem Bereich, der gerade beim Deployment mehrerer eigenständiger Services von Bedeutung ist. Besonders interessant ist hier die Rolle, die Consumer-Driven Contracts​ (CDC​s) für die Gewährleistung der Qualität unserer Software spielen.

Kapitel 8– Monitoring Die vor der Auslieferung durchgeführten Tests helfen uns nicht weiter, wenn Probleme erst auftreten, nachdem die Software bereits online gestellt wurde. In diesem Kapitel wird untersucht, wie sich verteilte Systeme überwachen lassen und wie man die bei solchen Systemen auftretende Komplexität handhabt.

Kapitel 9– Sicherheit Hier betrachten wir die Sicherheitsaspekte von Microservices und untersuchen, wie Authentifizierung und Autorisierung zwischen Benutzer und Service bzw. zwischen Services gehandhabt werden. Sicherheit ist ein sehr wichtiges Thema, das allzu leicht vernachlässigt wird. Ich bin zwar keineswegs ein Sicherheitsexperte, hoffe jedoch, dass dieses Kapitel Ihnen dabei hilft, beim Aufbau Ihrer Systeme bedeutsame Sicherheitsaspekte in Betracht zu ziehen – insbesondere, wenn es sich um Microservice-Systeme handelt.

Kapitel 10– Conways Gesetz und Systemdesign Dieses Kapitel widmet sich dem Zusammenspiel zwischen Organisationsstruktur und Systemarchitektur. Wie viele Unternehmen bereits feststellen mussten, führt es zu Problemen, wenn diese beiden Faktoren nicht aufeinander abgestimmt sind. Wir werden versuchen, die Ursachen dieses Dilemmas zu erörtern und betrachten verschiedene Möglichkeiten, das Systemdesign an die Struktur des Entwicklerteams anzugleichen.

Kapitel 11– Microservices skalieren Hier werden wir uns ansehen, wie Microservices skalieren, damit wir die bei einer großen Zahl von Services und hohem Datenaufkommen wachsende Wahrscheinlichkeit eines Systemausfalls handhaben können.

Kapitel 12– Auf den Punkt gebracht Das letzte Kapitel bemüht sich, die Besonderheiten von Microservices hervorzuheben. Es enthält eine Liste von sieben für Microservices geltende Prinzipien und arbeitet die Kernpunkte des Buches heraus.

Konventionen dieses Buches

In diesem Buch gelten folgende typografische Konventionen:

Neue Begriffe, Dateinamen und Dateinamenerweiterungen sind kursiv gedruckt.

URLs und E-Mail-Adressen sind im Hyperlink-Format dargestellt.

Für Programmlistings oder im Fließtext vorkommende Variablen- oder Funktionsnamen, Datenbanken, Datentypen, Umgebungsvariablen, Anweisungen und Schlüsselwörter wird eine nicht-proportionale Schrift verwendet.

Für vom Benutzer einzugebende Befehle und Texte wird eine fette nicht-proportionale Schrift benutzt.

Texte, die vom Benutzer durch eigene Eingaben oder aus dem Kontext ersichtliche Werte ersetzt werden sollen, sind in einer kursiven nicht-proportionalen Schrift gedruckt.

Danksagungen

Ohne Lindy Stephens würde es dieses Buch, das ihr gewidmet ist, nicht geben. Sie hat mich ermuntert, es in Angriff zu nehmen, hat mich bei dem oftmals anstrengenden Entstehungsprozess unterstützt und ist die beste Partnerin, die man sich nur wünschen kann. Ich möchte dieses Buch auch meinem Vater Howard Newman widmen, der immer für mich da war. Für euch beide ist dieses Buch.

Besonderer Dank gilt Ben Christensen, Vivek Subramaniam und Martin Fowler, die mir beim Schreiben dieses Buches ausführliche Rückmeldungen gaben und das vorliegende Werk dadurch mitgestalteten. Ich möchte auch James Lewis danken, mit dem ich bei der Besprechung der im Buch vorgestellten Ideen so manches Bier getrunken habe. Ohne eure Hilfe und Beratung wäre dieses Buch nur ein Schatten seiner selbst.

Außerdem haben viele andere mitgeholfen und die ersten Versionen des Buches kommentiert. Ich möchte insbesondere (in wahlloser Reihenfolge) folgenden Personen danken: Kane Venables, Anand Krishnaswamy, Kent McNeil, Charles Haynes, Chris Ford, Aidy Lewis, Will Thames, Jon Eaves, Rolf Russell, Badrinath Janakiraman, Daniel Bryant, Ian Robinson, Jim Webber, Stewart Gleadow, Evan Bottcher, Eric Sword, Olivia Leonard, sowie allen anderen Kollegen bei ThoughtWorks und in der Branche, die mir dabei geholfen haben, so viel zu erreichen.

Schließlich möchte ich auch der Belegschaft von O’Reilly USA danken, insbesondere Mike Loukides, der mich angeheuert hat, meinem Lektor Brian MacDonald sowie Rachel Monaghan, Kristen Brown, Betsy Waliszewski und all den anderen Leuten, die auf mir unbekannte Weise an der Entstehung dieses Buches beteiligt waren.

Über den Autor

Sam Newman ist als Technologe bei ThoughtWorks tätig, wo er einerseits als Berater für Klienten arbeitet und andererseits auch als Systemarchitekt für ThoughtWorks’ interne Systeme verantwortlich ist. Im Rahmen seiner Beratertätigkeit arbeitete er mit zahlreichen internationalen Unternehmen aus den unterschiedlichsten Geschäftsbereichen zusammen, wobei er oft mit einem Bein im Lager der Entwickler und mit dem anderen im Lager des IT-Betriebs stand. Wenn Sie ihn nach seiner Tätigkeit befragen, würde er sagen: »Ich helfe den Leuten dabei, bessere Softwaresysteme zu entwickeln.« Er veröffentlicht Artikel, hält Vorträge auf Fachtagungen und arbeitet hin und wieder auch an Open-Source-Projekten mit.

Kapitel 1: Microservices

Seit vielen Jahren erkunden wir inzwischen immer bessere Methoden für die Systementwicklung. Wir haben aus den Erfahrungen der Vergangenheit gelernt, neue Technologien adaptiert und erleben nun, wie eine neue Generation von Technologieunternehmen ganz verschiedene Ansätze bei der Errichtung von IT-Systemen verfolgt, die nicht nur ihre Kunden, sondern auch die eigenen Entwickler zufriedener stellen.

Eric Evans Buch Domain-Driven Design (Addison-Wesley) hat uns gelehrt, wie wichtig es ist, die reale Welt in unserem Code widerzuspiegeln und bessere Möglichkeiten aufgezeigt, unsere Systeme zu modellieren. Das Konzept Continuous Delivery führt vor, wie es gelingen kann, die Software effektiver und effizienter zur Serienreife zu bringen und schärft uns den Grundgedanken ein, jede einzelne Version wie einen zur Veröffentlichung geeigneten Release Candidate zu behandeln. Unsere Einsicht in die Funktionsweise des Webs hat uns dazu gebracht, bessere Methoden zur Kommunikation zwischen Computern zu entwickeln. Alistair Cockburns​ Konzept der hexagonalen Architektur (http://alistair.cockburn.us/Hexagonal+architecture) wies uns den Weg fort von abgestuften Architekturen, in denen sich die Anwendungslogik verbergen konnte. Virtualisierungsplattformen erlaubten es uns, Maschinen beliebiger Größe bereitzustellen und diese dank automatisierter Infrastrukturen in großem Maßstab einzusetzen. Einige große und erfolgreiche Unternehmen wie Amazon und Google befürworten die Ansicht, dass kleine Entwicklerteams für den vollständigen Entwicklungszyklus ihrer Services zuständig sein sollten. Und erst in jüngster Zeit hat Netflix uns den Aufbau robuster Systeme von einer Größe vorgeführt, die vor nur zehn Jahren kaum vorstellbar war.

Domain-Driven Design. Continuous Delivery. Virtualisierung nach Bedarf. Automatisierte Infrastrukturen. Kleine, eigenständige Entwicklerteams. Skalierbare Systeme. Aus diesem Umfeld sind die Microservices hervorgegangen. Sie wurden nicht vorab entwickelt oder geplant, sondern entstanden vielmehr aus den bei der praktischen Anwendung zu beobachtenden Tendenzen oder Mustern heraus. Microservices existieren also im Grunde genommen nur, weil es all die anderen genannten Dinge gibt. Ich werde im weiteren Verlauf des Buches immer wieder Verbindungen zu diesen vorausgehenden Entwicklungen aufzeigen, so dass sich schlussendlich beim Aufbau, der Verwaltung und der Fortentwicklung von Microservices ein geschlossenes Gesamtbild ergibt.

Viele Unternehmen haben nach der Einführung feingranularer Microservice-Architekturen festgestellt, dass ihre Software schneller zur Serienreife gelangt und selbst neue Technologien leicht übernommen werden können. Microservices gestatten uns eine deutlich größere Entscheidungsfreiheit, um auf die unvermeidlichen Änderungen reagieren zu können, die uns alle betreffen.

1.1  Was sind Microservices?

Microservices sind kleine, eigenständige Services, die kollaborieren bzw. sich gegenseitig zuarbeiten. Lassen Sie uns diese Definition im Folgenden etwas genauer fassen und die besonderen Eigenschaften der Microservices betrachten.

1.1.1  Klein und darauf spezialisiert, eine bestimmte Aufgabe richtig gut zu erledigen

Zur Ergänzung neuer Funktionalitäten schreiben wir zusätzlichen Code und erweitern damit zwangsläufig auch die Codebasis. Im Laufe der Zeit kann es allerdings schwierig werden, die Stelle zu finden, an der eine Modifikation erforderlich ist, weil die Codebasis so umfangreich geworden ist. Trotz des Strebens nach einer klar strukturierten, modularen monolithischen Codebasis werden die willkürlich gezogenen Grenzen nur allzu oft überschritten. Der zu ähnlichen Funktionen gehörende Code beginnt sich überall auszubreiten und erschwert es, Fehler zu beheben oder Änderungen vorzunehmen.

Bei monolithischen Systemen kämpfen wir dagegen an, indem wir versuchen, zusammenhängenden Code zu schreiben, nicht selten durch Abstrahierung oder das Erstellen von Modulen. Diese Geschlossenheit, also das Bestreben, zusammengehörigen Code auch zusammenzuhalten, spielt bei Microservices eine wichtige Rolle. Das wird auch durch das von Robert C. Martin​ definierte Prinzip einer einzigen Zuständigkeit​ bestätigt, das besagt: »Fasse Dinge zusammen, die aus demselben Grund geändert werden, und trenne Dinge, die aus unterschiedlichen Gründen geändert werden.«

Microservices verfolgen denselben Ansatz bezüglich voneinander unabhängiger Services. Wir beschränken unsere Services auf eng begrenzte Geschäftsvorgänge, damit offensichtlich ist, wo sich der zu einer bestimmten Funktionalität zugehörige Code befindet. Durch diese Fokussierung eines Services auf eine explizite Schnittstelle entgeht man der Versuchung, den Code zu groß werden zu lassen – und damit auch all den anderen Schwierigkeiten, die damit einhergehen können.

Man stellt mir oft die Frage: Wie klein ist klein? Hier eine Anzahl von Codezeilen anzugeben, ist problematisch, weil manche Programmiersprachen ausdrucksstärker sind als andere und daher dieselben Aufgaben in weniger Codezeilen verrichten können. Außerdem ist zu berücksichtigen, dass wir möglicherweise mehrfache Abhängigkeiten von anderem Code einbringen, der seinerseits aus vielen Zeilen besteht. Darüber hinaus sind manche Teile Ihrer Anwendung möglicherweise aus gutem Grund komplex und erfordern daher mehr Code. Jon Eaves​ (http://RealEstate.com.au) beschreibt einen Microservice als etwas, das in zwei Wochen neu geschrieben werden kann – eine Faustregel, die bei seinen besonderen Rahmenbedingungen tatsächlich sinnvoll ist.

Eine weitere, etwas banale Antwort auf obige Frage lautet: Klein genug, aber nicht zu klein. Als Redner auf Fachtagungen stelle ich fast immer die Frage: Wer betreibt ein zu großes System und würde es gern aufspalten? Nahezu jeder der Anwesenden hebt dann die Hand. Wir scheinen einen ausgeprägten Sinn dafür zu besitzen, etwas zu Großes zu erkennen. Folglich könnte man argumentieren, dass Code, der nicht mehr zu umfangreich erscheint, wahrscheinlich kompakt genug ist.

Bei der Beantwortung der Frage Wie klein? spielt es eine wichtige Rolle, in welchem Ausmaß der Service auf die Struktur des Entwicklerteams abgestimmt ist. Wenn die Codebasis zu groß ist, um von einem kleinen Entwicklerteam gehandhabt zu werden, ist es sinnvoll, sie aufzuspalten. Diese Abstimmung auf betriebliche Gegebenheiten wird später noch zur Sprache kommen.

Wenn es darum geht, wie klein denn nun klein genug ist, stelle ich mir das gern folgendermaßen vor: Je kleiner ein Service ist, desto stärker kommen die Vor- und Nachteile der Microservice-Architektur zum Tragen. Kleinere Services ziehen größere Vorteile aus der wechselseitigen Abhängigkeit. Gleichzeitig steigt aber auch die Komplexität, die sich aus dem Vorhandensein von immer mehr veränderlichen Systembestandteilen ergibt, was wir im weiteren Verlauf des Buches immer wieder untersuchen werden. Sobald man die Komplexität besser in den Griff bekommt, kann man auch immer kleinere Services anstreben.

1.1.2  Eigenständigkeit

Unser Microservice ist ein eigenständiges Gebilde. Dabei kann es sich um einen isolierten PaaS-Service (Platform-as-a-Service, Bereitstellung einer Computerplattform in der Cloud) handeln oder um einen eigenen Betriebssystemprozess. Wir versuchen zu vermeiden, mehrere Services auf derselben Maschine zu betreiben, auch wenn der Begriff Maschine heutzutage ziemlich vage ist. Diese Isolierung kann zwar etwas Verwaltungsaufwand verursachen, aber die damit einhergehende Vereinfachung trägt sehr dazu bei, das verteilte System besser zu verstehen. Außerdem werden viele der bei dieser Form des Deployments auftretenden Probleme durch neue Technologien deutlich entschärft.

Die Kommunikation der Services untereinander erfolgt durch Aufrufe über das Netzwerk. Dadurch wird die Isolierung der Services betont und man geht den Gefahren einer engen Kopplung aus dem Weg.

Die Services müssen unabhängig voneinander geändert und erneut bereitgestellt werden können und ohne Änderungen aufseiten der Consumer auskommen. Wir müssen uns Gedanken darüber machen, welche Informationen die Services preisgeben sollten und welche sie verbergen dürfen. Wenn zu viele Informationen gemeinsam genutzt werden, führt das zu einer Kopplung der Consumer an die interne Darstellung. Das vermindert die Eigenständigkeit, weil dadurch bei Änderungen eine zusätzliche Abstimmung mit den Consumern erforderlich wird.

Unser Service bietet eine A​PI (Application Programming Interface, Programmierschnittstelle) an, über die die anderen mit unserem Service kollaborierenden Services mit ihm kommunizieren. Wir müssen außerdem darüber nachdenken, welche Technologie am besten geeignet ist, damit durch die API selbst keine Kopplung an Consumer entsteht. Dazu kann es erforderlich sein, technologieunabhängige APIs einzusetzen, damit die Auswahl der eingesetzten Technologien nicht beschränkt wird. Wir werden im Verlauf des Buches immer wieder auf die Bedeutung einer guten entkoppelten API zurückkommen.

Ohne Entkopplung​ fällt alles wie ein Kartenhaus in sich zusammen. Die Gretchenfrage lautet: Können Sie eine Änderung an einem Service vornehmen und ihn erneut deployen, ohne irgendetwas anderes zu ändern? Lautet die Antwort Nein, werden sich viele der im Buch erörterten Vorteile nur schwer erzielen lassen.

1.2  Die wichtigsten Vorteile​

Microservices besitzen zahlreiche und vielgestaltige Vorteile. Viele davon bringt jedes verteilte System ohnehin mit sich, allerdings schöpfen Microservices das Potenzial dieser Vorteile tendenziell vor allem deswegen besser aus, weil sie bei der Umsetzung der Konzepte verteilter Systeme und serviceorientierter Architekturen (Service-Oriented Architecture, SOA) viel weiter gehen.

1.2.1  Verschiedenartige Technologien

Bei einem aus mehreren kollaborierenden Services bestehendem System können bei den einzelnen Services unterschiedliche Technologien zum Einsatz kommen. Dadurch ist es möglich, für jede Aufgabe das am besten geeignete Werkzeug auszuwählen, anstatt sich mit standardisierten Allzwecklösungen zufriedengeben zu müssen, die sich oftmals als kleinster gemeinsamer Nenner herausstellen.

Falls ein bestimmter Teil unseres Systems beschleunigt werden soll, könnten wir uns dazu entschließen, eine andere Technologie einzusetzen, die besser dafür geeignet ist, die erforderliche Geschwindigkeit zu erzielen. Es wäre ebenfalls möglich, die in verschiedenen Teilen des Systems anfallenden Daten auf unterschiedliche Weise zu speichern. Bei Anwendungen eines sozialen Netzwerks beispielsweise könnten wir die Interaktionen der Benutzer in einer grafikfähigen Datenbank speichern, um die hochgradig verknüpften Verbindungen in Form eines Social Graph widerzuspiegeln. Die Nachrichten der Benutzer hingegen könnten in einem dokumentorientierten Datenspeicher abgelegt werden, was zu einer heterogenen Architektur wie der in Abbildung 1.1 gezeigten führt.

Abb. 1.1: Microservices gestatten eine einfachere Übernahme unterschiedlicher Technologien.

Microservices ermöglichen außerdem eine schnellere Übernahme​ von Technologien, und wir können uns gegebenenfalls auch Verbesserungen zunutze mache. Die größten Hürden beim Ausprobieren und bei der Übernahme neuer Technologien sind die damit verbundenen Risiken. Wenn ich bei einer monolithischen Anwendung eine neue Programmiersprache, eine andere Datenbank oder ein Framework ausprobieren möchte, sind bei jeder Änderung weite Teile meines Systems betroffen. Bei einem aus mehreren Services bestehenden System stehen mir zum Austesten neuer Technologien hingegen gleich mehrere Möglichkeiten zur Verfügung. Ich kann mir einen unkritischen Service aussuchen, dessen Ausfall nur mit geringem Risiko verbunden wäre, und die Technologie dort einsetzen, wohlwissend, dass ich nur sehr begrenzten Schaden anrichten kann. Viele Unternehmen betrachten diese Möglichkeit, neue Technologien einzubinden, als echten Vorteil.

Die Integration mehrerer Technologien ist natürlich ohne einen gewissen Mehraufwand nicht machbar. Manche Unternehmen schränken etwa die Auswahl der Programmiersprache ein. Netflix und Twitter beispielsweise verwenden als Plattform vornehmlich die Java Virtual Machine (JVM​), weil sie über ein sehr gutes Verständnis der Zuverlässigkeit und der Leistungsfähigkeit dieses Systems verfügen. Beide Unternehmen entwickeln auch Bibliotheken und Hilfswerkzeuge für die JVM, was den Betrieb im großen Maßstab sehr erleichtert, aber den Einsatz nicht auf Java beruhender Services oder Clients erschwert. Jedoch beschränken sich selbst Twitter und Netflix nicht für sämtliche Aufgaben nur auf diese eine Technologie. Ein weiterer Kontrapunkt hinsichtlich der Bedenken, Technologien miteinander zu vermischen, ist auch die Größe der Codebasis: Wenn ich meinen Microservice tatsächlich in zwei Wochen komplett neu programmieren kann, sind die mit der Übernahme neuer Technologien verbundenen Risiken weitgehend entschärft.

Sie werden bei der Lektüre des Buches feststellen, dass es bei vielen Dingen, die Microservices betreffen, immer wieder darum geht, das richtige Gleichgewicht zu finden. Die Auswahl passender Technologien wird in Kapitel 2 erläutert, das sich vornehmlich mit der Fortentwicklung der Systemarchitektur beschäftigt. In Kapitel 4, das die Integration zum Thema hat, werden Sie erfahren, wie Sie Ihre Services voneinander unabhängig weiterentwickeln können, ohne sie übermäßig miteinander zu koppeln.

1.2.2  Belastbarkeit​

Bei der Gewährleistung einer hohen Belastbarkeit spielt das Abschotten der Services voneinander eine entscheidende Rolle: Wenn eine Komponente des Systems ausfällt, ohne die anderen in Mitleidenschaft zu ziehen, können Sie die betreffende Komponente isolieren und der Rest des Systems läuft weiter. Es liegt nahe, die Abschottung den Aufgaben der Services entsprechend vorzunehmen. Wenn bei einer monolithischen Anwendung ein Service ausfällt, funktioniert gar nichts mehr. Man kann monolithische Systeme auf mehreren Maschinen betreiben, um die Ausfallwahrscheinlichkeit zu verringern – bei der Verwendung von Microservices ist es allerdings möglich, Systeme zu entwickeln, deren Funktionalität bei einem Totalausfall von Services nur schrittweise abgebaut wird.

Wir sollten aber dennoch vorsichtig bleiben. Man muss die neuen Fehlerquellen, mit der verteilte Systeme vornehmlich zu kämpfen haben, genau verstehen, damit gewährleistet ist, dass unser Microservice-System Vorteile aus der erhöhten Belastbarkeit zieht. Netzwerke können nun einmal ausfallen – und das tun sie auch. Gleiches gilt für die Maschinen, auf denen das System läuft. Wir müssen daher wissen, wie Ausfälle zu handhaben sind und welche Auswirkungen, sofern vorhanden, diese Ausfälle für den Endbenutzer der Software haben.

In Kapitel 11 werden wir uns noch eingehender mit der Verbesserung der Belastbarkeit und der Handhabung von Fehlerzuständen beschäftigen.

1.2.3  Skalierung​

Bei einem großen, monolithischen Service muss alles gleichzeitig skaliert werden. Wenn auch nur ein kleiner Teil des Gesamtsystems nicht hinreichend leistungsfähig ist, dieser Teil aber in einer riesigen monolithischen Anwendung »eingesperrt« ist, muss das System als Ganzes skaliert werden. Bei der Verwendung kleinerer Services hingegen reicht es aus, nur die Leistungsfähigkeit der betroffenen Services zu erhöhen, was es ermöglicht, andere Teile des Systems auf weniger leistungsstarker Hardware zu betreiben (Abbildung 1.2).

Der Online-Modehändler Gilt hat Microservices aus genau diesem Grund eingeführt. Als Gilt 2007 seine Geschäftstätigkeit aufnahm, setzte das Unternehmen eine monolithische Rails-Anwendung ein. Ab 2009 konnte das System die zunehmende Last jedoch nicht mehr bewältigen. Nach der Aufspaltung wesentlicher Teile des Systems war Gilt dann aber wieder in der Lage, den aufkommenden Datenverkehr auch in Stoßzeiten zu handhaben. Heute laufen dort mehr als 450 Microservices, jeder davon auf mehreren unabhängigen Maschinen.

Abb. 1.2: Es reicht aus, nur die Leistungsfähigkeit betroffener Microservices zu erhöhen.

Beim Einsatz von Systemen, die Ressourcen nach Bedarf bereitstellen, wie z.B. Amazon Web Services (AWS), ist es sogar möglich, auch die Skalierung nur nach Bedarf vorzunehmen, nämlich nur für die Systembestandteile, bei denen es erforderlich ist. Dadurch wird es möglich, die anfallenden Kosten wesentlich effektiver zu steuern. Es kommt nur selten vor, dass ein architektonischer Ansatz so eng mit nahezu sofortigen Kosteneinsparungen verknüpft ist.

1.2.4  Komfortables Deployment​

Wenn bei einer aus Millionen Codezeilen bestehenden monolithischen Anwendung auch nur eine Zeile geändert wird, muss das Deployment für die gesamte Anwendung erneut durchgeführt werden, um diese Änderung zur Verfügung zu stellen. Das kann allerdings erhebliche Auswirkungen nach sich ziehen und birgt Risiken. In der Praxis werden solche risikobehafteten Deployments mit weitreichenden Auswirkungen aufgrund der verständlichen Sorgen, die man sich in diesem Zusammenhang macht, nur selten durchgeführt. Das bedeutet aber leider auch, dass sich die Modifikationen bis zum nächsten Release anhäufen und tatsächlich veröffentlichte Versionen somit jede Menge Anpassungen und Modifikationen aufweisen. Und je größer die Unterschiede zwischen den Versionen sind, desto höher ist auch das Risiko, Fehler zu begehen!

Bei der Verwendung von Microservices können wir dagegen Änderungen an einem einzelnen Service vornehmen und diesen dann unabhängig vom übrigen System deployen. Das ermöglicht es uns, den neuen Code schneller zu deployen. Falls ein Problem auftritt, kann es schnell einem bestimmten Service zugeordnet werden, was es wiederum erlaubt, Änderungen gegebenenfalls auch schnell wieder rückgängig zu machen. Darüber hinaus kann man auf diese Weise dem Kunden neue Funktionalitäten schneller zur Verfügung stellen. Das ist einer der Hauptgründe dafür, dass Unternehmen wie Amazon und Netflix diese Architektur verwenden – um zu gewährleisten, dass es bei der Veröffentlichung neuer Software so wenig Hindernisse wie möglich gibt.

Die auf diesem Gebiet eingesetzte Technologie hat sich in den letzten Jahren drastisch verändert. In Kapitel 6 werden wir das Deployment im Microservices-Umfeld noch genauer in Augenschein nehmen.

1.2.5  Betriebliche Abstimmung

Viele von uns wissen aus eigener Erfahrung um die Schwierigkeiten, die große Entwicklerteams und eine große Codebasis bereiten können. Diese Probleme können sich bei verteilten Teams noch verschärfen. Außerdem ist bekannt, dass kleinere Teams, die mit einer kleineren Codebasis arbeiten, tendenziell produktiver sind.

Microservices ermöglichen eine bessere Abstimmung der Architektur auf die Unternehmensstruktur und helfen uns dabei, die Anzahl der an einer bestimmten Codebasis arbeitenden Entwickler zu minimieren und so ein optimales Verhältnis zwischen Teamgröße und Produktivität zu erreichen. Außerdem können die Zuständigkeiten der Entwicklerteams umverteilt werden, damit die an einem bestimmten Service arbeitenden Entwickler am selben Ort tätig sind. Wir werden dieses Thema noch genauer betrachten, wenn in Kapitel 10 Conways Gesetz erörtert wird.

1.2.6  Modularer Aufbau

Man verspricht sich vom Einsatz verteilter Systeme und serviceorientierter Architekturen insbesondere, dass dadurch Möglichkeiten zur Wiederverwendung von Funktionalitäten eröffnet werden. Im Fall der Microservices ist vorgesehen, dass die Funktionalitäten auf verschiedene Weise für unterschiedliche Aufgaben nutzbar sind. Das kann besonders wichtig sein, wenn wir darüber nachdenken, wie die Nutzer unsere Software verwenden. Die Zeiten, in denen wir unsere Überlegungen entweder auf die Websiteversion für Desktoprechner oder Mobilgeräte beschränken konnten, sind lange vorbei. Heutzutage sind eine Unzahl von Kombinationen der Möglichkeiten des Webs, nativer Anwendungen, des mobilen Webs sowie von Tablet-Anwendungen oder tragbaren Geräten (»Wearables«) zu berücksichtigen. Während die Unternehmen dabei sind, sich von diesen einengenden Kommunikationskanälen zu verabschieden und sich eher ganzheitlichen Konzepten zur Kundenbindung zuwenden, benötigen wir Architekturen, die damit schritthalten können.

Mit Microservices öffnen wir unsere Systeme gewissermaßen einen Spaltbreit und machen einen Teil davon Außenstehenden zugänglich. Wenn sich die Umstände ändern, können wir unser System zur Anpassung anders aufbauen. Bei monolithischen Anwendungen steht mir als Außenstehendem oft nur ein vergleichsweise grobgranularer Zugang zur Verfügung. Wenn ich diesen Zugang weiter aufspalten möchte, um etwas Nützlicheres zu erhalten, brauche ich einen Vorschlaghammer! In Kapitel 5 werden wir erörtern, wie man bereits vorhandene monolithische Systeme aufspaltet und sie in hoffentlich wiederverwendbare und neu zusammensetzbare Microservices umwandelt.

1.2.7  Austauschbarkeit

Wenn Sie in einem Unternehmen mittlerer Größe oder sogar in einer großen Organisation tätig sind, stehen die Chancen nicht schlecht, dass dort ein großes, garstiges, veraltetes System in irgendeiner Ecke ein trauriges Dasein fristet. Das System, mit dem niemand etwas zu tun haben will. Das System, das für die Arbeitsweise Ihres Unternehmens unentbehrlich ist, aber in einem seltsamen Fortran-Dialekt programmiert ist und nur auf einer Hardware läuft, die besser vor 25 Jahren ausrangiert worden wäre. Warum wurde es nicht schon längst ersetzt? Sie ahnen es schon: Es wäre zu umständlich und zu riskant.

Bei einzelnen, kleinen Services ist der Aufwand für das Ersetzen einiger oder sogar aller Services durch eine verbesserte Implementierung viel leichter zu handhaben. Wie oft haben Sie schon an einem einzigen Tag mehr als hundert Codezeilen verworfen, ohne sich dabei allzu große Sorgen gemacht zu haben? Bei der Verwendung von Microservices, die oft von vergleichbarer Größe sind, fällt es nicht besonders schwer, sich dazu durchzuringen, einen Service neu zu schreiben oder vollständig zu entfernen.

Entwicklerteams, die den Microservice-Ansatz verfolgen, haben überhaupt kein Problem damit, bei Bedarf Services komplett neu zu programmieren oder überflüssige Services zu löschen. Wenn die Codebasis nur einige hundert Zeilen lang ist, wird wohl kaum jemand eine emotionale Bindung dazu aufbauen, und der Aufwand für das Ersetzen eines Services ist ziemlich gering.

1.3  Was ist mit serviceorientierten Architekturen?

Bei serviceorientierten Architekturen (Service-Oriented Architecture, SOA)​ handelt es sich um einen Designansatz, bei dem mehrere Services kollaborieren, um letzten Endes einen Satz an Funktionalitäten bereitzustellen. Hier ist mit dem Begriff »Service« typischerweise ein eigenständiger Betriebssystemprozess gemeint. Die Kommunikation zwischen diesen Services erfolgt über das Netzwerk, nicht durch Funktionsaufrufe innerhalb eines Prozesses.

SOA​ wurde entwickelt, um den Herausforderungen großer monolithischer Anwendungen etwas entgegenzusetzen. Dieser Ansatz zielt darauf ab, die Wiederverwendbarkeit von Software zu fördern. Beispielsweise könnten zwei oder mehr Programme für Endanwender dieselben Services nutzen. Die Wartung oder das Umschreiben von Software soll dadurch erleichtert werden, denn theoretisch könnten wir einen Service durch einen anderen ersetzen, ohne dass irgendjemand das bemerkt, sofern sich die Verwendungsweise des Services nicht allzu sehr ändert.

Im Grunde genommen ist SOA eine sehr vernünftige Idee, allerdings gibt es – trotz einer ganzen Reihe von Anläufen – keinen echten Konsens, wie SOA richtig umzusetzen ist. Meiner Ansicht nach betrachtet ein Großteil der Branche das Problem nicht ganzheitlich genug und präsentiert eine verlockende Alternative zur Sichtweise einiger Anbieter in diesem Umfeld.

Viele der Probleme, die SOA angelastet werden, hängen eigentlich mit anderen Dingen zusammen: Kommunikationsprotokolle (z.B. SOAP, Simple Object Access Protocol), Software zum Datenaustausch (Middleware) verschiedener Hersteller, fehlende Orientierungshilfe bei der Aufteilung der Services oder falsche Empfehlungen zur Auswahl der Stelle, an der ein System aufgespalten werden sollte. Ein Zyniker würde sagen, dass die Hersteller den SOA-Trend für sich vereinnahmt (und in einigen Fällen gefördert) haben, um die Verkäufe ihrer Produkte anzukurbeln, und dass ebendiese Produkte die SOA-Ziele letzten Endes untergraben.

Die landläufige Meinung über SOA trägt nicht zum Verständnis bei, wie etwas Großes in etwas Kleines aufgespalten wird. Es geht nicht darum, wie groß zu groß ist. Es geht hingegen zu wenig um realistische, praxisnahe Methoden, die gewährleisten, dass Services nicht zu eng gekoppelt werden. Die Summe der ungesagten Dinge ist der Ursprung für viele der Fallstricke, die mit SOA in Verbindung gebracht werden.

Der Microservice-Ansatz ist aus praktischen Anwendungen hervorgegangen und baut dabei auf unser besseres Verständnis der Systeme und Architekturen auf, um SOA richtig umzusetzen. Stellen Sie sich also Microservices lieber als einen bestimmten SOA-Ansatz vor, in derselben Weise, wie XP (Extreme Programming) oder Scrum bestimmte Ansätze der agilen Softwareentwicklung sind.

1.4  Weitere Verfahren zur Aufspaltung

Wenn man der Sache auf den Grund geht, stellt man fest, dass viele der Vorteile einer Microservice-basierten Architektur auf zwei Dingen beruhen: der Aufteilung der Services und der Tatsache, dass eine viel größere Auswahl an möglichen Herangehensweisen für Problemlösungen zur Verfügung steht. Aber könnten auch andere vergleichbare Verfahren zur Aufspaltung dieselben Vorteile bringen?​

1.4.1  Programmbibliotheken

Ein Standardverfahren zur Aufspaltung, das in praktisch jeder Programmiersprache vorkommt, ist die Aufteilung der Codebasis in mehrere Bibliotheken. Solche Bibliotheken können von Drittherstellern stammen oder in Ihrem Unternehmen erstellt worden sein.​

Bibliotheken ermöglichen es, Funktionalitäten mit anderen Entwicklerteams oder anderen Services zu teilen. Ich könnte beispielsweise einen Satz nützlicher Hilfsprogramme zur Handhabung von Objektsammlungen erstellen oder vielleicht eine wiederverwendbare Statistikbibliothek programmieren.

Entwicklerteams können sich entsprechend solcher Bibliotheken organisieren, und die Bibliotheken selbst sind wiederverwendbar. Es gibt aber auch einige Nachteile.

Erstens geht die echte Nutzung verschiedenartiger Technologien verloren, denn die Bibliothek muss typischerweise in derselben Sprache wie der Code programmiert sein, zumindest aber auf derselben Plattform laufen. Zweitens wird die Leichtigkeit beschnitten, mit der Sie Teile Ihres Systems voneinander unabhängig skalieren können. Drittens können Sie keine neue Bibliothek deployen, ohne auch den gesamten Prozess erneut zu deployen, sofern Sie keine dynamisch eingebundenen Bibliotheken verwenden. Dadurch schränken sich Ihre Möglichkeiten ein, isolierte Änderungen vorzunehmen. Das eigentliche Problem ist aber vermutlich, dass es nun keinen naheliegenden Zugang mehr gibt, über den Sie die architektonischen Sicherheitsmaßnahmen (siehe Kapitel 11) zur Aufrechterhaltung der Belastbarkeit des Systems einrichten können.

Dennoch haben Programmbibliotheken ihre Berechtigung. Sie werden für häufig anfallende Aufgaben, die unabhängig von einem bestimmten Geschäftsfeld sind, vermutlich Code erstellen, den Sie im gesamten Unternehmen wiederverwenden möchten – hier liegt es auf der Hand, eine wiederverwendbare Bibliothek einzusetzen. Seien Sie aber dennoch vorsichtig: Gemeinsam genutzter Code, der zur Kommunikation zwischen Services eingesetzt wird, kann zu einer Kopplung führen. Mehr dazu in Kapitel 4.

Services können auf Bibliotheken von Drittherstellern zugreifen und sollten auch regen Gebrauch davon machen, um häufig vorkommenden Code wiederzuverwenden. Die alleinige Lösung ist das aber nicht.

1.4.2  Module

Manche Programmiersprachen stellen eigene Verfahren zur Aufspaltung zur Verfügung, die die Möglichkeiten einfacher Bibliotheken übertreffen. Dabei kann die Lebensdauer solcher Module gesteuert werden, indem sie aktiviert und deaktiviert werden, was es ermöglicht, sie laufenden Prozessen bereitzustellen. Auf diese Weise können Sie Änderungen vornehmen, ohne den ganzen Prozess beenden zu müssen.

Hier ist insbesondere die Open Source Gateway Initiative (OSGI)​ als Ansatz zur Modularisierung zu nennen. Java an sich kennt noch keine richtigen Module und wir werden mindestens auf die Java-Version 9 warten müssen, bis die Sprache dahingehend erweitert wird. OSGI wurde in Form eines Frameworks entwickelt, das es ermöglicht, in der Java-IDE Eclipse Plug-ins zu installieren und wird nun dazu verwendet, in Java über eine Bibliothek ein Modulkonzept nachzurüsten.

Das Problem ist, dass OSGI Funktionalitäten wie die Steuerung der Lebensdauer von Modulen zu erzwingen versucht, ohne dass die Sprache selbst dies hinreichend unterstützt. Das führt dazu, dass die Modulautoren mehr Arbeit aufwenden müssen, um die Module ordnungsgemäß zu isolieren. Außerdem gerät man innerhalb eines einzelnen Prozesses allzu leicht in Versuchung, die verschiedenen Module zu sehr zu koppeln, was wiederum die verschiedensten Probleme hervorrufen kann. Ich weiß aus eigener Erfahrung, die mit derjenigen von Kollegen aus der Branche übereinstimmt, dass OSGI selbst bei guten Entwicklerteams schnell zu einer Komplexität führen kann, die von den Vorteilen nicht aufgewogen wird.

Die Programmiersprache Erlang verfolgt einen anderen Ansatz, bei dem Module zu einem Bestandteil der Laufzeitumgebung werden. Erlang ist somit eine sehr ausgereifte Verfahrensweise zur Modularisierung. Erlang-Module​ lassen sich problemlos stoppen, neu starten und aktualisieren. Diese Programmiersprache gestattet es sogar, mehrere Versionen eines Moduls gleichzeitig laufen zu lassen, wodurch es möglich ist, Module auf elegante Weise zu aktualisieren.

Die Fähigkeiten der Erlang-Module sind tatsächlich beeindruckend, aber selbst wenn wir das Glück haben, eine Plattform mit diesen Fähigkeiten zu verwenden, verbleiben immer noch die Unzulänglichkeiten, die wir von herkömmlichen Programmbibliotheken kennen. Unsere Möglichkeiten, neue Technologien einzusetzen, sind sehr beschränkt: Wir können nur in begrenztem Maße unabhängig skalieren, laufen Gefahr, zu stark koppelnde Integrationsverfahren zu verwenden, und es fehlt der Zugang zu architektonischen Sicherheitsmaßnahmen.

Es gibt an dieser Stelle aber noch eine weitere erwähnenswerte Überlegung. Rein technisch sollte es möglich sein, innerhalb eines einzelnen monolithischen Prozesses ordnungsgemäß aufgeteilte, unabhängige Module zu erstellen. Dessen ungeachtet sieht man dergleichen nur selten. Die Module selbst werden schon bald eng mit dem übrigen Code gekoppelt sein und geben damit einen ihrer wichtigsten Vorteile preis. Eine deutliche Trennung der Prozesse zwingt in dieser Hinsicht zu »sauberer« Programmierung (oder erschwert es zumindest, etwas falsch zu machen!). Ich will natürlich nicht behaupten, dass dies der entscheidende Antrieb zur Trennung von Prozessen sein sollte, aber es ist interessant festzustellen, dass die Vorteile einer Modularisierung innerhalb der Grenzen eines Prozesses in der Praxis kaum zum Tragen kommen.

Nun ist die Modularisierung und die Aufspaltung des Systems in Services zwar wünschenswert, kann allein aber auch nicht alle Probleme lösen.

Falls Sie ausschließlich Erlang einsetzen, kommen Sie dank der Qualität der Modulimplementierung in dieser Programmiersprache schon ziemlich weit, allerdings vermute ich, dass dies für meisten Leser nicht zutrifft.

1.5  Kein Patentrezept

Bevor wir zum Ende dieses Kapitels kommen, möchte ich noch darauf hinweisen, dass Microservices keine Wunderwaffe, kein Patentrezept und auch als Allheilmittel keine gute Wahl sind. Sie besitzen die mit verteilten Systemen einhergehende Komplexität, und auch wenn wir eine Menge über die richtige Handhabung (die im Buch immer wieder zur Sprache kommen wird) solcher Systeme gelernt haben, bleibt sie schwierig. Gegenüber monolithischen Systemen müssen Deployment, Tests und Monitoring erheblich verbessert werden, damit Sie in den Genuss der bislang vorgestellten Vorteile gelangen können. Im Vergleich zu monolithischen Systemen müssen Sie auch bei der Skalierung Ihrer Systeme und der Gewährleistung der Belastbarkeit umdenken. Seien Sie ebenfalls nicht überrascht, wenn Ihnen Dinge wie verteilte Transaktionen oder das CAP-Theorem Kopfzerbrechen bereiten werden!

Alle Unternehmen, Organisationen und Systeme sind unterschiedlich. Es gibt eine ganze Reihe von Faktoren, die eine Rolle dabei spielen, ob Microservices in Ihrem Fall geeignet sind oder nicht und wie aggressiv Sie bei der Einführung vorgehen können. Ich werde in den folgenden Kapiteln des Buches versuchen, die möglichen Fallstricke aufzuzeigen, damit Sie einen verlässlichen Weg vor Augen haben.

1.6  Fazit

Jetzt können Sie sich hoffentlich ein besseres Bild von den Microservices machen und wissen, was sie von anderen Aufspaltungsverfahren unterscheidet und was die entscheidenden Vorteile sind. In den nachfolgenden Kapiteln werden wir detaillierter betrachten, wie sich diese Vorteile erzielen lassen und wie man die typischen Stolpersteine umgeht.

Es gibt eine Vielzahl zu behandelnder Themen, aber irgendwo muss man ja anfangen. Eine der größten Herausforderungen, die Microservices mit sich bringen, ist die veränderte Rolle, die den für die Entwicklung verantwortlichen Systemarchitekten zukommt. Wir sehen uns zunächst verschiedene Ansätze zum Ausfüllen dieser Rolle an, um zu gewährleisten, dass wir diese neue Architektur auch wirklich ausreizen.

Kapitel 2: Der fortentwickelte Systemarchitekt

Wir haben bislang erfahren, dass Microservices viele Auswahlmöglichkeiten bieten und wir dementsprechend viele Entscheidungen treffen müssen – beispielsweise wie viele verschiedene Technologien wir einsetzen wollen, ob die diversen Entwicklerteams unterschiedliche Programmiersprachen verwenden dürfen und ob Services besser zusammengeführt oder aufgespalten werden. Doch wie werden diese Entscheidungen gefällt? Mit den zunehmend schnelleren Veränderungen und den flexibleren Umgebungen, die solche Architekturen möglich machen, muss sich auch die Rolle des Systemarchitekten wandeln. In diesem Kapitel werde ich einen ziemlich subjektiven Blick darauf werfen, welche Rolle der Systemarchitekt spielt und damit zu einem hoffentlich letzten Angriff auf den Elfenbeinturm blasen.

2.1  Unangebrachte Vergleiche

Sie benutzen immer wieder dieses Wort. Ich glaube aber nicht, dass es das bedeutet, was Sie denken.

Inigo Montoya in Die Braut des Prinzen

Systemarchitekten​ erfüllen eine wichtige Aufgabe: Sie zeichnen dafür verantwortlich, dass wir ein gemeinsames technisches Leitbild haben, das uns dabei hilft, unseren Kunden die erforderlichen Systeme bereitzustellen. Mancherorts muss ein Systemarchitekt nur mit einem Team zusammenarbeiten – in diesem Fall ist er oftmals gleichzeitig auch technischer Leiter. Andernorts gehört es zu seinen Aufgaben, mehrere womöglich weltweit verstreute Entwicklerteams zu koordinieren und das Leitbild für ein Projekt zu formen, mitunter sogar für unternehmensweite Projekte. Auf welcher Ebene ein Systemarchitekt auch tätig ist, die Rolle ist schwierig einzugrenzen, und auch wenn es der naheliegende Schritt auf der Karriereleiter für in Unternehmen tätige Programmierer ist, handelt es sich um die wohl am meisten kritisierte Position. Die Qualität des errichteten Systems, die Arbeitsbedingungen der Kollegen und die Fähigkeit des Unternehmens, auf Änderungen zu reagieren, werden stärker unmittelbar durch die Rolle des Systemarchitekten beeinflusst als durch jede andere – und dennoch wird sie so häufig missverstanden. Woran liegt das?

Unsere Branche ist noch jung. Wir scheinen diesen Umstand zwar leicht zu übersehen, tatsächlich erstellen wir aber immerhin erst seit etwa 70 Jahren überhaupt Programme, die auf von uns als Computer verstandenen Maschinen laufen. Daher schielen wir in dem Bemühen zu erklären, was wir eigentlich machen, stets ein wenig auf andere Berufe. Wir sind weder Ärzte oder Ingenieure noch Klempner oder Elektriker. Wir fallen durchs Raster und landen irgendwo dazwischen. Dadurch fällt es der Gesellschaft schwer, uns zu verstehen – und uns fällt es schwer zu verstehen, wo wir hingehören.

Also greifen wir auf andere Berufsbezeichnungen zurück und nennen uns Software-»Ingenieure« oder System-»Architekten«. Aber sind wir das eigentlich wirklich? Architekten und Ingenieure verfügen über eine Präzision und Disziplin, von der wir nur träumen können, und ihre gesellschaftliche Bedeutung ist wohlbekannt. Ich kann mich noch gut an ein Gespräch mit einem Freund erinnern, der einen Tag später seine Ausbildung zum Architekten abschließen sollte. Er sagte: »Wenn ich dir morgen Abend in der Kneipe einen Ratschlag gebe, wie du etwas zu bauen hast und dieser Rat falsch ist, kann ich dafür zur Verantwortung gezogen werden. Ich kann verklagt werden, weil ich dann vor dem Auge des Gesetzes ein ausgebildeter Architekt bin und dafür verantwortlich gemacht werden sollte, wenn ich etwas falsch mache.« Aufgrund der gesellschaftlichen Bedeutung dieser Berufsstände müssen bestimmte Qualifizierungen nachgewiesen werden. In Großbritannien beispielsweise ist ein mindestens siebenjähriges Studium erforderlich, bevor man sich Architekt nennen darf. Allerdings beruhen diese Berufe auch auf einem gesammelten Wissen, das mehrere tausend Jahre zurückreicht. Und wie sieht es bei uns aus? Tausende von Jahren? Nicht ganz. Das ist auch der Grund dafür, warum ich die meisten Arten von IT-Zertifizierungen für wertlos halte, denn wir wissen nur sehr wenig darüber, was gut in unserem Tätigkeitsfeld eigentlich bedeutet.

Manche von uns wünschen sich jedoch eine gewisse Bestätigung, und so borgen wir uns Bezeichnungen aus anderen Berufen, die bereits die Anerkennung genießen, nach der sich unsere Branche sehnt. Das kann in zweierlei Hinsicht gefährlich sein. Zum einen setzt es voraus, dass wir wissen, was wir tun – doch das ist schlicht und einfach nicht der Fall. Ich will ja nicht behaupten, dass Gebäude oder Brücken niemals einstürzen, allerdings passiert das im Verhältnis zu der Anzahl der Abstürze unserer Programme deutlich seltener, was den Vergleich unserer Tätigkeit mit der von Ingenieuren ziemlich unangebracht erscheinen lässt. Und zum zweiten funktionieren die Analogien schon bei einer nur flüchtigen Betrachtung nicht mehr. Oder anders ausgedrückt: Wenn es beim Bau einer Brücke wie beim Programmieren zuginge, würden wir auf halber Strecke feststellen, dass das andere Ufer 50 Meter weiter entfernt ist als gedacht, dass es nicht aus Granit, sondern aus Schlamm besteht, und dass wir keine Fußgängerbrücke, sondern eine für den Straßenverkehr geeignete Brücke bauen sollen. Unsere Software unterliegt nicht den physikalischen Einschränkungen, mit denen sich echte Architekten oder Ingenieure auseinandersetzen müssen. Was wir erstellen, ist dafür ausgelegt, anpassbar zu sein und sich mit den Anforderungen des Benutzers weiterzuentwickeln.

Vielleicht hat der Begriff Architekt den meisten Schaden angerichtet – die Vorstellung von jemandem, der detaillierte Pläne für andere zeichnet und erwartet, dass diese Pläne sachgerecht ausgeführt werden. Halb Künstler, halb Ingenieur, überwacht er die Entstehung seiner Vision, der alle anderen Aspekte untergeordnet sind, von den gelegentlichen Einwänden der Bauingenieure hinsichtlich physikalischer Gesetze einmal abgesehen. Eine solche Anschauung von einem Architekten führt in unserer Branche mitunter zu verheerenden Praktiken. Beseelt davon, das perfekte System zu konstruieren, werden Diagramm für Diagramm, Seite für Seite Dokumentationen erstellt, ohne dabei die grundsätzlich unbekannte Zukunft zu berücksichtigen. Ohne das geringste Verständnis dafür, wie schwierig die Implementierung sein wird oder ob es überhaupt funktioniert oder nicht, geschweige denn irgendwelche Möglichkeiten vorzusehen, Anpassungen vorzunehmen, sobald man mehr weiß.

Wenn wir uns mit Ingenieuren oder Architekten vergleichen, laufen wir Gefahr, uns allen einen Bärendienst zu erweisen. Leider sind wir aber fürs Erste auf den Begriff Architekt angewiesen. Daher erscheint es am vernünftigsten, neu zu definieren, was er in unserem Kontext bedeutet.

2.2  Das Zukunftsbild eines Systemarchitekten

Die an uns gestellten Anforderungen ändern sich schneller, als dies bei Architekten der Fall ist, die Gebäude entwerfen und bauen. Gleiches gilt für die Anforderungen an die uns zur Verfügung stehenden Werkzeuge und Techniken. Die Software, die wir erstellen, ist nicht unveränderlich. Ist sie erst einmal im produktiven Einsatz, wird sie sich weiterentwickeln, sobald sich die Art und Weise ihrer Nutzung ändert. Und sobald unsere Software in die Hände des Kunden gelangt, wird uns in den meisten Fällen nichts anderes übrig bleiben, als zu reagieren und sie anzupassen, denn es handelt sich ja nicht um ein unveränderliches Produkt. Unsere Systemarchitekten sollten sich daher nicht damit befassen, ein perfektes Endprodukt zu liefern, sondern sich darauf konzentrieren, Frameworks zu erstellen, in denen sich das richtige System allmählich entwickeln und weiter wachsen kann, während wir neue Erkenntnisse hinzugewinnen.

Ich habe Sie zwar in diesem Kapitel bisher ständig davor gewarnt, unsere Aufgaben allzu sehr mit anderen Berufen zu vergleichen, dennoch gibt es eine Analogie zur Tätigkeit des IT-Architekten, die mir besonders gefällt und sehr gut beschreibt, was diese Rolle eigentlich leisten soll. Erik Doernenborg erzählte mir von seiner Idee, dass wir uns unsere Rolle eher als Stadtplaner vorstellen sollten, nicht als Architekten der darin vorhandenen Gebäude. Was zu den Aufgaben eines Stadtplaners gehört, dürfte Ihnen spätestens dann vertraut sein, wenn Sie schon mal SimCity gespielt haben: Die Aufgabe eines Stadtplaners besteht darin, eine Vielzahl von Informationsquellen im Auge zu behalten und zu versuchen, den Aufbau der Stadt so zu optimieren, dass die gegenwärtigen Anforderungen der Bewohner so gut wie möglich befriedigt werden, dabei aber zugleich auch die zukünftige Entwicklung zu berücksichtigen. Interessant ist die Art und Weise der Einflussnahme des Planers auf die Stadtentwicklung: Er sagt nicht »Baue an dieser Stelle ein bestimmtes Gebäude«, sondern nimmt eine Zoneneinteilung vor. In SimCity können Sie beispielsweise einen Teil der Stadt als Industriegebiet ausweisen und einen anderen Teil als Wohngebiet. Wo genau welche Gebäude entstehen, wird von anderen entschieden, es gibt jedoch Einschränkungen: Wenn Sie eine Fabrik bauen möchten, muss dies in einem Industriegebiet geschehen. Anstatt sich darum zu kümmern, was in einer Zone passiert, verbringt der Stadtplaner weitaus mehr Zeit damit, die Art und Weise auszuarbeiten, wie Einwohner und Versorgungsbetriebe von einer Zone in die andere umsiedeln.

Städte werden manchmal als eine Art Lebewesen betrachtet. Jede Stadt verändert sich im Laufe der Zeit. Sie entfaltet und entwickelt sich entsprechend der Art und Weise, wie die Bewohner sie »nutzen« oder sie durch äußere Einflüsse geprägt wird. Der Stadtplaner versucht, diese Veränderungen möglichst genau vorherzusehen, muss aber akzeptieren, dass es zwecklos ist, sämtliche Aspekte der damit verbundenen Geschehnisse gezielt kontrollieren zu wollen.

Der Vergleich mit Software liegt auf der Hand: Sobald die von uns erstellte Software von den Benutzern verwendet wird, müssen wir darauf reagieren und entsprechende Änderungen daran vornehmen. Wir können allerdings nicht vorhersehen, was passieren wird, und anstatt für jede Eventualität gerüstet zu sein, sollten wir daher lieber Möglichkeiten für nachträgliche Anpassungen einplanen, indem nicht jedes letzte noch so kleine Detail festgelegt wird. Unsere Stadt – das System – soll für alle Bewohner ein schöner, angenehmer Ort zum Leben sein. Eine Sache wird dabei jedoch häufig übersehen: Unser System soll nicht nur den Benutzern entgegenkommen, sondern auch den Entwicklern und dem Betriebspersonal. Denn dieser Personenkreis arbeitet ebenfalls damit und soll gewährleisten, dass bei Bedarf Änderungen vorgenommen werden. Um einen Ausdruck von Frank Buschmann zu verwenden: Systemarchitekten haben die Verpflichtung, das System auch für Entwickler bewohnbar zu machen.​

Ein Stadtplaner muss, ebenso wie ein Systemarchitekt, außerdem wissen, wenn seiner Planung nicht Folge geleistet wird. Wenn er nur wenige Vorschriften erlässt, wird die Anzahl der zur Kurskorrektur nötigen Eingriffe minimal bleiben, falls aber jemand beabsichtigt, in einem Wohngebiet eine Kläranlage zu bauen, muss er das verhindern können.

Unsere Systemarchitekten müssen als Stadtplaner die Entwicklungsrichtung also nur in groben Zügen vorgeben und sich nur in wenigen Fällen bei ganz bestimmten Implementierungsdetails einmischen. Sie müssen sicherstellen, dass das System seinen heutigen Zweck erfüllt, aber auch zukunftstauglich ist. Außerdem muss gewährleistet sein, dass das System Benutzer und Entwickler gleichermaßen zufriedenstellt. Das klingt nach einer ziemlichen Herausforderung. Womit fangen wir also an?

2.3  Zoneneinteilung

Um die Metapher des Systemarchitekten als Stadtplaner ein weiteres Mal zu bemühen: Was entspricht den Zonen? Da wären die Schnittstellen der Services oder vielleicht auch etwas gröber unterteilte Gruppen von Services. Als Softwarearchitekten müssen wir uns viel weniger darum kümmern, was innerhalb der Zonen passiert, als vielmehr um das, was zwischen den Zonen vor sich geht. Das bedeutet, dass wir uns Gedanken darüber machen müssen, wie unsere Services miteinander kommunizieren oder dass die Möglichkeit, den Gesamtzustand unseres Systems zu überwachen, gewährleistet sein muss. In welchem Maße wir dabei im Inneren einer Zone eingreifen, variiert von Fall zu Fall. Viele Unternehmen haben Microservices eingeführt, um die Eigenständigkeit der Entwicklerteams zu maximieren. In Kapitel 10 werden wir darauf zurückkommen. Wenn Sie in solch einem Unternehmen tätig sind, werden Sie sich bei Entscheidungsfindungen häufiger auf das Entwicklerteam stützen können.

Zwischen den Zonen bzw. den Kästen in unseren herkömmlichen Architekturdiagrammen, müssen wir jedoch äußerst vorsichtig sein. Sollten hier Fehler unterlaufen, kann dies zu allen möglichen Problemen führen. Außerdem ist die Korrektur dieser Fehler unter Umständen sehr schwierig.

Innerhalb eines einzelnen Services ist es normalerweise unproblematisch, wenn das zuständige Entwicklerteam eine andere Technologie oder eine andere Methode zur Datenspeicherung auswählt. Hier können aber natürlich auch noch andere Belange eine Rolle spielen. Ihre Bereitschaft, die Entwicklerteams die geeigneten Werkzeuge selbst auswählen zu lassen, wird möglicherweise dadurch gezügelt, dass es schwieriger wird, Entwickler zu finden oder anderen Teams zuzuweisen, wenn zehn verschiedene Technologien unterstützt werden müssen. Wenn außerdem jedes Entwicklerteam eine völlig andere Methode zur Datenspeicherung auswählt, fehlt Ihnen womöglich die nötige Erfahrung, irgendeine davon in größerem Maßstab zu betreiben. Netflix beispielsweise hat das Datenbankmanagementsystem Cassandra weitgehend zum Standard erhoben. Und auch wenn es nicht in allen Fällen die beste Lösung ist, hält Netflix den Nutzen, den die bereitgestellten Werkzeuge und die mit Cassandra​ gesammelten Erfahrungen bringen, für wichtiger, als verschiedene andere Plattformen zu unterstützen und zu betreiben, die möglicherweise für bestimmte Aufgaben besser geeignet wären. Nun ist Netflix sicherlich ein extremes Beispiel, weil hier die Skalierbarkeit der wohl alles entscheidende Faktor ist, aber Sie verstehen schon, was gemeint ist.

Der Bereich zwischen den verschiedenen Services kann allerdings Probleme bereiten. Wenn ein Service REST (Representational State Transfer) via HTTP anbietet, ein anderer Protocol Buffers verwendet und ein dritter Java RMI (Remote Method Invocation, Aufruf entfernter Methoden) einsetzt, kann die Integration zu einem Alptraum werden, denn die darauf zugreifenden Services müssen dann mehrere Austauschformate unterstützen. Daher versuche ich der Leitlinie treu zu bleiben, sich darum zu kümmern, was zwischen den Kästen geschieht, und bei Vorgängen im Inneren großzügig zu sein.

Der programmierende Systemarchitekt

Wenn wir gewährleisten müssen, dass die von uns erstellten Systeme für Entwickler »bewohnbar« sind, müssen unsere Systemarchitekten die Folgen ihrer Entscheidungen einschätzen können. Sie sollten also zumindest zeitweise mit dem Entwicklerteam zusammenarbeiten und idealerweise auch zusammen mit den Entwicklern tatsächlich programmieren. Wenn bei Ihnen Paarprogrammierung​ praktiziert wird, bedeutet das einfach nur, dass ein Systemarchitekt kurzzeitig Mitglied eines Paares wird. Am besten sollten Sie dabei an herkömmlichen Aufgabenstellungen arbeiten, um einen Eindruck davon zu bekommen, wie sich die alltägliche