Zum Inhalt springen

Wie kommunizieren Remotes miteinander? Gar nicht.

Remotes kommunizieren nicht miteinander. Sie kommunizieren mit den Quellen, die ihre jeweilige fachliche Projektion verantworten.

Das bedeutet nicht, dass zwischen zwei Remotes niemals irgendein technisches Signal auftreten darf. Es bedeutet, dass ein Remote keine Actions, Zustandsübergänge oder fachlichen Browser-Events aus einem fremden Verantwortungsbereich abonnieren sollte. Auch ein technisch globaler Action Stream ist kein fachlicher Event Bus.

Diese Einschränkung ist keine willkürliche Architekturregel. Sie folgt aus der fachlichen Kapselung, die Microfrontends überhaupt erst rechtfertigt. Remotes können nebeneinander im selben Browserfenster erscheinen. Dadurch werden sie aber nicht zu benachbarten Komponenten innerhalb eines gemeinsamen Zustandsmodells.

Visuelle Nähe ist keine Kommunikationsbeziehung.

Bei klassischen Komponenten ist die Frage nach der Kommunikation naheliegend. Eine übergeordnete Komponente übergibt Zustand. Eine untergeordnete Komponente emittiert ein Ereignis. Zwei benachbarte Bereiche koordinieren sich über einen gemeinsamen Store.

Dieses Denkmodell wird häufig unverändert auf Microfrontends übertragen:

Remote A
└── übergibt Zustand oder Event
Remote B

Damit werden Remotes wie besonders große Komponenten derselben Anwendung behandelt. Für fachlichen Zustand ist das die falsche Ausgangslage.

Das passendere Modell lautet:

Remote A ──▶ verantwortliche Datenquelle
Remote B ──▶ eigene verantwortliche Datenquelle

Beide Remotes können auf dieselbe serverseitige Wahrheit zugreifen. Sie können auch unterschiedliche Projektionen derselben fachlichen Daten verwenden. Sie synchronisieren ihre lokalen Zustände jedoch nicht horizontal miteinander.

Remotes liegen nicht deshalb getrennt vor, damit ihre internen Zustandsmodelle anschließend über den Browser wieder miteinander verbunden werden. Wer genau das tut, trennt zwar Bundles, Deployment-Artefakte oder Repository-Bereiche, stellt die fachliche Kopplung aber unmittelbar danach wieder her.

Ein Microfrontend ist keine Komponente einer magisch gemeinsam reagierenden Anwendung. Es ist eine eigenständig lauffähige Anwendung, die in einen Host integriert wird.

Das Denkmodell einer solchen Anwendung umfasst mehr als ein separat gebautes JavaScript-Bundle. Ein Remote sollte seinen eigenen Lebenszyklus besitzen, allein gestartet und getestet werden können und seinen fachlichen Zustand selbst verantworten. Es kann zu einem anderen Zeitpunkt geladen werden als andere Remotes. Es kann unabhängig aktualisiert oder zurückgerollt werden. Möglicherweise erscheint es in mehreren Hosts, wird unter einer anderen Origin ausgeliefert oder verwendet eine andere Framework-Version.

Nicht jede dieser Möglichkeiten muss in jedem System vollständig ausgeschöpft werden. Sie beschreiben jedoch die Grenze, an der sich die Architektur orientieren sollte.

Eine eigenständige Anwendung wird nicht automatisch aktuell, nur weil eine andere Anwendung im selben Browserfenster einen Zustand geändert hat. Nach einem Reload kennt sie auch nicht die Historie der zuvor ausgeführten Actions. Wird sie erst später geladen, hat sie frühere Browser-Events nicht empfangen. Läuft sie in einem anderen Host oder Tab, existiert möglicherweise nicht einmal derselbe JavaScript-Kontext.

Das ist kein technisches Versäumnis, das durch einen besonders cleveren Event-Bus behoben werden müsste. Es ist eine Konsequenz tatsächlicher Eigenständigkeit.

Remotes kommunizieren nicht deshalb nicht direkt, weil der Browser es verbietet. Sie sollten es fachlich nicht benötigen.

Die offensichtlichste Form horizontaler Kopplung ist ein direkter Import:

Kalender-Remote
importiert API oder Zustand aus dem Profil-Remote

Vielleicht exportiert das Profil-Remote einen Service, einen Store oder eine Funktion zum Lesen aktueller Profildaten. Das Kalender-Remote verwendet diese Schnittstelle, weil beide Anwendungen ohnehin gemeinsam im Browser laufen.

Damit wird das Profil-Remote zu einer Laufzeitabhängigkeit des Kalender-Remotes. Dessen Funktionsfähigkeit hängt nun von der Verfügbarkeit, Aktivierung und kompatiblen Version des anderen Remotes ab. Lokale Entwicklung und isolierte Tests benötigen plötzlich einen zusätzlichen Container. Ein Rollback kann Erwartungen brechen. Unterschiedliche Ladezeitpunkte werden relevant. Interna des Profil-Remotes entwickeln sich faktisch zu einer öffentlichen API, obwohl sie ursprünglich nie als stabiler Vertrag gedacht waren.

Auch die Ownership wird unklar. Darf das Profil-Team eine exportierte Funktion verändern? Muss es alle konsumierenden Remotes kennen? Wer koordiniert Releases, wenn ein neues Datenmodell gleichzeitig auf mehreren Seiten aktiviert werden muss?

Ein Remote ist keine Laufzeitbibliothek für andere Remotes.

Das schließt nicht aus, dass gemeinsam verantwortete technische Bibliotheken existieren. Ein stabiler, bewusst veröffentlichter Vertrag ist jedoch etwas anderes als der Zugriff auf Zustand oder Anwendungsservices eines laufenden Remotes. Die Frage nach wiederverwendbaren Komponenten und Shared Libraries verdient eine eigene Betrachtung. Sie löst das Problem fachlicher Zustandssynchronisation nicht.

Weniger offensichtlich ist die Kopplung über einen gemeinsamen Dispatcher.

Ein Benutzer aktualisiert seinen Namen im Profil-Remote. Nach erfolgreichem Speichern wird eine Action ausgelöst:

Profil-Remote
└── dispatch: profileSaved
Kalender-Remote
└── reagiert auf profileSaved

Auf den ersten Blick wirkt das sauber. Das Kalender-Remote importiert keinen Profilservice und kennt vielleicht nicht einmal dessen Komponenten. Es lauscht lediglich auf eine Action und aktualisiert anschließend den angezeigten Namen.

Tatsächlich kennt es nun die interne Sprache des Profil-Remotes. Es kennt dessen Action-Namen, Payload und Zustandsübergänge. Es setzt voraus, dass eine bestimmte technische Aktion genau zu dem Zeitpunkt ausgelöst wird, an dem die fachliche Änderung als abgeschlossen gelten darf. Es macht Annahmen über Reihenfolge, Zustellung und Lebenszyklus.

War das Kalender-Remote beim Dispatch noch nicht geladen, verpasst es die Action. Nach einem Reload wird sie nicht erneut zugestellt. Ein zweiter Browser-Tab erhält sie nicht automatisch. Eine ältere Remote-Version kann die Payload anders interpretieren. Eine Umbenennung oder Aufteilung der Action wird zu einer breaking Change. Nach einem Rollback können Produzent und Konsument unterschiedliche Erwartungen besitzen.

Vor allem verwechselt das konsumierende Remote einen internen Prozessschritt mit fachlicher Wahrheit. profileSaved beschreibt zunächst, was das Profil-Remote getan hat. Daraus folgt nicht automatisch, welche Daten für das Kalender-Remote gültig sind, welche Projektion es benötigt oder ob weitere serverseitige Verarbeitung bereits abgeschlossen ist.

Actions gehören zum internen Zustands- und Prozessmodell des verantwortlichen Remotes. Auch wenn technisch ein gemeinsamer Dispatcher vorhanden ist, sind Actions anderer Fachbereiche keine öffentliche Integrationsschnittstelle.

Ein globaler Action Stream ist kein fachlicher Event Bus.

Statt Store-Actions können neutral klingende Browser-Events verwendet werden:

profileUpdated
appointmentChanged
patientSelected
invoiceCancelled

Ein globaler Event-Bus wirkt zunächst entkoppelt. Produzenten und Konsumenten kennen einander nicht direkt. In einem Proof of Concept genügt oft eine kleine JavaScript-Abstraktion, um Änderungen sofort auf dem Bildschirm sichtbar zu machen.

Mit zunehmender Lebensdauer des Systems entstehen jedoch dieselben Fragen wie bei jeder verteilten Kommunikation: Was geschieht mit verspäteten Subscribern? Müssen Events wiederholt werden? Welche Reihenfolge gilt? Werden sie bestätigt oder dedupliziert? Was passiert nach einem Reload oder in einem zweiten Tab? Enthält das Event nur eine ID oder bereits den vollständigen Zustand? Wer besitzt sein Schema und seine Versionierung? Ist es lediglich eine Benachrichtigung oder bereits die fachliche Wahrheit?

Solange ein Ereignis nur eine flüchtige Optimierung darstellt, können einzelne dieser Fragen irrelevant sein. Sobald jedoch dauerhafte, zuverlässige, geordnete oder wiederholbare Zustellung benötigt wird, beginnt das Frontend, ein verteiltes Eventsystem nachzubauen.

Spätestens wenn Browser-Events gespeichert, bestätigt, wiederholt oder geordnet verarbeitet werden sollen, entsteht im Frontend eine unzuverlässige Variante eines Event Brokers oder Outbox-Mechanismus.

Fachliche Konsistenz gehört nicht in einen flüchtigen Browser-Event-Bus.

Der globale fachliche Store ist ein versteckter Frontend-Monolith

Abschnitt betitelt „Der globale fachliche Store ist ein versteckter Frontend-Monolith“

Die dritte Variante vermeidet scheinbar jede direkte Remote-zu-Remote-Kommunikation:

Profil-Remote ──────┐
Kalender-Remote ────┼── gemeinsam besessener fachlicher Store
Abrechnung-Remote ──┘

Alle Remotes lesen und schreiben einen zentralen fachlichen Zustand. Änderungen werden unmittelbar sichtbar. Zusätzliche Requests scheinen unnötig. Die Integration wirkt einfach.

Die horizontale Kopplung ist damit allerdings nicht verschwunden. Sie wurde lediglich in einen gemeinsamen Zustandscontainer verschoben.

Die Remotes teilen nun Datenmodelle, Actions, Selektoren und Gültigkeitsregeln. Mehrere Teams verändern dieselbe fachliche Wahrheit. Eine neue Version des Profil-Remotes kann ein Store-Schema schreiben, das ein älteres Kalender-Remote noch nicht versteht. Rollbacks werden schwieriger, weil Zustand und Code nicht unabhängig voneinander betrachtet werden können. Tests benötigen globale Zustandsübergänge. Der Start eines einzelnen Remotes setzt den Store-Aufbau des Hosts oder anderer Remotes voraus.

Sind Remotes nur zusammen mit einem gemeinsamen fachlichen Store funktionsfähig, wurden die Bundles getrennt, nicht aber die Anwendung.

Bei unterschiedlichen Frameworks verschärft sich das Problem. Angular-, React- und Vue-Remotes können technisch über dieselbe JavaScript-Abstraktion auf einen Store zugreifen. Damit ist jedoch noch nicht geklärt, wie Reaktivität, Subscriptions, Lebenszyklen, Fehlerbehandlung und Kompatibilität zuverlässig zusammenwirken.

Aus vermeintlich neutraler Infrastruktur wird schnell ein selbst entwickeltes, frameworkübergreifendes Zustandsframework. Die Teams betreiben dann zusätzlich zu ihren eigentlichen Anwendungen einen gemeinsamen Runtime-Vertrag, dessen Auswirkungen jedes Remote berücksichtigen muss.

Horizontal gekoppelte Remotes teilen Actions, Events und fachlichen Zustand. Unabhängige Remotes beziehen eigene Projektionen aus verantwortlichen Quellen.

Die Kritik am gemeinsam besessenen fachlichen Zustand ist keine pauschale Kritik an Redux, NgRx oder einer technisch globalen Store-Instanz.

Klassische Anwendungen besaßen häufig einen zentral bereitgestellten Root Store:

Root Store
├── Kalender Feature State
├── Profil Feature State
└── Abrechnung Feature State

Die technische Registrierung war global. Die fachlichen Bereiche konnten trotzdem weitgehend gekapselt bleiben. Ein Feature besaß eigene Reducer, Actions, Selektoren, Effects und Zustandsmodelle. Andere Features mussten diese Interna nicht abonnieren oder verändern.

Auch in Microfrontend-Systemen konnte ein Store im Container des jeweiligen Remotes bereitgestellt werden:

Host
└── Kalender-Remote
└── eigener Store
└── Kalenderzustand

Damit blieben Zustand und Lebenszyklus beim Remote. Der Host musste dadurch nicht zum Verantwortlichen für das fachliche Modell werden.

Nicht die globale Store-Instanz ist das eigentliche Antipattern. Das Antipattern ist gemeinsam besessener fachlicher Zustand zwischen unabhängigen Remotes.

Ein Remote darf intern selbstverständlich Redux, NgRx, einen Signal Store oder eine andere Zustandslösung einsetzen. Problematisch wird es, wenn mehrere Remotes denselben fachlichen Zustand lesen und verändern, Actions oder Selektoren anderer Fachbereiche als Integrationsvertrag verwenden oder ohne den globalen Zustand des Hosts nicht mehr eigenständig funktionieren.

Die stärkere Verbreitung lokal bereitgestellter Stores macht diese Grenze heute sichtbarer. Moderne Store-Ansätze lassen sich näher an einem Feature oder Remote bereitstellen und besitzen dadurch einen klareren Lebenszyklus. Das widerlegt keine klassische globale Store-Infrastruktur. Es erinnert lediglich daran, dass technischer Zustand nicht automatisch auf Anwendungsebene geteilt werden muss.

Fachlicher Zustand sollte dort leben, wo er verantwortet wird.

Ein Name ändert sich – was geschieht im Kalender?

Abschnitt betitelt „Ein Name ändert sich – was geschieht im Kalender?“

Ein konkretes Beispiel zeigt den Unterschied.

Ein Benutzer aktualisiert im Profil-Remote seinen Namen:

Profil-Remote
└── schreibt Änderung an das Backend

An anderer Stelle zeigt ein Kalender-Remote den Namen dieses Benutzers an. Die unmittelbare Reaktion lautet häufig: Nach dem Speichern muss das Profil-Remote den neuen Namen an das Kalender-Remote weitergeben.

Die naheliegenden Lösungen sind eine Action oder ein gemeinsames Profilobjekt:

Profil-Remote
└── profileSaved ──▶ Kalender-Remote

oder:

Profil-Remote
└── schreibt Profilobjekt in globalen Store
Kalender-Remote

Beide Varianten setzen voraus, dass das Kalender-Remote das Zustandsmodell des Profil-Remotes übernimmt. Dabei benötigt es möglicherweise gar kein vollständiges Profil.

Das Profil-Remote arbeitet mit Namen, Kontaktinformationen, Einstellungen und weiteren bearbeitbaren Profildaten. Das Kalender-Remote benötigt vielleicht nur Anzeigename, Kürzel und Verfügbarkeit. Ein Abrechnungs-Remote interessiert sich dagegen für Rechnungsadresse und Kostenträger. Ein Dokumenten-Remote verwendet möglicherweise nur einen rechtssicher formatierten Namen.

Diese Modelle können auf denselben grundlegenden Daten beruhen. Sie sind trotzdem nicht identisch.

Profil-Remote
└── vollständige Profildaten
Kalender-Remote
└── Anzeigename, Kürzel und Verfügbarkeit
Abrechnungs-Remote
└── Rechnungsadresse und Kostenträger

Ein Remote lädt daher nicht einfach dieselben Daten noch einmal. Es lädt die Projektion, die zu seinem eigenen Anwendungsfall gehört.

Das robustere Modell sieht so aus:

Profil-Remote ── schreibt ──▶ verantwortliche Quelle
Kalender-Remote ── liest bei Bedarf ──▶ eigene Projektion

Das schreibende Remote besitzt die Benutzerintention. Die verantwortliche serverseitige Quelle besitzt die fachliche Wahrheit. Andere Remotes besitzen die Projektionen, die sie für ihre jeweiligen Anwendungsfälle benötigen.

Kein Remote muss dafür die internen Actions, Store-Schemata oder Zustandsübergänge eines anderen Remotes kennen.

Das Kalender-Remote muss nicht unmittelbar erfahren, dass im Profil-Remote ein bestimmter Speichervorgang ausgeführt wurde. Es muss lediglich erkennen können, wann seine eigene Projektion möglicherweise nicht mehr aktuell ist.

Dafür existieren unterschiedliche Strategien. Eine Projektion kann beim Betreten eines Bereichs geladen und nach einer fachlich sinnvollen Zeit revalidiert werden. Ein erneuter Fokus kann eine Prüfung auslösen. Einzelne Datensätze können gezielt nachgeladen werden. HTTP-Caches, Query-Caches und lokale Stores können unnötige Übertragungen vermeiden. Bei geeigneten Anwendungsfällen sind Polling, Server-Sent Events oder WebSockets möglich.

Entscheidend ist nicht der konkrete Mechanismus, sondern die Richtung der Abhängigkeit.

Ein serverseitiges Signal könnte beispielsweise mitteilen:

Benutzerdaten für Benutzer 4711 haben sich geändert.

Das Kalender-Remote kann daraufhin seine eigene Projektion für Benutzer 4711 invalidieren und bei Bedarf neu laden. Das Signal transportiert nicht das vollständige Profilmodell und schreibt auch keinen fremden Zustand in den Kalender-Store.

Invalidiere eine Projektion, statt fachlichen Zustand zwischen Remotes zu synchronisieren.

Die Unterscheidung ist wesentlich: Das Kalender-Remote reagiert nicht auf einen internen Vorgang des Profil-Remotes. Es reagiert auf die mögliche Veraltung seiner eigenen Daten. Die neue fachliche Wahrheit liest es über seinen eigenen Backend-, BFF- oder Integrationsvertrag.

Profil-Remote
└── schreibt Änderung
Backend / verantwortliche Quelle
├── persistiert Wahrheit
└── optionales Invalidierungssignal
Kalender-Remote
└── lädt eigene Projektion neu

Der Verlust eines Invalidierungssignals darf nicht zum Verlust fachlicher Wahrheit führen. Das Remote benötigt deshalb zusätzlich eine belastbare Revalidierungsstrategie. Das Signal ist ein Hinweis auf mögliche Veraltung, kein Ersatz für die verantwortliche Datenquelle.

Ein Profil-Remote schreibt eine Änderung, das Backend speichert die fachliche Wahrheit, ein Signal invalidiert eine Projektion und das Kalender-Remote liest seine eigene Projektion neu.

Der Performanceeinwand ist berechtigt. Wenn jedes Remote seine Projektion selbst verwaltet, können zusätzliche Requests entstehen. Netzwerkkosten und Latenzen verschwinden nicht durch eine gute fachliche Grenze.

Eigenständigkeit bedeutet jedoch nicht, bei jeder Interaktion sämtliche Daten ungefiltert neu zu laden. Sie bedeutet, dass ein Remote seinen Datenbedarf und seine Aktualitätsregeln selbst verantwortet.

Das Kalender-Remote weiß, welche Daten es benötigt und wie lange seine Projektion für den konkreten Anwendungsfall als ausreichend aktuell gelten kann. Es kann einen Datensatz gezielt revalidieren, statt den gesamten Kalender neu aufzubauen. Es kann Antworten lokal oder über HTTP zwischenspeichern. Es kann gleichartige Anfragen zusammenfassen, serverseitig aggregierte Projektionen verwenden oder Aktualisierungen erst beim nächsten fachlich relevanten Zugriff durchführen.

Eine remote-spezifische Projektion ist häufig kleiner als ein globales Modell. Das Kalender-Remote braucht kein vollständiges Profilobjekt, wenn es lediglich einen Anzeigenamen darstellen möchte. Umgekehrt muss es sich nicht an den Gültigkeitsregeln orientieren, die für die Bearbeitung von Kontaktdaten im Profil gelten.

Ein globales Profilobjekt wirkt zunächst effizient, weil es nur einmal geladen wird. Tatsächlich koppelt es alle Consumer an dasselbe Schema, dieselbe Version und dieselben Aktualitätsregeln. Änderungen für einen einzelnen Anwendungsfall können dadurch Auswirkungen auf alle Remotes haben.

Performanceoptimierung ist Aufgabe des jeweiligen Remotes und seines Backend-Vertrags – kein Grund, fachlichen Zustand horizontal zwischen Remotes zu teilen.

Redundante Requests sind ein Performanceproblem. Gemeinsam besessener fachlicher Zustand ist ein Architekturproblem. Das eine sollte nicht vorschnell durch das andere gelöst werden.

Ein internes Feature einer klassischen Anwendung kann häufig darauf vertrauen, dass ein globaler Store seinen aktuellen Zustand bereits enthält. Ein Microfrontend sollte diese Annahme nicht unbemerkt übernehmen.

Es kann allein gestartet werden, in einem anderen Host laufen, später geladen werden oder eine andere Version besitzen. Nach einem Reload baut es seinen Zustand neu auf. Es kennt keine Actions, die vor seinem Start in einem anderen Remote ausgeführt wurden.

Eine eigenständig lauffähige Anwendung erhält deshalb keine fachlichen Updates auf magische Weise. Sie benötigt eine eigene Revalidierungsstrategie; ein Invalidierungssignal kann diese Strategie ergänzen, aber nicht ersetzen.

Das ist keine Schwäche der Architektur, sondern eine Konsequenz tatsächlicher Kapselung.

Wer diese Konsequenz nicht akzeptieren möchte, benötigt möglicherweise keine unabhängigen Microfrontends, sondern modularisierte Features innerhalb einer gemeinsam ausgelieferten Anwendung. Das kann eine vollkommen angemessene Architektur sein. Problematisch wird es erst, wenn unabhängige Remotes versprochen werden, ihre Funktionsfähigkeit aber weiterhin von einem gemeinsamen fachlichen Laufzeitmodell abhängt.

Nicht jedes globale Signal transportiert fachliche Wahrheit.

Ein Host kann einen kleinen, stabilen Vertrag für technische Plattformkoordination anbieten. Dazu können je nach System Navigation, Logout, Sprache, Theme oder das Scheitern beim Laden eines Remotes gehören:

navigateTo
logout
localeChanged
themeChanged
remoteLoadFailed

Nicht jedes dieser Beispiele muss zwingend als Event umgesetzt werden. Entscheidend ist die Kategorie: Diese Informationen koordinieren die Plattform oder die Benutzeroberfläche. Sie veröffentlichen nicht den fachlichen Zustand eines Profil-, Kalender- oder Abrechnungs-Remotes.

