Zum Inhalt springen

Welche Anwendung sieht der Benutzer eigentlich?

Der vorherige Artikel hat eine zentrale Frage dynamischer Microfrontend-Architekturen behandelt:

Welche Produktkomposition soll für einen bestimmten Nutzungskontext aktiv sein?

Dafür können Remotes unabhängig veröffentlicht und anschließend über eine Composition ID zu einer freigegebenen Produktkomposition zusammengeführt werden. Die Host-Version bildet dabei den Host-Kontext, für den diese Komposition freigegeben ist.

Aus Sicht der Architektur entsteht beispielsweise:

Host 5.4.2
Remote A 1.1.0
Remote B 2.3.1
Remote C 4.7.0

Aus Sicht des Benutzers existiert dagegen nur:

die Anwendung

Ein Benutzer meldet nicht:

„Remote B 2.3.1 ist beim Bootstrap fehlgeschlagen.“

Er meldet:

„Die Seite funktioniert nicht.“

Genau an dieser Stelle verschiebt sich die Fragestellung.

Es reicht nicht mehr zu wissen, welche Produktkomposition aktiviert wurde. Für einen konkreten Fehlerfall muss nachvollziehbar sein, welche Produktkomposition für diese Sitzung aufgelöst wurde, welche Artefakte der Browser tatsächlich geladen hat und an welcher technischen Grenze der Fehler entstanden ist.

Microfrontends dürfen unabhängig ausgeliefert werden. Ihre Laufzeit darf deshalb noch lange nicht unabhängig beobachtet werden.

Für den Benutzer existiert eine Anwendung. Observability muss deshalb aus mehreren unabhängig ausgelieferten Frontends wieder einen gemeinsamen Laufzeitkontext herstellen.

Aktiviert ist nicht dasselbe wie tatsächlich geladen

Abschnitt betitelt „Aktiviert ist nicht dasselbe wie tatsächlich geladen“

Eine Aktivierungssteuerung kann eindeutig festlegen:

production-de
└── Composition 184

Damit ist definiert, welche Produktkomposition für einen bestimmten Nutzungskontext vorgesehen ist.

Diese Information beantwortet jedoch noch nicht die Frage, was in einem konkreten Browser passiert ist.

Vielleicht konnte ein Remote nicht geladen werden. Vielleicht wurde es aufgrund von Lazy Loading während der gesamten Sitzung überhaupt nicht benötigt. Vielleicht wurde das Artefakt geladen, sein Bootstrap ist jedoch fehlgeschlagen. Oder das Remote ist erfolgreich gestartet und erst anschließend bei einem API-Aufruf in einen Fehlerzustand geraten.

Deshalb müssen drei Zustände sauber voneinander getrennt werden.

Sollzustand, aufgelöster Snapshot und beobachteter Browserzustand

Abschnitt betitelt „Sollzustand, aufgelöster Snapshot und beobachteter Browserzustand“

Die Aktivierungssteuerung beschreibt beispielsweise:

production-de
└── Composition 184

Die Frage lautet:

Was soll geladen werden?

Beim Start löst der Host die Aktivierung auf und pinnt die ausgewählte Produktkomposition für die Sitzung:

Session
└── Composition 184

Die Frage lautet nun:

Welcher freigegebene Produktstand wurde für diese Sitzung ausgewählt?

Damit existiert ein reproduzierbarer Bezugspunkt. Eine spätere Aktivierung von Composition 191 verändert diesen Snapshot nicht automatisch.

Im Browser kann dagegen folgender Zustand entstehen:

Composition 184
Host 5.4.2
├── Remote A 1.1.0 → geladen
├── Remote B 2.3.1 → Ladefehler
└── Remote C 4.7.0 → noch nicht geladen

Jetzt lautet die Frage:

Was ist beim Benutzer tatsächlich angekommen?

Eine Composition ID beschreibt zunächst den vorgesehenen und aufgelösten Produktstand. Observability muss zusätzlich zeigen, welche Bestandteile davon im Browser tatsächlich geladen, gestartet oder verworfen wurden.

