Microfrontends in der Praxis
Microfrontends sind die logische Fortsetzung von Microservices. Warum werden sie verwendet, wie sieht eine typische Microfrontend-Anwendung aus, welche Standards gilt es einzuhalten und wie lassen sie sich implementieren. Antworten auf diese Fragen finden Sie in diesem Beitrag.
Warum Microfrontends?
Die fachgerechte Zerschneidung von Anwendungen ist eine der wichtigsten Aufgaben eines Software-Architekten. Spätestens seit der Veröffentlichung von M. Fowler und J. Lewis sind es Microservices1, die diese Aufgabe erfüllen. Ein Werkzeug hierfür stellte E. Evans schon 2003 – also schon vor 18 Jahren – mit dem Domain Driven Design2 zur Verfügung.
Das Zuschneiden von Anwendungen wurde immer auf die beteiligten Domänen und den abzubildenden „Bounded Context“ bezogen. Unter „Bounded Context“ wird die Beschränkung eines Domänenmodells verstanden, die von einem Team bearbeitet werden kann. Z.B. bilden im Sales-Bereich alle zu einem Kunden gehörenden Kontakte, Notizen und Angebote einen Bounded Context, während in der Buchführung unter dem Kunden die zugehörigen Rechnungen und eventuelle Mahnungen verstanden werden.
Microfrontends sind die logische Fortsetzung dieser Überlegungen hinsichtlich des Zuschneidens von Unternehmensanwendungen.
Um Unternehmensanwendungen zu strukturieren und damit besser beherrschbar zu machen, wurden in den 90er und in den frühen 2000er Anwendungen in die Bereiche Benutzerschnittstelle, Geschäftslogik und Persistenz (Datenbanken) unterteilt. Es entstanden entsprechende Teams, die domänenübergreifend den jeweiligen Bereich betreuten.
Schnell wurde klar, dass diese nicht domänen-spezifische Unterteilung zu Verzögerungen und vielfachen Synchronisationen zwischen den Teams führte. Immer wieder wurden von den verantwortlichen Datenbankteams, Änderungen in der Geschäftslogik nicht implementiert, da die Datenbankteams Prioritäten anders setzten als die Teams, die die Geschäftslogik implementierten.
Also versuchte man Geschäftslogik und Persistenz zusammen zu führen und in der jeweiligen Domäne zusammen zu führen. Um den notwendigen Datenaustausch trotzdem zu gewährleisten, wurden zu dieser Zeit der späteren 2000er Enterprise Service Bus (ESB)-Systeme eingeführt. Diese Entwicklung führte zu Microservice-Architekturen, in denen die Geschäftslogik zusammen mit der Persistenz in einen „Bounded Context“ (vgl. Eric Evans) implementiert wird. Allerdings mussten im Laufe der Entwicklung die schwergewichtigen ESBs durch Eventbusse abgelöst werden. Unter „Bounded Context“ oder auch begrenzter Kontext versteht man eine Funktion einer Domäne, die durch den Microservice vollständig implementiert werden kann. Implementierung dieser Kontexte oder Funktionen kann durch ein einziges Team erfolgen, um die Abhängigkeiten zu anderen Teams möglichst gering zu halten.
Allerdings blieb die Benutzerschnittstelle als Monolith über den Microservices „hängen“. Die Benutzerschnittstellen auch in die Microservice-Welt zu integrieren, führte zu mehreren Herausforderungen. Insbesondere die Unterschiedlichkeit der Implementierungen für den Benutzer sind in der Regel nicht akzeptabel. Daher hat sich das monolithische User Interface (UI) lange gehalten.
Eine solche monolithische Benutzerschnittstelle stellt aber die gleichen Herausforderungen an die Software wie ein gesamthafter Monolith:
- schwer zu verstehen,
- schwer zu warten,
- hoher Kommunikationsaufwand mit den Geschäftslogik-Teams.
Die logische Antwort auf diese Fragen sind Microfrontends. Microfrontends werden in den jeweiligen „Bounded Context“ Teams mitentwickelt (vgl. auch Two Pizza Rule ). Das heißt, jedes Funktionsteam entwickelt die Benutzerschnittstelle als Microfrontend seiner Funktion mit. Alle Funktionen aller Domänen werden über eine Integrationsschicht dem Benutzer verfügbar gemacht. Das entsprechende Vorgehen und die technischen Herausforderungen möchte ich gerne anhand eines Beispiels veranschaulichen.
Microfrontends – ein Beispiel aus der Praxis
Stellen wir uns ein Kundenportal einer großen Versicherung vor. Kund*innen können sich einloggen und ihre aktuellen Verträge einsehen. Stellen wir uns eine Kundin vor, die gerade umgezogen ist. Sie benötigt Verträge für ihr neu gebautes Haus, so sieht sie entsprechende Angebote und den Termin mit ihrem Vertreter, bei dem sie diese Angebote besprechen will. Auch hat sie auch aktuelle, noch nicht regulierte Schadensmeldungen aus ihrer Hausratversicherung und ihrer Krankenversicherung. Für die entsprechenden Schadensmeldungen kann sie auch den Status einsehen. Eine Skizze/ ein Scribble einer solchen Benutzerschnittstelle kann ungefähr so aussehen:
Abbildung 2: Beispiel für ein einfaches Kundenportal einer Versicherung
Die einzelnen Bereiche kommen aus unterschiedlichen Domänen und bedienen unterschiedliche Subdomänen, wie in Abbildung 2 dargestellt.
Abbildung 3: Domänen und Subdomänen einer beispielhaften Portalanwendung
Die blaue markierte Domäne ist die Bestandsverwaltung mit der Funktion Vertragsanzeige.
Die grün markierten Bereiche gehören zur Verkaufs-Domäne und implementieren die Funktionen Risikobewertung, Angebotsverwaltung und Terminvereinbarung.
Die orange-markierten Bereiche gehören der Domäne Schaden an und implementieren die Funktionen Schadensregulierung und Schadensaufnahme.
Zusätzlich zu den fachlichen Domänen werden auch unterstützende Domänen benötigt, die Informationen und ein Eingangsmanagement zur Verfügung stellen. Auch diese Bereiche werden von spezialisierten Teams implementiert.
Microservice-Architektur und Frontend-Architektur
Abbildung 4 zeigt eine typische Microfrontend-Anwendung. Über eine Portalanwendung (implementiert als App Shell4) werden die einzelnen Microfrontends integriert. Sie bietet die Funktionalität der Komposition für unabhängige Microfrontends.
Die einzelnen Microfrontends im Browser kommunizieren zum Server via BFFs. BFF steht hier für Backend for Frontend und bildet die Schnittstelle für spezifische Funktionen der jeweiligen Domäne5. Die BFFs wiederum kommunizieren via REST-Services mit den Implementierungen der Geschäftslogik. Die REST-Services sind als domänenspezifische APIs ausgeprägt und folgen dem OpenAPI Standard6.
Mit einem solchen Ansatz schafft man größtmögliche Unabhängigkeit der einzelnen Teams auch in der Frontend-Entwicklung. Allerdings müssen die einzelnen Microfrontends bestimmten Standards entsprechen:
- einheitliche Kommunikation,
- einheitliche Navigation,
- einheitliche Positionierung,
- einheitliches Sicherheitskonzept,
- einheitliches Designkonzept,
- automatisches Testen von funktionalen und nicht-funktionalen Anforderungen und
- gutes Wissensmanagement.
Auf die Aspekte Kommunikation, Sicherheit und Design gehe ich nachfolgend ein:
Einheitliche Kommunikation
Abbildung 5: Kommunikation zwischen Microfrontends
Abbildung 5 zeigt eine Möglichkeit eine einheitliche, standardisierte Kommunikation zwischen Microfrontends zu ermöglichen7.
Jedes Microfrontend stellt zwei Event-Schnittstellen „In“ und „Out“ zur Verfügung. Über diese Schnittstellen können Informationen ausgetauscht werden. So können z.B. Änderungen in einem Frontend Statusänderungen in einem anderen Frontend hervorrufen. Bspw. erzeugt die Chat-Komponente ein Event „Status im Schaden angefragt“ mit einer bestimmten Schadensnummer. Dieses Event wird im Ereignisspeicher über die standardisierte Schnittstelle „Out“ veröffentlicht und kann von anderen Microfrontends über die standardisierte Schnittstelle „In“ konsumiert werden. Im vorliegenden Beispiel wird das Ereignis „Status im Schaden angefragt“ von dem Microfrontend „Schadensregulierung“ konsumiert und der entsprechende Status dem Benutzer angezeigt. Nun könnte die Schadensregulierung wiederum ein Ereignis „Aktion von Kunden angefordert“ auslösen, das wiederum z.B. von dem Informations-Microfrontend konsumiert wird.
Über eine solche Vereinheitlichung der „In“ und „Out“ Schnittstellen, können unabhängig voneinander Microfrontends entwickelt werden, die miteinander kommunizieren können.
Sicherheit
Eine der größten Herausforderungen für Microfrontends ist die Herstellung der geforderten Sicherheit über Microfrontends hinweg. Hierzu müssen alle Microfrontends einen standardisierten Anmeldefluss implementieren. Ein solcher standardisierte Anmeldefluss ist der OAuth2/OpenIDConnect-Fluss. Der Autorisierungsfluss des OAuth2-Protokolls wird um den Authentifizierungsfluss des OpenIDConnect-Standards erweitert.8 In diesem Protokoll ruft der Benutzer „seine“ Anwendung – also z.B. das Portal auf. Das Portal leitet den Benutzer zu dem Identitätsanbieter (Identity Provider) weiter. Hier liegt noch keine gültige Anmeldung für den Benutzer vor und der Benutzer kann sich z.B. mit Benutzernamen und Passwort oder auch mit einem Zertifikat anmelden. Der Benutzer wird dann wieder automatisch an das Portal zurückverwiesen (redirect). Der Benutzer erhält einen Token, der als Eintrittskarte (Autorisierung) für Serverzugriffe benutzt werden kann.
Das Portal ruft nun nacheinander alle Microfrontends auf, die ihm zugewiesen sind. Jedes dieser Microfrontends ruft nun für sich den Identitätsanbieter auf, um seinen eigenen Sicherheitskontext herzustellen. Beim Aufruf stellt der Identitätsanbieter wiederum fest, dass eine gültige Session für den Benutzer vorliegt und dieser nicht wiederum seine Authentifikations-Eingaben machen muss (Single-Sign-On). Mit den dann vorliegenden Autorisierungen für die einzelnen im Portal vertretenden Funktionen, können die entsprechenden Microservices aufgerufen und die entsprechenden Daten angezeigt oder geändert werden.
Die hier vorgestellte Arbeitsweise impliziert, dass die einzelnen Microfrontends sich nicht kennen und sich nicht vertrauen. Eine solche Vorgehensweise wird empfohlen, um die Unabhängigkeit der Teams und der jeweiligen Entwicklung auch im Sicherheitskontext zu gewährleisten. Lösungen, die mit einem gemeinsamen Sicherheitskontext arbeiten (Shared Token), müssen immer gemeinsam in Produktion gebracht werden, wenn sich der Sicherheitskontext ändert. Zudem müssen sie sich auch gegenseitig vertrauen, was einem Null-Vertrauen-Prinzip9 widerspricht.
Einheitliches Designkonzept
Einheitliche Designkonzepte müssen übergreifend im Unternehmen für alle Teams zur Verfügung gestellt werden. Hierzu gehören sowohl grafische Vereinheitlichung als auch die Vereinheitlichung von ganzen Blöcken innerhalb der Benutzerschnittstelle. Ein solcher Block kann eine Adresseingabe oder auch eine vereinheitliche Tabellendarstellung mit Sortierfunktionen und Filtern sein.
Ein Beispiel für eine solche Vereinheitlichung von Blöcken ist das Aquila-Komponenten-System, das innerhalb der Allianz entwickelt wurde.10 Es stellt verschiedene Blöcke in einem Experten- und Standardmodus zur Verfügung. Gleichzeitig stellt es entsprechende Styling-Werkzeuge zur Verfügung, um das Aussehen der Elemente und das Verhalten von Benutzerschnittstellen zu vereinheitlichen.
Standardisierung
Viele dieser Aspekte sind unabhängig von der technischen Implementierung – wie z.B. die einheitliche Formensprache. Allerdings muss auf jeden Fall die Kommunikation via Events (Ereignisse) auf der Browserseite gut definiert werden, um die versprochene Teamunabhängigkeit zu ermöglichen. Ereignisse erlauben Microfrontends indirekt miteinander zu kommunizieren und so die Kopplung der einzelnen Bestandteile gering zu halten. Aber die damit zusammenhängende Schnittstellenverträge müssen eingehalten werden und unterliegen damit einer notwendigen Kontrolle. Auch das Aussehen der einzelnen Microfrontends muss kontrolliert und das standardkonforme Verhalten getestet werden.
Diese Standardisierungsanforderungen sollten nach Möglichkeit automatisch beim Deployment durch entsprechende von außen zur Verfügung gestellte Tests geprüft werden.
Technische Implementierung von Microfrontends mit Web Components
Web Components sind eine Sammlung von Webplattform-Schnittstellen, die es erlauben neue wiederverwendbare und unabhängige (gekapselte) HTML-Tags11 zu erzeugen, die in Webseiten und -anwendungen verwendet werden können. Sie basieren auf existierenden Web-Standards und kapseln sowohl das Aussehen als auch das Verhalten der enthaltenden Elemente. Besonders spannend hierbei ist, dass sie mit allen gängigen JavaScript-Bibliotheken oder Frameworks zusammenarbeiten können.12 Einzelne Teams müssen sich also nicht auf ein einheitliches Framework – sagen wir Angular oder React – einigen, sondern können ein Framework benutzen, dass ihre Aufgabe am besten erfüllt.
Das heißt, die einzelnen Teams können Übersichten und Detailansichten für das Portal zur Verfügung stellen, ohne von anderen Teams und ihren Releasezyklen abhängig zu sein. Dabei wird ein Microfrontend als ein HTML-Tag zur Verfügung gestellt, also z.B. <Vertragsanzeige>. Web Components basieren hierbei auf vier Hauptprinzipien:
- Kundenelemente erlauben die Definition von eigenen HTML-Elementen, die den bestehenden HTML-Standard um eigene Funktionen erweitern.
- Schattendokumente erlauben die Zusammenführung von multiplen HTML-Seiten. Normalerweise verfügt eine HTML-Seite über genau ein Dokument (DOM Element). Schattendokumente erlauben die Zusammenführung solcher Dokumente auf einer HTML-Seite, ohne die gegenseitige Isolation und Unabhängigkeit zu verlieren.
- JavaScript Module erlauben den Import von JavaScript-Bibliotheken und so eine verteilte Entwicklung von Funktionalitäten.
- HTML Schablonen erlauben die Definition von Teilen der Seite, die zum Zeitpunkt des Ladens noch nicht benötigt werden und später bei Gebrauch nachgeladen werden können. Hierdurch erhöht sich die Performance der Web-Anwendung maßgeblich.
Web Components sind nur eine Möglichkeit für die Implementierung von Microfrontends. Sie geben aber den Teams weitestgehend Unabhängigkeit in Bezug auf Framework, Releasezyklen und Technologiewahl. Daher wurde es hier explizit erläutert.
Weitere Arten sind neben dem Framework Web Components13 :
- Multiple URL based Single Page Applications (SPAs)
- Pure Web Components
- Selbst-enthaltene Microfrontends
- Fragmente
Alle diese unterschiedlichen Herangehensweisen verfügen über eigene Vor- und Nachteile. Diese müssen in Abhängigkeit der jeweiligen Anwendungen gesondert betrachtet werden. Im Sinne eines komplexen Portals, wie es im Artikel vorgestellt wurde, setzen sich heute Web Components durch.
Zusammenfassung
Microfrontends sind die logische Fortsetzung des Microservice-Gedankens. Wenn ein Team eine Geschäftsfunktion implementieren will, muss es auch die Benutzerschnittstelle dafür liefern. Allerdings müssen diese Funktionen bestimmten Standardisierungsanforderungen genügen, die sowohl das Verhalten als den Datenaustausch und die Sicherheit betreffen.
Für Microfrontends setzt sich derzeit das Web Components Framework durch, da es für Teams große Unabhängigkeit auf der einen Seite und auf der anderen Seite gute HTML- und JavaScript-Standardtreue vereinigt.
Hinweise:
Interessieren Sie sich für weitere Tipps aus der Praxis? Testen Sie unseren wöchentlichen Newsletter mit interessanten Beiträgen, Downloads, Empfehlungen und aktuellem Wissen.
[1] Lewis, J., Fowler, M.: Microservices, März 2014, https://martinfowler.com/articles/microservices.html, abgerufen 21.8.2021
[2] Evans, E.: Domain Driven Design, Addison Wesley, 2003
[3] N.N.: Two pizza team, AWS 2021, https://docs.aws.amazon.com/whitepapers/latest/introduction-devops-aws/communication-collaboration.html, abgerufen 21.8.2021
[4] Osmani, A.: The App Shell Model, Web Fundamentals 14.5.2019, https://web.dev/learn/pwa/architecture?hl=de, abgerufen 21.8.2021
[5] N.N.: Backend for Frontend Pattern, Microsoft Docs 23.06.2017, https://learn.microsoft.com/en-us/azure/architecture/patterns/backends-for-frontends, abgerufen 21.8.2021
[6] N.N.: OpenAPI Standard Version 3.0.3, https://swagger.io/specification/, abgerufen 21.8.2021
[7] Penev, S.: Microfrontends and BoxR Frontend, Internal presentation Allianz, 6.8.2021
[8] N.N.: Microsoft Documentation, https://learn.microsoft.com/de-de/entra/identity-platform/v2-protocols-oidc, abgerufen 21.8.2021
[9] Luber, S., Schmitz, P.: Was ist ein Zero-Trust-Modell, Security Insider 4.10.2018, https://www.security-insider.de/was-ist-ein-zero-trust-modell-a-aee40a92525d3d81600abc90cdcdf91e/, abgerufen 21.8.2021
[10] N.N.: Aquila Components Documentation, https://aposin.github.io/ng-aquila/documentation, abgerufen 21.8.2021
[11] N.N.: HTML <html> Tag, W3C Schools, https://www.w3schools.com/tags/tag_html.asp, abgerufen 21.08.2021
[12] Vgl. What are web components?, https://www.webcomponents.org/introduction, abgerufen 21.08.2021
[13] Nolte, K.: 6 Micro-Frontend-Arten im Direkt-Vergleich: Das sind die Vor-und Nachteile, itemis 7.12.2018, https://blogs.itemis.com/6-micro-frontend-arten-im-direkt-vergleich, abgerufen 21.8.2021
Dr. Annegret Junker hat im t2informatik Blog weitere Beiträge veröffentlicht, u.a.:
Dr. Annegret Junker
Dr. Annegret Junker arbeitet als Chief Software Architect bei der codecentric AG. Seit über 30 Jahren ist sie in der Software-Industrie in verschiedensten Rollen und unterschiedlichen Domänen wie Automotive, Versicherungen und Finanzdienstleistungen tätig. Besonders interessiert sie sich für DDD, Microservices und alles, was damit zusammenhängt.