Plattformkontext darf gemeinsam verfügbar sein. Fachliche Wahrheit gehört nicht in einen globalen Browser-Store.

Wo genau die Grenze globaler Events verläuft und welche Verträge ein Host anbieten sollte, ist ein eigenes Thema. Für die Kommunikation fachlichen Zustands genügt die Unterscheidung: Technische Plattformkoordination ist nicht dasselbe wie horizontale Zustandssynchronisation.

Ein gemeinsamer Store oder Browser-Event-Bus wirkt im ersten Prototyp oft überzeugend. Die Änderung ist sofort sichtbar. Ein zusätzlicher Request entfällt. Der technische Aufwand bleibt gering und die Demo funktioniert.

Die Kosten zeigen sich später.

Versionen können nicht mehr unabhängig aktiviert werden. Rollbacks müssen die Erwartungen unbekannter Consumer berücksichtigen. Tests benötigen mehrere Remotes und globale Zustandsübergänge. Fehler entstehen abhängig von Ladezeitpunkt, Reihenfolge oder Browser-Tab. Teams verändern gemeinsam genutzte Modelle, deren tatsächliche Besitzer nicht mehr eindeutig sind. Lokale Entwicklung wird schwerer, weil ein Remote ohne Host, Event-Bus oder globalen Store nicht vollständig funktioniert.

Der im Prototyp gesparte Request kann langfristig mit gemeinsamem Ownership und gekoppelten Releases bezahlt werden.

Das Gegenmodell kann zusätzliche Reads und Revalidierungen verursachen. Dafür bleiben die Verträge explizit. Jedes Remote kontrolliert seinen Zustand, seinen Lebenszyklus und seine Aktualitätsregeln. Änderungen am Profilmodell müssen nicht automatisch zu Änderungen im Kalender führen. Ein Kalender-Remote kann zurückgerollt oder separat getestet werden, ohne die internen Prozesse des Profil-Remotes nachzubilden.

Diese Trennung ist nicht kostenlos. Sie verschiebt die Arbeit jedoch an die richtige Stelle: in explizite Projektionen, verantwortete Backend-Verträge und fachlich begründete Aktualitätsregeln.

Aus der Argumentation ergeben sich harte, aber einfache Konsequenzen.

Ein Remote abonniert keine fachlichen Actions eines fremden Verantwortungsbereichs. Fachliche Browser-Events werden nicht als horizontaler Zustandskanal verwendet. Remotes teilen keinen gemeinsam besessenen fachlichen Zustand über einen globalen Store. Ein Remote importiert keine laufenden Anwendungsservices oder Store-Interna eines anderen Remotes.

Stattdessen besitzt jedes Remote seine eigene Projektion und liest sie über einen eigenen Vertrag. Ein optionales Signal darf anzeigen, dass diese Projektion veraltet sein könnte. Die neue fachliche Wahrheit stammt jedoch aus der dafür verantwortlichen Quelle.

Das bedeutet nicht, dass jedes Remote sein eigenes Backend benötigt. Frontend- und Backend-Zerlegung bleiben getrennte Entscheidungen. Mehrere Remotes können dieselbe API, ein gemeinsames BFF oder eine frontendnahe Integrationsschicht verwenden. Ausschlaggebend ist, dass ihre Verträge und Projektionen nicht aus den internen Zustandsmodellen anderer Remotes entstehen.

Remotes müssen nicht den internen Änderungsvorgang eines anderen Remotes kennen. Sie müssen erkennen können, wann ihre eigene Projektion nicht mehr verlässlich ist.

Behandle Remotes wie getrennte Anwendungen. Dann wird aus der Frage nach ihrer Kommunikation wieder die richtige Frage: Wem gehört der Zustand?

Remotes kommunizieren nicht miteinander. Sie kommunizieren mit den Quellen, die ihre jeweilige fachliche Projektion verantworten.