Die Composition ID wird dadurch nicht falsch. Sie bleibt der Kontext, in dem der Vorgang stattgefunden hat. Sie beweist lediglich nicht, dass jedes referenzierte Artefakt erfolgreich ausgeführt wurde.

Aktivierungssteuerung, gepinnter Kompositionssnapshot und tatsächlich beobachteter Browserzustand werden als drei getrennte Ebenen dargestellt.

Die technische Zerlegung eines Produkts ist für die Entwicklung relevant. Für die Benutzererfahrung ist sie zunächst bedeutungslos.

Wenn /members nicht funktioniert, ist aus Benutzersicht die Anwendung fehlerhaft. Ob der Fehler im Host, im Remote Loader, im Members-Remote oder in einem Backend-Service entstanden ist, ist eine Diagnosefrage.

Daraus folgt eine wichtige Konsequenz: Die technische Zerlegung darf bei der Beobachtung erhalten bleiben, aber sie muss innerhalb eines gemeinsamen Produktkontexts ausgewertet werden können.

Ein Fehler braucht einen Besitzer.

Ein Supportfall braucht dagegen den gesamten Zustand, in dem dieser Fehler aufgetreten ist.

Diese beiden Anforderungen widersprechen sich nicht.

Technische Observability und Supportdiagnose sollten deshalb keine getrennten Wahrheiten über das Produkt erzeugen.

Beide sind unterschiedliche Projektionen desselben Runtime Context.

Runtime Context
┌──────────────┴──────────────┐
↓ ↓
Technical Observability Support / Diagnostics
│ │
Errors, Traces, Metrics, Support ID,
Performance, Load Events Version Information,
User-Visible Status

Die technische Observability interessiert sich beispielsweise für:

  • Composition ID,
  • Host-Version,
  • Remote-Version,
  • Build-ID,
  • Route,
  • Ladefehler,
  • Runtime-Fehler,
  • Ladezeiten,
  • API-Anfragen,
  • Correlation IDs,
  • Trace IDs.

Die Supportsicht benötigt dagegen möglicherweise nur:

Produktversion
2026.08.07-184
Support ID
71AF-29C4

Intern kann dieselbe Support-ID auf den detaillierten Laufzeitkontext verweisen.

Technische Observability und Supportdiagnose sollten keine unterschiedlichen Wahrheiten über die Anwendung erzeugen. Sie sind unterschiedliche Projektionen desselben Laufzeitkontexts.

Ein herstellerneutrales Referenzmodell könnte beispielsweise so aussehen:

Runtime Context
├── Composition ID
├── Release-Channel
├── Host-Version
├── Host-Build-ID
├── Session- oder Support-ID
├── Correlation- oder Trace-ID
├── Auflösungszeitpunkt
└── beobachtete Remote-Instanzen
├── Name
├── Version
├── Build-ID
├── Ladezustand
└── Ladezeit

Nicht jede dieser Informationen muss in jedem Telemetrieereignis wiederholt werden. Entscheidend ist, dass sie eindeutig miteinander in Beziehung gesetzt werden können.

Die Composition ID beschreibt den gepinnten Produktstand. Eine Remote-Version erleichtert Menschen die Zuordnung. Eine Build-ID sollte eindeutig auf ein konkretes Artefakt verweisen; ein Artefakt-Digest kann zusätzlich die tatsächlich ausgelieferten Bytes absichern. Session-ID, Support-ID, Correlation ID und Trace ID erfüllen unterschiedliche Aufgaben und müssen nicht identisch sein. Gemeinsam ermöglichen sie, Ereignisse über technische Grenzen hinweg eindeutig in Beziehung zu setzen.

Das ist kein globaler fachlicher Zustand.

Ein gemeinsamer Runtime Context ist keine fachliche Kommunikation zwischen Remotes.

Eine Composition ID, Build-ID oder Correlation ID verletzt keine fachliche Autonomie. Sie beschreibt lediglich, in welchem technischen Produktzustand ein Ereignis stattgefunden hat.

Ein gemeinsamer technischer Runtime Context speist sowohl technische Observability als auch eine reduzierte Supportdiagnose.

Ein naheliegender Ausgangspunkt ist der Host-Bootstrap:

Host-Bootstrap
├── löst Composition ID auf
├── erzeugt Session-/Support-Kontext
└── initialisiert technischen Runtime Context

Beim erfolgreichen Laden eines Remotes kann der beobachtete Kontext ergänzt werden:

Remote A geladen
└── registriert:
├── Remote A
├── Version 1.1.0
├── Build 184
├── Ladezeit
└── Status: started

Bei einem fehlgeschlagenen Ladevorgang kann der Remote-Code diese Informationen möglicherweise nie selbst melden. Erwartete Version und Build-ID müssen dann aus der aufgelösten Produktkomposition stammen:

Remote B erwartet
├── Version 2.3.1
├── Build 92
└── beobachteter Status: load-failed

Damit bleibt klar getrennt, was die Komposition erwartet und was der Browser tatsächlich beobachten konnte. Dafür ist keine zentrale fachliche Registry erforderlich.

Der technische Kontext kann über eine kleine Observability-Schnittstelle, standardisierte Telemetrie, einen gemeinsamen SDK-Layer oder vorhandene Browser- und Tracing-Mechanismen transportiert werden.

Die konkrete Implementierung ist zweitrangig. Wichtig ist der Vertrag über die technischen Identitäten.

Welche Metadaten ein ausgeliefertes Frontend kennen sollte

Abschnitt betitelt „Welche Metadaten ein ausgeliefertes Frontend kennen sollte“

Jedes unabhängig ausgelieferte Frontend sollte sich selbst technisch identifizieren lassen.

Beispielsweise:

{
"name": "members",
"version": "2.7.4",
"buildId": "918",
"commit": "8c7a5e1"
}

Oder für eine kompakte Darstellung:

members 2.7.4+918

Die genaue Form ist weniger wichtig als die Eindeutigkeit.

Eine semantische Version wie 2.7.4 kann für Menschen hilfreich sein, muss aber nicht zwingend die konkreten ausgelieferten Bytes eindeutig bestimmen. Derselbe Versionsstring darf nicht unkontrolliert für nachträglich veränderte Artefakte wiederverwendet werden.

Build-Metadaten sollten deshalb beim Build entstehen und dauerhaft zum Artefakt gehören.

Für eine belastbare Reproduktion muss nachvollziehbar sein, in welchem konkreten Artefakt der Fehler aufgetreten ist.

Eine Git-Commit-ID kann dabei intern hilfreich sein. Sie muss deshalb nicht automatisch in einer öffentlichen Diagnoseansicht erscheinen.

Im Normalfall stimmen Produktkomposition und Browserbeobachtung überein:

Composition 184 erwartet:
Remote A 1.1.0
Browser beobachtet:
Remote A 1.1.0 / Build 184

Interessant werden die Abweichungen:

Composition 184 erwartet:
Remote B 2.3.1
Browser:
Remote B konnte nicht geladen werden

Falls eine Architektur kontrollierte Fallbacks unterstützt, könnte auch entstehen:

Composition 184 erwartet:
Remote B 2.3.1
Browser:
Remote B 2.3.0 / Fallback

Dann muss genau diese Abweichung sichtbar sein.

Observability sollte sowohl den erwarteten als auch den beobachteten Zustand kennen.

Das bedeutet nicht, dass automatische Fallbacks grundsätzlich empfehlenswert sind. In stark kontrollierten Systemen kann ein klarer Ausfall die sicherere Variante sein als eine Produktkomposition, die in dieser Form niemals freigegeben wurde.

Dynamische Microfrontends werden häufig nicht alle beim Anwendungsstart geladen.

Eine Produktkomposition kann enthalten:

Composition 184
├── Remote A
├── Remote B
├── Remote C
└── Remote D

Eine konkrete Sitzung besucht jedoch vielleicht nur Bereiche aus A und C:

tatsächlich geladen:
Remote A
Remote C

Daraus darf nicht die Aussage entstehen:

Remote B läuft fehlerfrei

Remote B wurde überhaupt nicht ausgeführt.

Für den Lade- und Lebenszyklus könnten beispielsweise folgende Zustände beobachtbar sein:

expected
not-loaded
loading
loaded
bootstrap-failed
started
unmounted

Laufzeitfehler sollten davon getrennt als Ereignisse erfasst werden. Ein erfolgreich gestartetes Remote wird nicht allein durch jede abgefangene Exception automatisch zu runtime-failed.

Die Begriffe sind nicht normativ. Wichtig ist die Semantik dahinter.

Nicht geladen ist kein Erfolg und kein Fehler. Es ist ein eigener beobachtbarer Zustand.

Ein besonders wichtiger Fall entsteht, wenn ein Remote niemals erfolgreich ausgeführt wird.

Benutzer öffnet /members
Host löst Composition 184 auf
Remote members 2.7.4 soll geladen werden
Chunk Request → 404
Remote-Code wird nie ausgeführt

Das Remote selbst kann diesen Fehler nicht zuverlässig melden. Sein Code wurde schließlich nie gestartet.

Trotzdem sollte ein Diagnoseereignis entstehen können:

RemoteLoadFailure
├── Composition 184
├── expected remote: members 2.7.4
├── URL
├── HTTP status: 404
├── session/support ID
└── timestamp

Daraus folgt eine klare technische Verantwortlichkeit:

Die Integrationsschicht, die ein Remote lädt, muss Ladefehler beobachten können.

Das macht den Host oder den Remote Loader nicht zum fachlichen Besitzer des Remotes. Er beobachtet ausschließlich die technische Integrationsgrenze.

Host
└── load Remote B
├── start
├── success
└── failure

Für die Diagnose lohnt sich außerdem die Unterscheidung zwischen Ladefehler, Bootstrap-Fehler, Runtime-Fehler nach erfolgreichem Start und Fehlern externer APIs oder Backend-Systeme.

Runtime-Fehler brauchen Remote-Ownership und Produktkontext

Abschnitt betitelt „Runtime-Fehler brauchen Remote-Ownership und Produktkontext“

Nach einem erfolgreichen Start verschiebt sich die Verantwortung.

Ein JavaScript-Fehler aus dem Members-Remote könnte beispielsweise so eingeordnet werden:

Error Event
├── Composition ID: 184
├── Host: 5.4.2+8231
├── Remote: members
├── Remote Version: 2.7.4
├── Remote Build: 918
├── Route: /members/42
├── Correlation ID: c-8f21...
└── Error: TypeError ...

Die Zuordnung zu einem Remote ermöglicht Ownership, gezielte Alarmierung, Analyse nach Builds und den Vergleich vor und nach einer Aktivierung.

Der Remote-Kontext allein genügt jedoch nicht immer.

Vielleicht tritt derselbe Build nur in Composition 184 auf:

Composition 184
├── Host 5.4.2
├── Members 2.7.4
└── Tasks 4.2.1
Fehler

Während eine andere Kombination problemlos funktioniert:

Composition 171
├── Host 5.4.2
├── Members 2.7.3
└── Tasks 4.2.1
kein Fehler

Ein Remote-Build ist eine wichtige Diagnoseachse. Die Composition ID liefert den Produktkontext, in dem dieser Build tatsächlich betrieben wurde.

Ein Fehler braucht einen technischen Besitzer. Für die Diagnose braucht er zusätzlich den Produktzustand, in dem er auftrat.

Microfrontend-Grenzen erhöhen die Gefahr, denselben Fehler mehrfach zu erfassen.

Remote B
└── wirft Fehler
Host
└── fängt denselben Fehler an einer Integrationsgrenze
Global Error Handler
└── sieht ihn ebenfalls

Ohne Korrelation können daraus scheinbar drei unabhängige Fehler werden.

Die bessere Modellierung ist, den Ursprung eindeutig zu erfassen und weitere Beobachtungen als Kontext oder Folgeereignisse mit demselben Vorgang zu verbinden.

Hilfreich sind beispielsweise eindeutige Event- oder Error-IDs und ein gemeinsamer Correlation Context.

Observability soll einen Fehler anreichern, nicht durch jede Architekturschicht vervielfachen.

Das gleiche Prinzip gilt über Frontend- und Backend-Grenzen hinweg.

Ein Remote kann erfolgreich geladen und gemountet sein, während anschließend seine API fehlschlägt:

members 2.7.4
├── erfolgreich geladen
├── erfolgreich gemountet
└── GET /members → 500

Die Diagnose sollte dann erkennen können:

Composition 184
Remote members 2.7.4+918
Frontend Trace
API Request
Backend Trace

Damit wird aus „Members funktioniert nicht“ eine deutlich präzisere Aussage:

Das Remote läuft. Eine seiner externen Abhängigkeiten ist fehlgeschlagen.

Produktionscode wird typischerweise transformiert, gebündelt und häufig minifiziert.

Ein Fehler kann deshalb zunächst so aussehen:

Remote A 1.1.0 / Build 184
→ app.8f7c.js
→ Fehler bei Zeile 1, Spalte 182734

Für die Entwicklung wird der Stacktrace durch die passende Source Map wesentlich besser analysierbar.

Build 184
├── app.8f7c.js
└── app.8f7c.js.map

Source Maps bilden generierten Code auf seine ursprünglichen Quellen zurück und können auch für serverseitige Stacktrace-Symbolisierung verwendet werden. Entscheidend ist deshalb die eindeutige Bindung zwischen generiertem Artefakt und zugehöriger Source Map.

Eine Source Map eines anderen Builds kann Positionen auf den falschen Quellcode abbilden und damit eine Diagnose eher verschlechtern als verbessern.

Bei parallel betriebenen Remote-Versionen müssen folglich auch die entsprechenden Diagnoseartefakte ausreichend lange verfügbar bleiben. Die Retention sollte zum vorgesehenen Support-, Rollback- und Analysefenster passen.

Source Maps müssen für die Diagnose verfügbar sein. Das bedeutet nicht zwingend, dass sie öffentlich vom Browser abrufbar sein müssen.

Eine mögliche Betriebsform ist:

Browser
└── liefert minifizierten Stacktrace + Build-ID
Error Backend
└── symbolisiert mit intern gespeicherter Source Map

Source Maps können Informationen über Quellstruktur und – abhängig von ihrer Erzeugung – auch Quellinhalte enthalten. Ob sie öffentlich ausgeliefert oder intern aufbewahrt werden, ist deshalb eine bewusste Betriebsentscheidung und keine allgemeingültige Regel.

Auch Performance folgt der Benutzersicht.

Eine Navigation kann technisch aus mehreren Phasen bestehen:

Navigation
→ Host rendert
→ Remote Entry wird geladen
→ Shared Chunks werden geladen
→ Remote bootstrapt
→ API antwortet
→ UI wird sichtbar

Eine langsame Seite kann deshalb sehr unterschiedliche Ursachen haben.

Navigation /tasks
Host routing 20 ms
Remote resolution 15 ms
Remote load 420 ms
Remote bootstrap 65 ms
Initial API 780 ms
Render 40 ms

Ein gemeinsamer Runtime Context macht es möglich, diese Phasen derselben Produktkomposition und derselben Sitzung zuzuordnen.

Dafür können zusätzliche technische Messpunkte sinnvoll sein:

  • Beginn des Remote-Loads,
  • Remote Entry geladen,
  • Bootstrap gestartet,
  • Mount abgeschlossen,
  • erstes relevantes Rendering,
  • kritische API abgeschlossen,
  • Fehler- und Timeout-Zeitpunkte.

Browserseitige User-Timing-Mechanismen erlauben Anwendungen, eigene Marks und Measures für solche anwendungsspezifischen Zeitpunkte zu erfassen. Entscheidend ist jedoch weniger die konkrete API als ein konsistentes Messmodell.

Warum Web Vitals nicht automatisch einem Remote gehören

Abschnitt betitelt „Warum Web Vitals nicht automatisch einem Remote gehören“

