© Alexander Supertramp/Shutterstock.com
Synergie oder Widerspruch in sich?

Microfrontends im Monorepo


Microfrontends, die für gewöhnlich in einem jeweils eigenen Repository platziert werden, können gemeinsam in einem Monorepo ein Zuhause finden. Monorepos vereinfachen Aufgaben, die rund um Microfrontends anfallen, bergen jedoch ein paar bewusste Einschränkungen. Damit sie skalieren können, sind darauf ausgelegte Prozesse und Werkzeuge notwendig.

Das Hauptziel von Microfrontends ist Isolation: Einzelne kleine Anwendungen, die gemeinsam ein größeres System bilden, sollen unabhängig voneinander umgesetzt werden. Somit kann sich jeweils ein kleines Team um jede Anwendung kümmern. Da diese Teams autark sind, müssen sie sich nicht gegenseitig abstimmen und können möglichst rasch Geschäftsnutzen bieten. Deswegen ist es auch üblich, Microfrontends in einem jeweils eigenen Repository zu platzieren [1]. Das bringt zwar Isolation, aber auch einen Mehraufwand bei der Verwaltung und beim Teilen von Bibliotheken mit sich. Monorepos, die mehrere Microfrontends beherbergen, machen solche Aufgaben hingegen einfacher.

In diesem Artikel möchte ich die Konsequenzen beider Ansätze herausarbeiten. Als Beispiel [2] nutze ich eine Angular-Lösung, die auf Module Federation und einem Nx-Monorepo basiert.

Ein Repository pro Microfrontend

Der Einsatz mehrerer Repositorys sorgt für ein Maximum an Isolation. Die Repositorygrenzen verhindern Abhängigkeiten zwischen den einzelnen Microfrontends (Abb. 1).

steyer_monorepos_1.tif_fmt1.jpgAbb. 1: Verwaltung von Microfrontends in mehreren Repos

Da jedes Team sein eigenes Repository hat, können diese autark agieren: Jedes Team entscheidet selbst, welche Frameworks, Bibliotheken und Versionen zum Einsatz kommen. Auch der Zeitpunkt von Updates obliegt den Teams. Eine Abstimmung mit anderen Teams ist prinzipiell nicht nötig. Das bringt Agilität. Interne Bibliotheken, die die Teams untereinander teilen, werden versioniert und über eine npm Registry bereitgestellt. Um den Aufwand dafür gering zu halten, ist ein hoher Grad an Automatisierung nötig. Das bedeutet aber auch, dass das notwendige Wissen dazu im Team vorhanden sein muss.

Es kann vorkommen, dass mehrere Versionen ein und derselben internen Bibliothek gewartet werden müssen. Schließlich kann jedes Team entscheiden, wann und ob es ein Update durchführt. Ein Team, das beispielsweise beschlossen hat, bei Angular 10 zu bleiben, braucht auch Versionen der internen Bibliotheken, die für Angular 10 kompiliert wurden. Werden die einzelnen Microfrontends dem Benutzer als integrierte Lösung präsentiert, kann es auch notwendig werden, mehrere Versionen derselben Frameworks und Bibliotheken zu laden. Beispielsweise könnten so sowohl Angular 10 als auch Angular 11 im Browser landen. Das wirkt sich natürlich negativ auf die Ladezeiten aus. Hier wird ein Zielkonflikt zwischen Isolation und optimierten Ladezeiten deutlich: Entweder sind die einzelnen Anwendungs-Bundles voneinander isoliert und bringen ihre eigenen Abhängigkeiten oder die einzelnen Microfrontends greifen auf geteilte Abhängigkeiten zu. Im letzteren Fall müssen sich Teams auf die geteilten Versionen zu Lasten einer isolierten Vorgehensweise einigen.

Ein Monorepo für alle Microfrontends

Ein alternativer Organisationsansatz, der unter anderem bei Firmen wie Google, Facebook oder Microsoft zum Einsatz kommt, ist das Monorepo. Es handelt sich dabei um ein Repository, das mehrere zusammengehörige Projekte beherbergt (Abb. 2).

steyer_monorepos_2.tif_fmt1.jpgAbb. 2: Verwaltung von Microfrontends in einem Monorepo

Monorepos vereinfachen das Teilen von Quellcode. Anstatt eine neue Version über eine Registry zu veröffentlichen, werden die Änderungen einfach in einen entsprechenden Branch übernommen. Außerdem muss auch immer nur die aktuellste Version im Repository gewartet werden. Daneben sehen einige Monorepo-Implementierungen auch vor, dass jede Abhängigkeit nur in einer einzigen Version für alle Projekte vorliegt. Der oben erwähnte Fall, dass mehrere Angular-Versionen miteinander kollidieren, kann sich also erst gar nicht ergeben.

Prozesse und Werkzeuge für skalierbare Monorepos

Der Monorepo-Ansatz skaliert jedoch nur, wenn sowohl entsprechende Prozesse als auch Werkzeuge zum Einsatz kommen. Die Prozesse regeln zum Beispiel, wie mit Breaking Changes von Bibliotheken umzugehen ist. Denkbar ist das Etablieren einer Deprecation Policy, die eine gewisse Abwärtskompatibilität für einen bestimmten Zeitraum vorsieht oder das Veröffentlichen neuer Bibliotheksversionen in Release-Branches. Mit diesen können die Produktteams prüfen, ob die schlussendliche Umstellung auf die neue Bibliotheksversion funktionieren wird. Es liegt auf der Hand, dass diese Prozesse die Souveränität der einzelnen Teams einschränken. Auf der anderen Seite verhindern sie die Koexistenz verschiedener Bibliotheksversionen und stellen sicher, dass Versionskonflikte vermieden oder zumindest frühzeitig aufgelöst werden.

Neben...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang