Insbesondere in großen Frontend-Projekten treten mit zunehmender Komplexität diverse Probleme auf: Die Entwicklungsgeschwindigkeit sinkt und Merge-Konflikte sind an der Tagesordnung. Micro-Frontends können eine Lösung für diese und weitere Probleme sein. Im Folgenden erfährst du, was Micro-Frontends sind, welche Vorteile sie haben aber auch welche Herausforderungen beim Einsatz von Micro-Frontends zu meistern sind.
Wer wie ich bereits in zahlreichen großen Frontend-Projekten unterwegs war, dem fällt eines schnell auf: Je größer die Clients werden, die wir bauen, desto schwieriger wird es, diese zu entwickeln, zu erweitern und zu warten. Oft ist es in Frontend-Projekten so, dass man zu Beginn eine sehr starke Entwicklungsgeschwindigkeit vorweisen kann, die jedoch mit zunehmender Komplexität stark nachlässt. Woran liegt das?
Der Grund dafür ist meist, dass ein riesiger Frontend-Monolith auf einer Codebasis entwickelt wird, an der viele Webentwickler beteiligt sind. Mit einem Frontend-Monolithen ist es fast unmöglich, skalierbar zu bleiben. Denn umso größer er wird, desto komplexer werden auch die Abhängigkeiten (z. B. Komponenten-Bibliotheken) und Auswirkungen innerhalb der Applikation. Auch die isolierte Testbarkeit der Applikation leidet stark bei einem solchen Ansatz.
Ein weiterer, großer Nachteil eines Monolithen ist die erschwerte Entwicklung mit Continuous Delivery in einem großen Entwicklungsteam. Wenn man in einem Webprojekt z. B. mit mehr als zehn Webentwicklern an einem großen Monolithen arbeitet, dann ist man oftmals lange mit Merge-Konflikten und roten Builds beschäftigt. Umstrukturierungen des Codes oder andere Refaktorisierungsmaßnahmen innerhalb eines Sprints, sorgen schnell für massive Probleme.
Im Backend gibt es prinzipiell die gleiche Problematik. Dort löst man diese mit Hilfe sogenannter Micro Services, in denen einzelne Funktionalitäten einer Applikation in möglichst kleine Services aufgeteilt werden. Diese voneinander isolierten Services können dann unabhängig voneinander entwickelt, getestet und deployt werden.
Wie man diesen Ansatz auf die moderne Frontend-Entwicklung mit Micro Frontends überträgt und mit welchen Herausforderungen man dabei zu kämpfen hat, möchte ich dir im Rahmen dieses Blog Artikels kurz vorstellen.
Micro Frontends sind ein Ansatz, die Idee der Micro-Service-Architektur aus dem Backend-Bereich in die Welt des Frontends zu übertragen. Anstatt einen großen Frontend-Monolithen zu entwickeln bzw. zu deployen, wird die Applikation in kleine Micro-Frontends mit eigenem Verantwortungsbereich aufgeteilt. Die jeweiligen Frontends können dabei völlig autonom von unterschiedlichen Teams entwickelt, getestet und deployt werden. Jedes Team ist auf ihren jeweiligen Bereich spezialisiert (Frontend oder Backend) und stellt seinen eigenen Kontext zur Verfügung. In Abbildung 1 ist beispielsweise zu sehen, wie der Frontend-Monolith in fünf Micro Frontends aufgeteilt wurde.
Bei Micro-Frontends gibt es außerdem für gewöhnlich einen Composition Layer, der die Aufgabe hat, alle Frontends zu einer Gesamtapplikation zu komponieren. Der Aggregation Layer bildet dabei die Brücke zwischen den Frontend und den Backend-Services. Grundsätzlich dient er dazu, die Daten von mehreren Backend-Services zu aggregieren und zentral zur Verfügung zu stellen. Darüber hinaus kann er aber auch dazu dienen, Daten zu cachen oder kleinere Teile an Prozesslogik auszuführen, wobei letzteres vermieden werden sollte. Je nach Anwendungsfall kann es auch sinnvoll sein, spezielle Aggregation-Services für unterschiedliche Plattformen (mobile client, desktop client) anzubieten.
Aktuell werden Micro-Frontends noch stark mit unterschiedlichen Ansätzen bzw. Definitionen diskutiert und es gibt noch nicht den einen richtigen bzw. falschen Weg diese zu implementieren.
Im Gegensatz zu monolithischen Strukturen weisen Micro-Frontends eine Reihe von Vorteilen auf:
Doch auch bei Micro-Frontends gibt es nicht nur Vorteile, sondern einige große Herausforderungen, die es bei der Umsetzung zu meistern gilt. Beispielsweise muss man sich durch die klare Trennung der einzelnen Frontends überlegen, wie man zwischen den Frontends kommuniziert, navigiert oder einzelne Ressourcen teilt.
Auch das Frontend übergreifende State Management oder mögliche CSS-Konflikte sind Themen, mit denen man sich auseinandersetzen muss. Wie lädt man Komponenten asynchron nach? Wie kann man, trotz einer autonomen Entwicklung, eine einheitliche Usability bzw. UX gewährleisten?
Auf den letzten Punkt möchte ich an dieser Stelle noch näher eingehen und einige Varianten vorstellen, wie man mit dem Problem der User Experience umgehen kann.
Wer in einem Projekt auf eine Micro-Frontend-Architektur setzt, hat zwangsläufig das Problem, dass die einzelnen Frontends relativ schnell auseinanderlaufen und keine einheitliche User Experience bieten. Das ist zu einem gewissen Teil ihrer Natur geschuldet, da sie isoliert voneinander in autonomen Teams entwickelt werden.
Dennoch gilt es bei einer Micro Frontend Architektur damit umzugehen und die womöglichen Nachteile zu vermeiden. Es gibt vier unterschiedliche Ansätze, wie man mit dieser Problematik umgehen kann.
Bei diesem Ansatz wird ein übergeordnetes Design System entwickelt und zur Verfügung gestellt, das anschließend als Styleguide und somit als Vorlage für die einzelnen Teams dient. Die einzelnen Entwicklungsteams agieren autonom, haben aber die Vorgabe sich an den Styleguide zu halten. Typisches Beispiel für ein Design System ist Google Material.
Dies bedeutet den Aufbau einer teamübergreifenden Framework Component Library (z. B. mit Storybook). Alle Teams nutzen die Komponenten aus dieser Bibliothek, wodurch ein einheitliches Erscheinungsbild erreicht wird. Bei diesem Ansatz ist es sehr wichtig darauf zu achten, dass die Verwendung der Komponenten definiert ist und diese auch eingehalten wird. Typisches Beispiel für eine Shared Framework Component Library ist Material Design components for Angular.
Dieser Ansatz entspricht weitestgehend dem vorherigen Ansatz, mit dem einzigen Unterschied, dass hier Web Components zum Einsatz kommen. Das bringt den Vorteil, dass die Library unabhängig vom eingesetzten Framework ist. Nachteil ist, dass die Komponenten meist nicht so viele Funktionen beinhalten und an einigen Stellen noch mehr Anpassungen notwendig sind. Typisches Beispiel für eine Shared Web Component Library sind die Strand Web Components.
Bei diesem Ansatz setzt man auf die Entwicklung einer eigenen Component Library. Dieser Ansatz ist nur zu empfehlen, wenn man zum Einen die Anforderung hat, ein ganz besonderes bzw. eigenes Design umzusetzen (z. B. ein starkes Corporate Design vorliegt) und man bereits Erfahrungen im Bereich der Komponenten-Entwicklung im Haus hat. In allen anderen Fällen würde ich von dieser Variante abraten, da der Aufbau einer völlig neuen Bibliothek sehr komplex ist.
Die Micro-Service-Architektur lässt sich grundsätzlich auf das Frontend übertragen, es gibt allerdings einen entscheidenden Unterschied im Gegensatz zum Backend: Man kann die einzelnen Bestandteile eines Frontend zwar beliebig trennen, jedoch müssen sie am Ende des Tages wieder zusammen im Browser ankommen. Diese Tatsache macht es im Frontend an vielen Stellen wesentlich komplizierter, da Abhängigkeiten immer zusammen im Client ausgeliefert werden müssen.
Außerdem interagiert der Nutzer direkt mit den autonom entwickelten Frontends, was zwangsläufig dazu führen kann, dass er Inkonsistenzen bei der Bedienung feststellt. Dieser Punkt ist innerhalb einer Micro-Service-Architektur im Backend wesentlich einfacher zu handeln, da die entwickelten Services abstrahiert durch eine Schnittstelle zur Verfügung gestellt werden.
Wenn ich hier von Inkonsistenzen innerhalb der User Experience spreche, dann meine ich nicht nur, dass die entwickelten Oberflächen bzw. UI-Komponenten unterschiedlich aussehen, sondern das gleiche Funktionalitäten auch vom Verhalten (Application Flow) unterschiedlich umgesetzt wurden.
Die vier aus diesem Artikel vorgestellten Ansätze, um einer uneinheitlichen User Experience entgegen zu wirken, können nur als Hilfsmittel für diese Problematik dienen. Die Praxis zeigt, dass gerade wenn es auch um das Verhalten der Applikation geht, benötigt man im Projekt jemanden der stets ein Auge auf die User Experience und den Application Flow hat.
Über ein durchdachtes technisches Setup mit z. B. einer Shared Component Library, sollte man ein teamübergreifend, visuell einheitliches Bild erzielen. Damit auch der Application Flow über alle Micro-Frontends hinweg einheitlich wird, sollten auch die Verwendungsszenarien der einzelnen Komponenten und Design Patterns im Projekte geklärt werden. Auf diese Weise kann man die Vorteile von Micro-Frontends nutzen und die Nachteile auf ein Minimum reduzieren.