Core Web Vitals beschreiben primär Eigenschaften der vom Benutzer erlebten Seite: Ladeerlebnis, visuelle Stabilität und Reaktionsfähigkeit entstehen im zusammengesetzten Produkt.

Bei Microfrontends lässt sich daraus nicht automatisch ableiten:

dieses LCP gehört Remote A
dieses INP gehört Remote B
dieses CLS gehört dem Host

Mehrere Deployables teilen sich DOM, Netzwerk, Main Thread und Rendering-Pipeline.

Für die Untersuchung einzelner Beiträge sind deshalb ergänzende technische Marks, Measures oder Traces sinnvoll.

Lokale Performancebudgets bleiben dennoch nützlich. Sie verhindern beispielsweise, dass ein einzelnes Remote unkontrolliert wächst.

Sie reichen nur nicht als Produktmetrik.

Remote A ist schnell.
Remote B ist schnell.
Host ist schnell.

Und trotzdem kann das Gesamtprodukt langsam sein.

Ursachen können doppelt geladene Abhängigkeiten, konkurrierende Netzwerkrequests, parallele Bootstraps, unnötige Vorladungen, Main-Thread-Konkurrenz oder Layout Shifts sein.

Lokale Performancebudgets sind hilfreich. Die relevante Benutzererfahrung entsteht jedoch aus ihrer Komposition.

Frontend- und Backend-Ereignisse miteinander verbinden

Abschnitt betitelt „Frontend- und Backend-Ereignisse miteinander verbinden“

Viele Fehler enden nicht an der Frontend-Grenze.

Browser Session / Trace
Remote A
API Request
Backend Service

Wenn Infrastruktur und Sicherheitsmodell es erlauben, kann ein technischer Korrelationskontext über solche Grenzen weitergeführt werden.

Browser-Ereignisse können einen gemeinsamen Trace- oder Correlation-Kontext tragen. API-Aufrufe können diesen Kontext weitergeben, sofern Trust-Grenzen und technische Integration das zulassen. Backend-Telemetrie kann anschließend mit dem Frontendvorgang verbunden werden.

Damit entsteht keine fachliche Kommunikation zwischen Microfrontends. Es wird lediglich derselbe technische Vorgang über mehrere Systeme nachvollziehbar.

Dabei gelten weiterhin Trust-Grenzen.

Interne IDs sollten nicht unkontrolliert an beliebige fremde Domains oder externe APIs weitergegeben werden. Ebenso muss nicht jeder Request zwingend Bestandteil eines vollständigen Distributed Traces sein.

Korrelation ist ein Werkzeug zur Diagnose, kein Selbstzweck.

Ein korrelierter Laufzeit-Zeitstrahl verbindet Host, Remote, API und Backend zu einem einzigen vom Benutzer erlebten Vorgang.

Eine vollständige technische Diagnoseansicht könnte intern beispielsweise enthalten:

Anwendungsinformationen
Produktversion
Composition 184
Host
5.4.2 / Build 8231
Geladene Bereiche
Members 2.7.4 / Build 918
Tasks 4.2.1 / Build 1271
Release-Channel
production-de
Support ID
71AF-29C4

Für einen normalen Benutzer wäre diese Detailtiefe meist unnötig.

Eine reduzierte Darstellung kann genügen:

Version
2026.08.07-184
Support ID
71AF-29C4

Intern löst der Support die ID auf:

Support ID 71AF-29C4
└── Runtime Context
├── Composition 184
├── Host 5.4.2+8231
├── Members 2.7.4+918
├── Tasks 4.2.1+1271
├── Channel production-de
├── Session
└── relevante Telemetrie

Der Benutzer muss die Architektur nicht verstehen, damit der Support sie diagnostizieren kann.

Ob solche Informationen über eine About-Seite, einen Diagnosemodus, eine Supportrolle oder ausschließlich interne Werkzeuge erreichbar sind, ist eine Produkt- und Betriebsentscheidung.

Architektonisch entscheidend ist etwas anderes: Die Informationen stammen aus demselben Runtime Context wie Fehler, Ladeereignisse und Performance-Telemetrie.

