Erinnern Sie sich noch an Ihr erstes Mal? Nicht, was Sie jetzt denken. Gemeint ist vielmehr die Zeit, als Sie Ihren ersten Microservice implementierten? Über ein Jahrzehnt ist vergangen, seitdem die Community der Softwarearchitektinnen und Softwarearchitekten dieses Konzept im späten Zeitalter des SOAzän zum ersten Mal diskutierte. Im Jahr 2014 haben Microservice-Vater James Lewis und Martin Fowler ausgiebig darüber sinniert, welche Definition Microservices zugrunde liegen sollte und kamen zu folgendem Ergebnis:
Die Microservice-Architektur ist ein Ansatz zur Entwicklung einer einzigen Anwendung als eine Reihe kleiner Dienste, die jeweils in einem eigenen Prozess ausgeführt werden und über leichtgewichtige Mechanismen, häufig eine HTTP-Ressourcen-API, kommunizieren. Diese Dienste sind um Geschäftsfunktionen herum aufgebaut und können unabhängig voneinander durch vollautomatische Bereitstellungsmaschinen eingesetzt werden. Diese Dienste, die in verschiedenen Programmiersprachen geschrieben sein können und unterschiedliche Datenspeichertechnologien verwenden, werden nur minimal zentral verwaltet.
Zu Beginn dieser neuen Ära war freilich das Implementieren von Microservices eher eine Sache von vielen Stunden oder sogar Tagen. Heutzutage lassen sich zum Beispiel Spring Boot 3, IntelliJ Idea Ultimate und Docker einsetzen, um mittels Java-Annotationen wie @SpringBootApplication oder @RestController in nur wenigen Minuten einen laufenden und halbwegs sinnvollen Microservice mit zahlreichen Endpunkten bereitzustellen. Den REST inklusive eines Testrahmens generiert das Framework automatisch. Kommen Sicherheitsaspekte oder Persistenzlösungen ins Spiel, steht das Framework ebenfalls mit Rat und Tat zur Seite. Darunter fallen alle möglichen Datenbanken und die dafür notwendigen JPA-Wrapper.
Das Spring-Framework im Allgemeinen und Spring Boot 3 im Speziellen verfügen natürlich über wesentlich mehr Funktionalität als die zur Generierung von Microservices. Allerdings fokussieren sich viele Anwendungen heutzutage auf das Erstellen von Web-Anwendungen und Microservices, weshalb ich mich hier auf die Letzteren konzentriere.
Wie immer im Leben stehen Entwickler vor der Qual der Wahl, denn auch andere Mütter haben schöne Frameworks. Für Java sind dies unter anderem Micronaut, Quarkus und Vert.x, für JavaScript vor allem Node.js und für Python-Enthusiasten vorwiegend Django.
Wer lediglich Microservices aufrufen will, kann das in Desktop- Betriebssystemen, auf mobilen oder auch auf eingebetteten Systemen bis hin zu niedertourigen Mikrocontroller-Boards bequem bewerkstelligen. Es lebe das Internet der Dinge!
Nicht zu vergessen (Docker-)Container, die den jeweiligen Dienst in eine abgeschirmte Sandbox integrieren und mittels Kubernetes für Skalierbarkeit und Ausfallsicherheit sorgen.
Möglich ist das vor allem durch das leichtgewichtige und dank HTTP überall einsetzbare RESTful-Architekturmuster mit seinem HATEOAS-Paradigma (Hypermedia as the Engine of Application State). Demnach sind Microservices nichts anderes als Ressourcen, auf die eine Entwicklerin zum Beispiel mittels GET-, PUSH-, PUT-, DELETE-Aufrufen uniform zugreift. Trotzdem können dadurch komplexe Programmierschnittstellen (APIs) entstehen, deren Verwaltung Entwicklerinnen und Entwickler vor neue Herausforderungen stellt – Stichwort API-Management und API-Gateways.
Es ist halt wie immer in der Informatik: Eliminiert eine Technologie Komplexität, schlägt die Komplexität auf einer anderen Ebene zu, wenngleich meistens auf einem höheren Abstraktionsniveau. Haben sich etwa Fehler in den eigenen Code eingeschlichen, kann die Fehlerursache teilweise recht aufwendig sein, auch wenn das Framework sachdienliche, meistens zielführende Hinweise gibt. Merke: Das Verbergen von Systemdetails kann einem bei der Fehlersuche auf die eigenen Füße fallen. Darüber hinaus ist es wie immer: Die besten Technologien nützen nur wenig, wenn Anforderungen oder Architekturfragen in einem Projekt hintanstehen - Garbage-in-Garbage-out.
Doch was mach ich nur, ich armer Tor, welch' Framework nehm ich mir vor?
Für Java- beziehungsweise JVM-Entwickler zeichnet sich Quarkus durch den niedrigen Speicherfußabdruck, eine schnelle Boot-Zeit und das integrierte Kubernetes aus. Erwähnenswert ist in diesem Zusammenhang, dass Quarkus intern sowohl das Eclipse MicroProfile als auch Vert.x nutzt.
Micronaut wiederum glänzt durch seine Cloud-native-Strategie, integriertes Lokalisieren von Diensten sowie Kubernetes-Unterstützung. Der Lebenszyklus von Microservices gestaltet sich dort leichter, wohingegen Spring mehr Flexibilität erlaubt - wo Licht, da auch Schatten.
Spring Boot wiederum verfügt über eingebettete Server wie Tomcat oder Jetty, findet in vielen IDEs Unterstützung und besitzt etwa 62 Prozent Marktanteil (Stand 2021). Quarkus (6 Prozent) und Micronaut (4 Prozent) folgen mit großem Abstand. Auf die weiteren Frameworks gehe ich daher erst gar nicht ein. Für Spring existiert dementsprechend eine riesige Community, was aber die Bedeutung der anderen Frameworks nicht schmälern soll, die ebenfalls ihre Berechtigung haben. Zu Quarkus gibt es bereits ein paar Artikel in JavaSPEKTRUM.
Da viele Microservices auf Containern und in der Cloud laufen, spielen auch Containertechnologien wie Docker, Rocket oder containerd eine wichtige Rolle. In IDEs wie IntelliJ IDEA oder Visual Studio Code findet sich selbst dafür Unterstützung, was die Entwicklung sehr erleichtert.
Entscheidend für Softwareentwicklungsprojekte ist jedenfalls, inwieweit das Framework der Wahl sich mit den eigenen Vorstellungen, Vorkenntnissen und Anforderungen deckt. Eine gute Wahl stellen alle genannten Frameworks dar.