Eines Tages, vor nicht allzu langer Zeit, hörte ich immer wieder Witze über „Micro Frontends“ – so ähnlich, wie ich zuerst von Toast erfahren habe. Ich verstand die Quelle erst nicht, bis ich nachfragte und dabei diesen Artikel von Cam Jackson entdeckte.
In diesem Artikel werden wir einen aktuellen Trend beschreiben, Frontend-Monolithen in viele kleinere, besser zu handhabende Teile zu zerlegen, und wie diese Architektur die Effektivität und Effizienz von Teams, die an Frontend-Code arbeiten, steigern kann.
Ich würde argumentieren, dass es „Frontend-Monolithen“ und „Frontend-Code“ heißen sollte, aber ich schweife schon ab.
Die Idee ist ähnlich wie bei Microservices, aber für das Frontend. Anstatt einer einzigen großen Frontend-Architektur (z. B. einer React-App) werden verschiedene Teile des Frontends völlig unabhängig voneinander entwickelt, haben keine Abhängigkeiten voneinander und können unabhängig bearbeitet und bereitgestellt werden.
Es ist eines dieser Dinge, bei denen man nicht genau sagen kann, ob es sich wirklich um eine interessante Vorahnung der Zukunft handelt, nur um eine Nischenarchitektur-Wahl, die für eine Handvoll großer Organisationen funktionierte, oder sogar nur um eine theoretische Option.
Zuerst denke ich an Konsistenz und DRY-ness. Wo immer ich gearbeitet habe, waren diese Dinge wichtig, und es scheint, dass die Branche insgesamt endlose Frontend-Probleme damit hatte, Designs zu liefern, die konsistent und kohärent bleiben, ohne sich mit Bergen von technischer Schuld zu wiederholen. Unabhängige Frontends scheinen ein Problem zu sein, wenn Team B von Team A blockiert wird, weil etwas nicht direkt damit zusammenhängt, aber dann entsteht das Problem, dass die Ergebnisse von Team B von der Konsistenz mit den Ergebnissen von Team A abweichen.
Der Artikel selbst spricht von einer Browse/Search-Landingpage, einer Detail-/Bestellseite und einer Profilseite, wobei alle drei von verschiedenen unabhängigen Produkten/Teams bearbeitet werden. Das klingt für mich irgendwie cool und interessant, und es klingt auch, als ob diese Teams bei der Arbeit besser nebeneinander sitzen sollten; sonst geht die App in zwei Wochen in Richtung Frankensteins Monster. Das Styling wird nur leicht mit einer „Ich weiß nicht, mach einfach einen guten Job“-Mentalität behandelt. Teams haben damit Probleme, wenn sie alle am selben Produkt arbeiten, daher hätte ich hier erhebliche Bedenken. Das Erste, was ich versuchen würde zu lösen, wenn dies ernsthaft diskutiert wird, wäre ein Designsystem, das alles überspannt und das jeder ohne Ausnahme nutzt.
Und was, wenn diese Micro Frontends auf derselben Seite koexistieren? Benutze <iframe>, sagt der Artikel. Ich kann mir keine Welt vorstellen, in der das zu einer guten Benutzererfahrung führt. (iFrames sind langsam, besonders wenn viele von ihnen ihre eigenen Welten starten – und was ist mit Elementen, die Grenzen überschreiten könnten, wie Tooltips und Menüs?)
Die anderen Integrationsoptionen… sie in eigene Bundles oder sogar native Webkomponenten zu isolieren, klingt etwas besser. Aber immer noch, die Idee der siloartigen Entwicklung, bei der eine React-Komponente auf derselben Seite wie eine Vue-Komponente platziert wird, scheint eine enorme Benutzerstrafe für ein ziemlich spezifisches organisatorisches Problem zu sein. Ganz zu schweigen davon, dass Sie die Vorteile eines gemeinsamen Verständnisses einer Codebasis und die Vorteile eines tieferen technischen Verständnisses einer kleineren Auswahl an Werkzeugen verlieren.
Ich charakterisiere das wahrscheinlich nicht fair, besonders weil die Idee für mich ziemlich neu ist und ich noch nie so gearbeitet habe.
Nader Dabit hat einen Folgeartikel: Building Micro Frontends with React, Vue, and Single-spa. Nur damit ich das nicht falsch darstelle: Die Idee ist wirklich, dass du vielleicht eine React-App baust und ich baue eine Vue-App und wir hauen sie auf dieselbe Seite. Ich komme definitiv aus einer Ära, in der wir lachten-dann-zuckten, als wir Seiten fanden, die mehrere Versionen von jQuery auf derselben Seite verwendeten, plus etwas, das MooTools und Prototype scheinbar versehentlich lud. Wir zuckten, weil das ein Eimer voller JavaScript war, meist unnötigerweise dupliziert, was Fehler verursachte und die Seite verlangsamte. Das scheint nicht viel anders zu sein.
Joel Denning weist in einem AMA zum Thema darauf hin
Ich weise darauf hin, dass wir uns in der Phase des „Hassens, ohne genau zu prüfen“ dieser Idee befinden. Es ist durchaus möglich, dass die Idee nach einer legitimen, genauen Prüfung immer noch scheitert. Aber es ist noch zu früh, um das zu sagen.
Einverstanden.
Entschuldigung für das Anhäufen. 😣
— Chris Coyier (@chriscoyier) 20. Juni 2019
Es sind… Komponenten. Sie haben… Komponenten erfunden.
Das schien mir zunächst auch eine radikale Idee zu sein, aber ehrlich gesagt ergibt sie viel Sinn. Ich würde jedoch nicht so weit gehen, wie manche es vorschlagen. Einer der Vorteile von Microservices ist, dass man wirklich getrennte und unabhängige Teams haben kann, die an verschiedenen Diensten arbeiten, wobei jedes Team die für es am besten geeigneten Sprachen und/oder Frameworks verwendet. Das Endergebnis ist normalerweise nur eine JSON-Antwort, sodass die zugrunde liegende Architektur wenig Bedeutung hat.
Dasselbe gilt nicht unbedingt für Micro Frontends. Man könnte zwar React in einem Frontend und Vue in einem anderen verwenden, aber das belastet den Benutzer: Er muss all diese verschiedenen Bibliotheken herunterladen, während er die gesamte Website durchläuft. Aus diesem Grund glaube ich nicht, dass hier die gleiche Flexibilität wie bei Microservices besteht. Alle Frontends sollten sich an ein gemeinsames Client-Side-Framework halten.
Abgesehen davon gibt es jedoch immer noch viel potenziellen Wert. ASP.NET Core hat zum Beispiel Razor Class Libraries, mit denen gemeinsame Interface-Elemente wie Header, Footer oder verschiedene andere Komponenten geteilt werden können. Andere Frameworks haben möglicherweise ähnliche Funktionalitäten. Dies in Kombination mit CDNs, sowohl öffentlichen als auch privaten, kann jedem Frontend sofort eine gemeinsame Basis bieten, sodass sich das eigentliche Frontend nur auf das konzentrieren muss, was es speziell bereitstellen muss.
Das Problem mit einem monolithischen Frontend ist dasselbe wie bei einem monolithischen Backend: Eine Änderung in einem Bereich erfordert die Bereitstellung des gesamten Systems. Ich sehe einen echten, greifbaren Vorteil darin, diskrete Frontend-Einheiten zu haben, die unabhängig voneinander bereitgestellt und geändert werden können, vorausgesetzt, sie arbeiten alle von einer gemeinsamen Basis aus, um Konsistenz zu gewährleisten.
Ein gutes Beispiel hierfür in der Praxis könnten CAPTCHA oder verschiedene „Als [Name] anmelden“-Funktionen sein. Sie sind im Grunde ein Endpunkt mit einem importierbaren Widget, das sich damit verbindet.
Um dies in einer großen Anwendung zu ermöglichen, denke ich, dass Teams auch Seiten besitzen müssten, zusätzlich zu reinen Funktionen.
Am Beispiel der Registrierung
Team A könnte einen Endpunkt, UI-Komponenten und eine dedizierte Seite für die Registrierung entwickeln, mit dem Verständnis, dass bestimmte Richtlinien eingehalten werden müssen, z. B. wie die Komponenten den Bildschirmplatz in einem Modal nutzen, auch wenn sie ihn nicht so verwenden.
Team B, das die Startseite besitzt, könnte dann den Endpunkt und die UI-Komponenten von Team A VERWENDEN, um ein Registrierungsmodal auf der Startseite zu implementieren.
Ich weiß nicht, ob das in der Realität funktionieren würde; ein Designer ohne gründliches Verständnis dafür, wie Modularität in der Praxis funktioniert, oder ein Entwickler, der brüchiges CSS schreibt, könnte vielen Teams Probleme bereiten.
Ein Micro Frontend sollte nur das verwenden, was es braucht, nicht ein monolithisches Frontend-Tool wie React, Vue, jQuery. Diese Ungetüme sollten in verknüpfbare Teile zerlegt werden, um nützlich zu sein: Anstatt das ganze Ungetüm zu laden, nur die Teile verknüpfen, die verwendet werden. Das Problem hier ist, dass es bei einer dynamischen interpretierten Sprache schwierig ist zu wissen, welche Teile verwendet werden, und so wächst das Ungetüm immer weiter, ist monolithisch und muss komplett geladen werden, um irgendetwas davon zu nutzen.
Wenn nur die benötigten Teile geladen würden, dann wären iframes nicht langsam. Iframes, die ganze Monolithen laden, immer und immer wieder (jeweils für jeden iframe), sind immer langsam, und Caching hilft wenig, wenn jeder einen anderen Monolithen verwendet.
Das andere Problem ist natürlich, dass sie über das Internet geladen werden müssen (zumindest beim ersten Mal), und separate Anfragen für viele kleine Teile sind langsamer als das Laden des gesamten Monolithen auf einmal. Frontends brauchen also wirklich einen Linker-Schritt, bei dem man die winzigen Teile, die man braucht, in die Quelle der Seite einfügen kann: Anstatt ganze Monolithen zu referenzieren, verknüpft man die benötigten Teile in den Quelltext der Seite und erstellt seinen eigenen Mikrolithen für jeden iframe…
Das Endergebnis ist jedoch, dass die Summe der Mikrolithen für eine ganze Reihe von Seiten, die eine Website bilden, größer sein kann als die Größe des Monolithen. Es gibt also einen Kompromiss zwischen Seitengeschwindigkeit und Ressourcenverbrauch sowie Webseiten-Geschwindigkeit und Ressourcenverbrauch.
Persönlich nutze ich keine der Monolithen wegen der Ladezeiten, ich programmiere einfach in reinem JavaScript und die Verwendung von Frames, wo dies zur Trennung von Belangen angemessen ist, war kein Performance-Problem.
Das erinnert irgendwie an die Reaktionen, die die Leute in den frühen Tagen von CSS-in-JS hatten.
Ich glaube wirklich, dass dies einfach eine Idee ist. Ob sie das Stadium erreicht, das Microservices erreicht haben, wird man sehen. Ich persönlich sehe nicht, wie die Verwendung mehrerer Frameworks in einer einzigen Anwendung vorteilhaft sein könnte, ohne andere Tools zu entwickeln, um sie im Browser wirklich zu isolieren und unerwartete UI-Fehler in einer realen Anwendung zu vermeiden. Ist der Wert dieses Ansatzes wirklich größer als die Verwendung von etwas Traditionellerem wie unseren aktuellen Designsystemen und/oder Storybook-gesteuerter Entwicklung? Ich bin mir nicht sicher, aber ich glaube, dass es dafür einen Platz geben könnte, für ein System wie dieses. Vielleicht ist es nicht die Art und Weise, wie das Konzept gedacht war. Aber irgendwie erscheint mir die Idee, dass mehrere Teams an unterschiedlichen UIs und Codebasen arbeiten, ein wenig magisch, diese Idee liebe ich. Ich glaube jedoch, dass dies bereits möglich ist, mit ein wenig GIT-Management und durchdachter Entwicklungszyklen können wir die Vorteile von „Micro Frontends“ erzielen, die sich alle bei der Bereitstellung zusammenfügen. Rechtfertigt es eine vollständige architektonische Änderung, Umstrukturierung und/oder Teamdynamiken? Ich bin mir nicht sicher. Aber ich denke, wir werden es erst wissen, wenn wir genug begründet haben, um es in die Praxis umzusetzen. Wer weiß.
Wir sind vor einigen Jahren zu diesem Ansatz für ein großes Projekt übergegangen, es funktionierte großartig mit etwa 5 UI-Teams, die etwa 20 Unter-Apps/Seiten betreuten. Es funktioniert gut, wenn man überwechseln oder alternative/neue Frameworks verwenden möchte, da die Einführung schrittweise erfolgen kann, mit minimalen Auswirkungen auf die aktuelle Implementierung. Die Versionsverwaltung über die gesamte Codebasis war entscheidend, obwohl es schwierig war, die Konsistenz in bestimmten Bereichen (z. B. Styling, Komponenten) aufrechtzuerhalten, aber dafür gibt es passendere Lösungen.
Es ist nicht perfekt oder für alle Fälle geeignet, aber es hat viele Vorteile.
Ich habe in einem Kurs etwas über Microservices gelernt und bin wirklich begeistert davon. Aber Frontend-Microservices ist eine völlig andere Idee und hat mich umgehauen. Ich werde nach weiteren Details suchen, danke…
Mein größtes Anliegen bei all den Gesprächen ist, praktikable Lösungen für den Umfang und den Kontext des Problems zu bieten. Was ich hasse, ist die abfällige Art mancher Kritiken; Die Art von „Was soll das schnaub, nimm einfach Iframes!“ oder „Das sind dann also Webkomponenten?“ Oder jede Art von „Tsk, tsk, jeder gute Entwickler weiß…“.
Nehmen wir an, wir haben eine große Anwendung mit vielen Funktionen. Die „Eltern“-App wird von einem Team besessen und die „Kind“-Funktionen werden alle von verschiedenen Teams besessen. Es gibt über 30 Funktionen, die von 15 Teams besessen werden. Nicht nur das, sondern diese über 30 Funktionen können auch in anderen „Eltern“-Apps wiederverwendet werden. Heute geht die Richtung dahin, „die Funktionen zu einem NPM-Paket zu machen“, und dann konsumieren die Eltern-Apps diese Abhängigkeiten, kompilieren sie und optimieren sie auf verschiedene Weise, um eine „monolithische“ App zu produzieren (… unter Verwendung dieses Begriffs, obwohl es Chunking- und Splitting-Optionen gibt).
Das Problem ist, dass die Teams der Eltern-Apps nun Gatekeeper für all die anderen Kind-Funktions-Teams sind. Nichts kann zu einem Benutzer gelangen, ohne dass ein Team aktiv und direkt die Arbeit eines anderen Teams konsumiert. Das andere Problem sind Versionskonflikte. Es kann dazu führen, dass alle 15 Teams alle ihre Produkte aktualisieren müssen, um eine Paketaktualisierung zu implementieren, die eigentlich nur von 1 Kind-Funktion benötigt wurde.
Da haben wir also Teams, die sich dadurch eingeschränkt fühlen, dass sie ihr Produkt nicht zeitnah herausbringen können, und andere Teams, die sich überfordert fühlen für etwas, das nicht ihr Problem ist. Man kann das als kulturelles Problem bezeichnen, was ich Leute sagen höre: „Das versucht, Projektmanagement- und Teamkollaborationsprobleme zu lösen, vielleicht sollten wir uns auf die Kultur statt auf technische Lösungen konzentrieren“
Das Problem ist, dass wir Entwickler nicht als Benutzer betrachten. Sie sind Menschen, die die gleichen Dinge wollen wie die Benutzer ihrer Produkte; einfache Bedienung, ihre Aufgabe schnell erledigen, die Kontrolle fühlen, minimaler Aufwand für maximales Ergebnis.
Ob es Microfrontends oder eine andere Lösung sind, ich möchte, dass wir Entwickler wie Benutzer behandeln. Ich glaube, dass die User Experience von Entwicklern auch wichtig ist. Wenn es Lösungen außerhalb von Microfrontends gibt, um dies anzugehen, dann lasst uns konkrete Beispiele nennen, nicht nur Rhetorik und Anekdoten. Lasst uns diese Beispiele auf Lücken und Benutzerfreundlichkeitsprobleme analysieren. Dann lasst uns nutzbarere Lösungen produzieren. Meine Befürchtung ist, dass zu viele Leute das Feld beobachten, nicht das genaue Problem haben, das andere Teams haben, und es als „kein echtes Problem“ abtun.
Es ist ein sehr reales Problem. Microfrontends könnten eine Lösung sein.
Ich arbeite in einer Organisation, die ein CMS entwickelt, die Benutzeroberfläche ist komplex, die Codebasis ist groß. Wie alle großen Apps hat sie Legacy-Frameworks, es ist eine Mischung aus Wicket, ExtJS, Angular.js und jetzt Angular, und jetzt sollen wir sie mit React-Apps kombinieren, die von Teams eines Unternehmens geschrieben wurden, das uns übernommen hat. Es ist zu groß, um alles in einem Framework zu konsolidieren, es würde Jahre dauern (kombiniert mit der Entwicklung neuer Features, sonst sterben wir), bis dahin wird ein neues Framework aufgetaucht sein, das besser ist. Mein Punkt ist, dass es in großen Unternehmensanwendungen wie diesen immer technische Schulden, mehrere nebeneinander existierende Frameworks und keine Zeit zur Konsolidierung geben wird. Die Verwendung dieses Micro-Frontend-Ansatzes, bei dem diese Teile aufgeteilt werden (in unserem Fall mit iframes) und über eine gut definierte API-Schicht kommunizieren können, ermöglicht eine bessere Trennung und Refactoring später.
Aber das ist für große Apps, wer würde das für eine einzelne Webseite tun?
Schaut mal
https://single-spa.surge.sh/