Eine Support-ID als Brücke zur technischen Diagnose

Abschnitt betitelt „Eine Support-ID als Brücke zur technischen Diagnose“

Eine Support-ID sollte einen technischen Laufzeitkontext adressieren, nicht die Benutzeridentität selbst.

Sie sollte deshalb nicht automatisch E-Mail-Adresse, Benutzername, Personalnummer, Kundennummer, Session Token oder Access Token enthalten oder daraus direkt ableitbar sein.

Eine Support-ID soll einen technischen Laufzeitkontext adressieren, nicht den Benutzer offenlegen.

Supportprozesse können selbstverständlich zusätzliche geschützte Informationen benötigen. Diese gehören jedoch in den dafür vorgesehenen Kontext und nicht zwangsläufig in öffentlich sichtbare Versions- oder Fehlerinformationen.

Damit bleibt die Support-ID genau das, was sie sein soll: eine Brücke zwischen einem konkreten Benutzererlebnis und dem dazugehörigen technischen Laufzeitkontext.

Auch die Zeitdimension gehört zur Diagnose.

Angenommen, eine Sitzung wurde mit Composition 184 gestartet:

Session A
└── Composition 184

Während diese Sitzung läuft, wird eine neue Produktkomposition aktiviert:

production-de → Composition 191

Session A bleibt zunächst auf ihrem gepinnten Snapshot.

Eine neue Sitzung oder ein kontrollierter Reload kann anschließend Composition 191 erhalten.

Für einen Supportfall ist deshalb die Frage

„Welche Version ist aktuell in Produktion?“

oft zu ungenau.

Entscheidend ist:

Welche Composition ID wurde für diese konkrete Sitzung aufgelöst und welche Builds wurden darin tatsächlich ausgeführt?

Gerade bei parallelen Release-Channels, schrittweisen Aktivierungen oder kontextspezifischen Produktkompositionen können zur selben Zeit mehrere gültige Antworten existieren.

Technische Observability ist keine fachliche Kopplung

Abschnitt betitelt „Technische Observability ist keine fachliche Kopplung“

Ein gemeinsames Observability-Konzept darf nicht zum Vorwand werden, fachliche Grenzen wieder einzureißen.

Nicht:

Host
└── versteht alle fachlichen Events aller Remotes

Sondern beispielsweise:

gemeinsamer technischer Vertrag
├── Composition ID
├── Build-Metadaten
├── Trace-/Correlation-Kontext
├── Fehlerformat
└── technische Lifecycle-Ereignisse

Zentralisiert werden technische Korrelationsinformationen, nicht die fachliche Bedeutung der Remotes.

Das ist derselbe Unterschied, der auch bei anderen gemeinsamen Plattformbausteinen wichtig ist.

Ein Observability-SDK darf ein technischer Plattformbaustein sein. Es sollte jedoch nicht zum versteckten Runtime-Service werden, ohne den die Fachlichkeit eines Remotes nicht mehr funktioniert.

Remotes bleiben fachlich eigenständig.

Ihre technischen Laufzeitereignisse werden lediglich in einen gemeinsamen Produktkontext eingeordnet.

Nicht jedes technische Ereignis benötigt einen Alarm.

Interessant sind vor allem Veränderungen mit relevanter Benutzerwirkung, beispielsweise:

  • ein deutlicher Anstieg von Remote-Ladefehlern,
  • neue Bootstrap-Fehler nach einer Aktivierung,
  • eine erhöhte JavaScript-Fehlerrate eines bestimmten Builds,
  • auffällige API-Fehlerraten,
  • eine deutliche Performanceverschlechterung,
  • Integritäts- oder Manifestfehler.

Universelle Grenzwerte existieren dafür nicht. Ein einzelner Fehler kann in einem sicherheitskritischen Prozess relevant sein, während in einem anderen System sporadische Netzwerkfehler erwartbar und automatisch behandelbar sind.

Alarmiert werden sollte auf Veränderungen und relevante Benutzerwirkung, nicht auf jede einzelne technische Ausnahme.

