Zum Inhalt springen

Taktisches Frontend-Design

Architektur wird irgendwann konkret.

Strategische Entscheidungen können festlegen, welche fachlichen Grenzen ein System besitzt, wem Verantwortung gehört und welche Teile möglichst unabhängig voneinander bleiben sollen. Irgendwann muss daraus aber Code werden. Dann stellt sich nicht mehr nur die Frage, welche Grenze sinnvoll ist, sondern auch, wie sie sich im Projekt tatsächlich ausdrückt.

Welche Datei lädt Daten? Wo entsteht ein ViewModel? Wer startet einen Command? Wo gehören Mapping, Navigation oder Notifications hin? Und welche dieser Aufgaben sollte eine Komponente besser gar nicht erst übernehmen?

Genau an dieser Stelle beginnt für mich Taktisches Frontend-Design.

Der Begriff ist bewusst an Domain-Driven Design angelehnt.

DDD unterscheidet zwischen strategischen Entscheidungen über Domänen, Grenzen und Zusammenarbeit und dem taktischen Design innerhalb dieser Grenzen. Dort bekommen fachliche Konzepte konkrete Formen im Code, etwa als Entities, Value Objects, Aggregates oder Repositories.

Ein Frontend braucht davon keine mechanische Kopie. Ein Angular-Projekt wird nicht automatisch besser, wenn jeder DDD-Begriff irgendwo als Ordner auftaucht.

Der Grundgedanke ist trotzdem wertvoll:

Architektur muss sich irgendwann im Code wiederfinden.

Im Frontend können das andere Formen sein. Ein Read Flow organisiert eine fachliche Projektion für die Oberfläche. Ein ViewModel beschreibt bewusst, was eine View benötigt. Ein Command modelliert eine Änderung und ihre Folgen. Mapping schützt das Frontend davor, fremde Modelle ungefiltert zu übernehmen. Notifications, Navigation oder Invalidierung bekommen einen nachvollziehbaren Ort, statt zufällig dort zu landen, wo gerade ein HTTP-Aufruf abgeschlossen wird.

Darum heißt diese Rubrik taktisch: Sie beschäftigt sich mit dem konkreten Schnitt innerhalb einer fachlichen Grenze.

Viele Architekturprobleme entstehen nicht, weil ein Team die richtigen Begriffe nicht kennt. Sie entstehen, weil Verantwortungen im Alltag Stück für Stück an den bequemsten Ort wandern.

Eine Page lädt zunächst nur Daten. Später kommen Loading und Error Handling hinzu, dann Mapping, ein Toast, Navigation nach dem Speichern, ein Reload und zwei Sonderfälle. Irgendwann orchestriert die Komponente einen halben Use Case.

Dasselbe kann einem Store passieren. Was ursprünglich Zustand verwalten sollte, übernimmt plötzlich HTTP, Mapping, Commands, Formularlogik, Routing und fachliche Entscheidungen.

Das funktioniert oft erstaunlich lange. Genau deshalb lohnt es sich, früher über den Schnitt zu sprechen.

Die Beispiele in dieser Rubrik zeigen deshalb keine isolierten Patterns, sondern vollständige kleine Code-Slices. Die interessante Frage lautet nicht nur, ob ein Store, Mapper oder Command sinnvoll ist, sondern wie diese Teile zusammenarbeiten und wo ihre Verantwortungsgrenzen verlaufen.

Grundlagen zu einzelnen Mustern findest du beispielsweise bei ViewModel Aggregation, Event-driven Projection und dem Anti-Corruption Layer. Hier geht es einen Schritt weiter: Aus dem Gedanken wird ein ausführbarer Schnitt.

Die Beispiele orientieren sich an einem modernen Angular-Stack mit Angular 21, NgRx 21, Signals und NgRx Signal Store. Die Versionen bestimmen den Werkzeugkasten, nicht die Architektur.

Ein sauber getrennter Read Store mit Mapper, ViewModel und Tests kann für einen langlebigen fachlichen Slice sehr sinnvoll sein. Für einen kleinen Backoffice-Dialog wäre derselbe Aufbau möglicherweise unnötiger Ballast.

Deshalb sind die Beispiele nicht als Bauanleitung nach dem Muster „So muss man es machen“ gedacht.

Sie sollen einen konkreten Schnitt zeigen, über den man diskutieren kann.

Welche Variante sinnvoll ist, hängt unter anderem von fachlicher Komplexität, Lebensdauer, Änderungsdruck, Team und vorhandener Architektur ab. Gute Architektur braucht Struktur, aber Struktur allein ist noch kein Qualitätsmerkmal.

Den Einstieg bilden klassische CRUD-Flows, weil sich an ihnen sehr gut zeigen lässt, wie unterschiedlich Lesen und Schreiben im Frontend tatsächlich funktionieren können.

Retrieve Slice: Daten laden ohne Komponentenlogik zeigt einen Read Flow von der Infrastruktur bis zum ViewModel.

Create Slice: Schreiben als Command Flow betrachtet das Anlegen nicht als bloßes POST, sondern als Änderung mit fachlichem Ergebnis und möglichen Seiteneffekten.

Update Slice: Formularzustand ist kein DTO beschäftigt sich mit der Grenze zwischen Edit State, Backend-Modell und Command.

Delete Slice: Löschen ist eine fachliche Entscheidung zeigt, warum selbst ein scheinbar einfacher Delete Flow mehr sein kann als ein HTTP-Aufruf.

Daneben geht es um Reaktionen, die über einen einzelnen Slice hinausreichen. Notification Flow, Routing nach erfolgreichem Command und Reload und Invalidierung nach Success beschäftigen sich mit der Frage, wo solche Folgen modelliert werden, ohne sie wieder in die aufrufende Komponente zurückzuschieben.

Taktisches Frontend-Design liegt für mich zwischen zwei Extremen.

Auf der einen Seite stehen Architekturaussagen wie „Wir brauchen klare Grenzen“. Das ist richtig, hilft aber nur begrenzt, wenn anschließend niemand weiß, welche Verantwortung in welche Datei gehört.

Auf der anderen Seite stehen technische Aussagen wie „Wir verwenden NgRx Signal Store mit withMethods und withHooks“. Auch das kann richtig sein, sagt aber noch nichts darüber aus, was dieser Store eigentlich verantworten soll.

Diese Rubrik versucht, die Mitte zu treffen: konkret genug, um daraus Code zu bauen, und abstrakt genug, um zu verstehen, warum der Schnitt so gewählt wurde.

Die Beispiele sind deshalb keine endgültigen Antworten. Sie sind Vorschläge, die konkret genug sind, um sie im eigenen Projekt zu prüfen, zu kritisieren und bei Bedarf anders zu schneiden.