Microservices und die Benutzeroberfläche
Dieser Beitrag ist ein Erfahrungsbericht zum Umgang mit der Microservice-Architektur und der Implementierung einer dazugehörigen Benutzeroberfläche. Die Gestaltung einer grafischen Benutzeroberfläche (GUI) ist grundsätzlich eine Herausforderung, denn es müssen die Qualitätsfaktoren der Usability und User Experience (UX) berücksichtigt werden. Ohne eine:n entsprechend ausgebildete:n Expert:in im Team ist die Entwicklung einer qualitativ hochwertigen GUI nur sehr schwer umsetzbar.
Weitere Herausforderung im Bereich GUI liegen in den entsprechenden Technologien. In unserem aktuellen Projekt Handschriftenportal besteht die Aufgabe in der Entwicklung einer komplexen Oberfläche, welche über den Webbrowser bedienbar ist. In der Vergangenheit stellte diese Tatsache allein bereits eine große Herausforderung dar, da die HTML- und Javascript-Kompatibilität nicht in allen Browsern einheitlich gegeben war. Mittlerweile hat sich die Situation deutlich verbessert, da sich unter anderem die Anzahl der Browser mit hohem Marktanteil verringert hat. Andere Herausforderungen bleiben jedoch bestehen, dazu zählen:
- Barrierefreiheit (verpflichtend für Bundesbehörden),
- Responsive Design (für die Darstellung auf unterschiedlichen Endgeräten),
- Rasante Entwicklung komplexer UI Frameworks,
- Performance auch auf schwächeren Endgeräten und Netzwerken,
- Verwaltung des UI-Zustands im Browser.
Hat sich das Team für eine Microservice-Architektur entschieden, kommt allerdings noch eine weitere Herausforderung hinzu: Jeder Microservice sollte idealerweise, wenn es die fachliche Aufgabe erfordert, eine eigene GUI ausliefern. Nur so ist sichergestellt, dass sich eine fachlich bedingte Entwicklung ausschließlich auf einen einzigen Microservice auswirkt. Das entsprechende Team verantwortet damit alle zum Microservice gehörenden Komponenten – von der Datenspeicherung bis hin zur Benutzeroberfläche. Dies erleichtert die Wartung und Weiterentwicklung des Gesamtsystems. Dieses Architekturkonzept wird als Self-Contained Systems (SCS) bezeichnet. Folgt man diesem Ansatz, stellt sich die Frage, wie nun die einzelnen GUI Bestandteile der jeweiligen Microservices zu einer konsistenten Gesamtoberfläche zusammengesetzt werden können. Für diese Herausforderung haben sich im Laufe der Zeit unterschiedliche Lösungsmöglichkeiten etabliert:
- Integration durch HTTP Links
- iFrame Integration
- Microfrontend Frameworks
In den Projekten der letzten Jahre haben wir diese drei Lösungsmöglichkeiten evaluiert und teilweise auch produktiv im Einsatz. Wichtige Aspekte, in welchen sich die Ansätze stark unterscheiden, sind dabei folgende:
- Einheitlichkeit in Layout und Design,
- UI-Zustandsverwaltung,
- Routing zwischen den UI-Komponenten,
- Implementierung übergreifender UI-Elemente wie der Hauptnavigation.
HTTP-Link-Integration
Im Falle der HTTP-Link-Integration ist ein einheitliches Design lediglich durch eine gemeinsame Layout- und Designbibliothek zu gewährleisten. Dazu müssen sich alle Teams diese Bibliothek teilen und sie gemeinsam pflegen. Die Zustandsverwaltung kann in dem entsprechenden Microservice selbst behandelt und übergreifend über die Adresszeile des Browsers verteilt werden. Die Routing-Lösung ist in dem Verfahren der Linkauflösung selbst mit inbegriffen. Eine Lösung für eine übergreifende Navigation stellt hierbei sicherlich die größte Herausforderung dar: Entweder wird diese ebenfalls als Bibliothek zur Verfügung gestellt oder jeder Microservice muss selbst eine Navigation implementieren. Der Ansatz der HTTP-Link-Integration stellt damit aber eine technisch sehr etablierte und leicht umzusetzende Lösung dar. Folgt man dem Ansatz „Keep it simple and stupid“ (KISS) dann sollte dies der erste Ansatz sein, welcher im Team diskutiert und evaluiert wird.
iFrame-Integration
Die iFrame-Integration ist der HTTP-Link-Integration sehr ähnlich. Sie ist technisch sehr ausgereift und einfach umzusetzen. Im Bereich eines einheitlichen Layouts und Designs sowie bezüglich der Zustandsverwaltung steht das Team vor identischen Herausforderungen und Lösungsmöglichkeiten. Dafür ist die Darstellung übergreifender UI-Element mithilfe einer zentralen Startseite einfacher umzusetzen. Die Ursache dafür liegt in der Tatsache, dass kein Seitenwechsel zwischen den GUI-Bestandteilen durchgeführt werden muss.
Microfrontend-Integration
Eine Zusammenführung mehrerer GUI-Bestandteile zu einem konsistenten UI auf Basis des Microfrontend-Ansatzes ist die technisch anspruchsvollste Aufgabe. Zu Beginn muss sich das Team für ein Microfrontend-Framework entscheiden, beispielsweise:
- Zalando Mosaic,
- Single-SPA (Single Page Application),
- Bit,
- …
Neben der Auswahl eines Frameworks muss sich das Team entscheiden, ob die GUI-Bestandteile auf dem Server oder direkt im Browser zusammengesetzt werden. Hier besteht die Wahl zwischen einer ‚Single Page Application‘ (SPA) und dem ‚Server Side Rendering‘ (SSR). Mit einem SPA-Ansatz lässt sich der Zustand und die Zustandsveränderung sehr einfach direkt im Browser umsetzen. Ein populäres Framework ist React von Meta, ehemals Facebook. Bei der Auswahl eines UI-Frameworks sollten sich allerdings alle Teams abstimmen und wenn möglich jeweils dasselbe verwenden. So lässt sich die Gesamtintegration aller GUI-Elemente einfacher durchführen. Am Beispiel von React kann ein einheitliches Layout und Design durch den Einsatz von React Material UI erreicht werden. Eine Zustandsverwaltung im Browser kann durch die Bibliothek Redux erfolgen, zu welcher bereits eine sehr etablierte React-Integration existiert. Auch für Routing und das Umsetzen gemeinsamer Komponenten bietet React gute Möglichkeiten.
Unsere Alternative
Neben all diesen konzeptionell vollständig konsistenten Lösungen bieten sich aber auch viele Mischformen an. Im Handschriftenportal haben wir eine solche Mischform mit erstaunlich positiven Nebeneffekten eingesetzt: Im Projekt haben wir uns für einige Microservices bewusst gegen den Self-Contained-System-Ansatz entschieden. Der entsprechende Microservice stellt anstelle einer HTML-Oberfläche eine HTTP REST API zur Verfügung. Dies bietet die Möglichkeit, die Integration auf Basis der Datenschnittstelle und nicht auf Basis der Benutzeroberfläche durchzuführen. Die Integration kann auf Seiten des Servers stattfinden, welcher dann eine konsistente UI ausliefert.
Bedauerlicherweise gibt es derzeit wenig Möglichkeiten, komplexe Benutzeroberflächen mit aufwendiger Zustandsverwaltung mithilfe von Java umzusetzen. Java Server Faces (JSF) bieten zwar einige Möglichkeiten, komplexe UI-Komponenten auf Basis etablierter Frameworks wie Primefaces aufzubauen, allerdings müssen für die UI-Zustandsverwaltung noch immer klassische AJAX-Requests durchgeführt werden. Für standardisierte Elemente wie Datentabellen oder Formulare ist dies auch problemlos möglich. Für Komponenten wie einem individualisierten Texteditor stoßen Entwickler:innen jedoch sehr schnell an Grenzen.
Vor diesem Hintergrund haben wir uns für die Mischform einer SPA auf Basis von React und SSR auf Grundlage von Java Server Faces (JSF) entschieden. Dies bedeutet, dass die JSF-Standard-UI-Elemente klassisch auf dem Server und die komplexeren Elemente auf der Clientseite im Browser erstellt werden. Die Integration der komplexen SPA-Komponenten wurde auf Basis eines Maven-Plugins auf dem Continuous-Integration-Server durchgeführt. Die Kommunikation zwischen der SPA und dem SSR-Anteil wurde auf Basis von Custom Events aufgebaut. So konnten wir erreichen, dass durch eine Aktion, die innerhalb der SPA in den jeweiligen Browsern der Nutzer:innen ausgelöst wurde, die JSF-Seite einen AJAX-Aufruf triggert, welcher wiederum Zustände im Java-Backend verändert.
Auf dieser Basis konnten wir zwei sonst sehr gegensätzliche Technologien wie Java Server Faces und Javascript React nahtlos integrieren. Beide Technologien sind dabei auf einer HTML-Seite wiederzufinden und können ihre UI-Zustände ohne ein vollständiges Aktualisieren der Seite beeinflussen. Natürlich muss unser Team jetzt zwei Technologien (React und JSF) sehr gut beherrschen. Dieser Umstand bedeutet zwar einen einmaligen Einarbeitungsaufwand, fördert als Nebeneffekt aber die Entwicklung der Kompetenzen unseres Teams im Umgang mit komplexen Oberflächen. Aufgrund der Tatsache, dass sowohl Primefaces mit der Ultima-Erweiterung als auch React eine Material-Design-Layout-Integration anbieten, konnten wir eine konsistente Oberfläche entwickeln. Für die Nutzer:innen sind damit keine Brüche zwischen serverseitiger Darstellung und SPA-Komponenten erkennbar. Aspekte wie Routing, Suchmaschinenoptimierung oder Barrierefreiheit waren problemlos durch die serverseitige JSF-Integration umzusetzen. Auch der Aspekt der Performance wird durch diese Mischform stark begünstigt: Datenreiche Elemente können nun durch JSF auf dem Server erzeugt werden und sind nicht – wie bei einer reinen SPA – erst im Browser zu rendern.
Mein persönliches Fazit aus den komplexen Überlegungen bezüglich der Microservice-Architektur und UI: Eine Mischform von Technologien kann ein sehr attraktiver Ansatz mit durchaus positiven Nebeneffekten sein. Daher lohnt es sich, bei jeder Suche nach technischen Lösungen verschiedene Varianten auch augenscheinlich unvereinbarer Technologien auszuprobieren und deren Kompatibilität zu testen.
Ihr Kommentar
An Diskussion beteiligen?Hinterlassen Sie uns einen Kommentar!