Von einzelnen Deployables zurück zur beobachtbaren Anwendung

Abschnitt betitelt „Von einzelnen Deployables zurück zur beobachtbaren Anwendung“

Microfrontends zerlegen ein Frontend in unabhängig verantwortete und unabhängig auslieferbare Einheiten.

Diese Zerlegung ist wertvoll für Ownership, Releases und technische Evolution.

Zur Laufzeit müssen die einzelnen Teile jedoch wieder als gemeinsames Produkt beobachtbar werden.

Dafür braucht es keine zentrale fachliche Steuerung. Es braucht gemeinsame technische Identitäten.

Die Composition ID beantwortet, welche freigegebene Produktkomposition für eine Sitzung aufgelöst wurde.

Build-IDs beantworten, welche konkreten Artefakte beteiligt waren.

Der beobachtete Remote-Zustand beantwortet, welche davon tatsächlich geladen und gestartet wurden.

Correlation IDs und Trace IDs verbinden technische Ereignisse.

Source Maps verbinden Produktionsartefakte mit analysierbarem Quellcode.

Performance-Messpunkte verbinden einzelne technische Phasen mit der vom Benutzer erlebten Journey.

Eine Support-ID verbindet schließlich diese technische Sicht mit einem Supportfall, ohne vom Benutzer verlangen zu müssen, die interne Architektur zu verstehen.

So entsteht aus unabhängigen Deployables keine unabhängige Diagnose, sondern ein gemeinsamer beobachtbarer Produktzustand.

Der vorherige Artikel konnte festlegen, welche Composition ID für einen Nutzungskontext aktiviert ist. Für einen konkreten Support- oder Fehlerfall reicht diese Information allein nicht aus.

Eine Composition ID beschreibt, welche Produktkomposition für eine Sitzung aufgelöst wurde. Observability muss zusätzlich zeigen, welche Artefakte tatsächlich geladen und gestartet wurden.

Jedes unabhängig ausgelieferte Frontend benötigt eindeutige Build-Metadaten, damit Fehler, Source Maps und Performancewerte dem tatsächlich ausgeführten Artefakt zugeordnet werden können.

Fehler eines Remotes benötigen klare Ownership. Sie dürfen dabei den gemeinsamen Produktkontext aus Composition ID, Sitzung und technischer Korrelation nicht verlieren.

Ladefehler müssen an der technischen Integrationsgrenze beobachtbar sein, weil der betroffene Remote-Code möglicherweise niemals ausgeführt wird.

Source Maps müssen eindeutig dem konkreten Build zugeordnet bleiben. Bei parallelen Versionen müssen auch die dazugehörigen Diagnoseartefakte ausreichend lange verfügbar sein.

Performance gehört aus Benutzersicht zum Gesamtprodukt. Messungen einzelner Remotes können Ursachen sichtbar machen, ersetzen aber nicht die Beobachtung der gesamten User Journey.

Technische Korrelation zwischen Host, Remotes und Backend-Systemen ist keine fachliche Kommunikation zwischen Microfrontends.

Der normale Benutzer benötigt keine Liste interner Remote-Versionen. Eine kompakte Produktversion und eine Support-ID können genügen, solange der Support darüber den vollständigen technischen Laufzeitkontext rekonstruieren kann.

Nicht jedes Remote einer Produktkomposition ist in jeder Sitzung tatsächlich geladen. not-loaded, loading, started und konkrete Fehlerereignisse müssen unterscheidbar bleiben.

Damit treffen drei Perspektiven wieder aufeinander:

Benutzer
└── sieht eine Anwendung
Architektur
└── sieht mehrere Deployables
Observability
└── verbindet beide Perspektiven über einen gemeinsamen Runtime Context

„Welche Version ist gerade in Produktion?“ greift dabei zu kurz.

Welche Composition ID und welche konkreten Builds liefen in dieser Sitzung – und was ist mit ihnen tatsächlich passiert?

Für den Benutzer ist es eine Anwendung. Für die Diagnose muss exakt rekonstruierbar sein, aus welchen Versionen sie in diesem Moment bestand.