System-Design zuerst
Die meisten Tickets beschreiben was gebaut werden soll und verstecken die Fragen, die entscheiden, ob es den Kontakt mit der Produktion überlebt: wie viele Benutzer, wie oft, wie viele Daten, was passiert, wenn eine Abhängigkeit langsam ist, wem gehört die Wahrheit, wenn zwei Schreiber konkurrieren. Dieser Skill macht diese Fragen explizit bevor Code geschrieben wird, in einer Form, die der Autor der Aufgabe lesen und widersprechen kann.
Der Durchlauf ist: Umfang → Schätzung → High-Level-Design → Deep Dive → Zusammenfassung, angewandt auf echte Arbeit: Es gibt eine bestehende Codebasis, einen Autor mit einer Absicht und ein Budget. Das Ziel ist ein klares Bild der Funktion aus Sicht des Systems.
Antworte in der Sprache, in der der Benutzer schreibt. Das Briefing ist für ihn, nicht für dich.
1. Zuerst die Tiefe abschätzen
Ein Tippfehler zu überdimensionieren ist genauso falsch wie einen Zahlungsfluss zu unterdimensionieren. Wähle die Stufe, sag es in einem Satz und gib entsprechend aus.
| Stufe | Typische Aufgabe | Was du produzierst |
|---|---|---|
| L0 – trivial | Textänderung, Umbenennung, Style-Anpassung, offensichtlicher Fehler mit lokaler Korrektur | Nichts extra. Höchstens einen Satz, wenn ein verstecktes Risiko besteht ("Dieses Label wird auch 24h im CDN gecached"). Dann einfach die Aufgabe erledigen. |
| L1 – lokale Änderung | Neues Feld, neuer Filter, kleine Endpunktänderung, ein Hook, eine Query-Anpassung | Eine 3-7-zeilige Design-Prüfung inline: was es berührt, auf welcher Last es reitet, die eine Sache, die beißen könnte (N+1, Cache-Invalidierung, Paginierung, Idempotenz). Dann implementieren. |
| L2 – Feature | Neuer Bildschirm mit Datenfluss, neuer Endpunkt + Speicher, Benachrichtigungen, Suche, Export, Integration mit einem Drittanbieter | Das Design-Briefing (Abschnitt 4), etwa eine Seite. Dann nach dem Briefing implementieren. |
| L3 – Subsystem | Neuer Service, Echtzeitkanal, Ereignispipeline, Multi-Tenant-Datenmodell, Migration eines Hot Paths, alles mit "Skalierung" im Ticket | Vollständiges Briefing plus einen Deep Dive pro riskanter Komponente, betrachtete Alternativen, Migrationspfad, was nach dem Start gemessen werden soll. |
Signale, die eine Aufgabe eine Stufe nach oben verschieben: benutzerseitige Latenz, gleichzeitige Schreiber, Fan-Out (ein Ereignis → viele Empfänger), unbegrenztes Wachstum einer Tabelle oder Liste, Drittanbieter-Ratenlimits, Geld, PII, alles, was nach einem Zeitplan läuft, oder "vorübergehende" Lösungen, die offensichtlich bleiben werden. Signale, die sie nach unten verschieben: interne Tools mit einer Handvoll Benutzern, Daten, die für immer in den Speicher passen, Feature-Flag-Experimente mit einem Kill-Switch.
Wenn der Benutzer explizit nach einem Design-Review oder einer tieferen Analyse fragt, behandle es als L3, unabhängig von der Größe.
2. Der Durchlauf, Schritt für Schritt
Arbeite diese in der Reihenfolge durch. Für L1 komprimiere sie in ein paar Zeilen; für L2/L3
wird jeder Schritt zu einem Abschnitt des Briefings. references/framework.md enthält die
Fragenchecklisten für jeden Schritt; lies es beim ersten L2+-Durchlauf in einer Sitzung.
Schritt 1 — Verstehen und abgrenzen
- Formuliere das Feature in einem Absatz aus Sicht des Systems neu: Akteure, Auslöser, Eingaben, Ausgaben, Nebeneffekte.
- Trenne funktionale Anforderungen (was es tut) von nicht-funktionalen (wie gut: Skalierung, Latenz, Verfügbarkeit, Konsistenz, Haltbarkeit, Sicherheit, Kosten, Betriebsfähigkeit). Tickets nennen fast nie die zweite Art; leite sie aus dem Produktkontext ab und sage, dass sie abgeleitet sind.
- Schreibe auf, was außerhalb des Rahmens liegt, damit das Briefing nicht still wächst.
- Sammle die Absicht des Autors: Tickettext, PR-Beschreibung, Kommentare, verlinkte Designs, bestehende ADRs, wie ähnliche Funktionen in diesem Repo gebaut wurden. Der Autor hat normalerweise ein Design im Kopf; bringe es an die Oberfläche, anstatt es zu ersetzen.
- Stelle dem Benutzer nur Fragen, die das Design materiell verändern (z. B. "Muss das innerhalb einer Sekunde sichtbar sein, oder ist eine Minute in Ordnung?"). Für alles andere nimm eine Annahme an und mach weiter; Annahmen kommen ins Briefing.
Schritt 2 — Schätzen
Zahlen verwandeln Meinungen in Entscheidungen. Mache eine Überschlagsrechnung, auch
wenn das Ticket keine hat; references/estimation.md enthält die Referenzzahlen
(Latenzleiter, Zweierpotenzen, Verfügbarkeitsneunen, Kapazitäten pro Knoten)
und durchgerechnete Beispiele.
- Benutzer / Mandanten → täglich aktive → Aktionen pro Tag → durchschnittlicher und Spitzen-QPS (Spitze ist normalerweise 2-5× der Durchschnitt, mehr für Burst-Flows wie "jeder öffnet die App um 9:00").
- Lese-/Schreibverhältnis, Payload-Größe → Speicher pro Tag / Jahr, Bandbreite.
- Wachstum: Wie hoch ist die Zahl in 12 Monaten, wenn das Produkt erfolgreich ist?
- Wo reale Zahlen existieren (Analysen, DB-Zeilenanzahlen, bestehende Dashboards, Konfigurationslimits), verwende sie und zitiere die Quelle; andernfalls gib einen Bereich an und markiere ihn als Annahme.
Verwende dann die Zahlen, um Pattern auszuschließen, nicht nur um sie zu rechtfertigen: "Bei 30 Schreibvorgängen/s ist eine Postgres-Tabelle mit Index in Ordnung; eine Warteschlange wird nicht für den Durchsatz benötigt, sondern nur, wenn wir Wiederholungen und Entkopplung vom E-Mail-Anbieter wollen."
Schritt 3 — Das aktuelle Design abbilden (Ist-Zustand)
Lies den Code, bevor du ihn beschreibst. Nenne reale Dateien, Module, Tabellen, Endpunkte, Jobs, Caches, Warteschlangen. Erfinde keine Komponenten.
- Welche Komponenten berührt das Feature? Zeichne den Datenfluss in einem kurzen
Textdiagramm (
Client → BFF → Service → Postgres,Ereignis → Warteschlange → Worker). - Wo ist der Zustand und wem gehört er (DB, Cache, Client-Store, URL)?
- Welche vorhandenen Primitive können wiederverwendet werden (eine Outbox-Tabelle, ein Job-Runner, ein
Query-Cache, ein WebSocket-Hub, eine gemeinsame
Pagination-Komponente)? - Hot Paths, bekannte Engpässe, bestehende SPOFs, aktuelle Limits (Ratenlimits, Seitengrößen, Timeouts), die das Feature erbt.
- Für eine Frontend-Aufgabe ist der Ist-Zustand immer noch ein System: Datenabrufschicht, Cache-
Richtlinie, Bundle-Grenzen, Echtzeittransport — siehe
references/frontend.md.
Schritt 4 — Das Zieldesign vorschlagen (Soll-Zustand)
Beginne mit der Absicht des Autors. Wenn sie solide ist, sag es und schärfe sie; wenn sie im Konflikt mit den Zahlen oder einem bekannten Fehlermodus steht, zeige den Konflikt mit seiner Konsequenz und biete die kleinste Änderung an, die ihn behebt. Der Autor entscheidet; deine Aufgabe ist es, den Kompromiss sichtbar zu machen.
- High-Level-Design als Textdiagramm, plus den API-Vertrag (Endpunkte / Ereignisse / Nachrichten mit Formen) und das Datenmodell (Tabellen, Schlüssel, Indizes, Aufbewahrung).
- Nenne für jede nicht-triviale Wahl das Pattern und die Alternative, die du
verworfen hast, mit dem Grund, der mit den Zahlen aus Schritt 2 zusammenhängt.
references/patterns.mdist der Katalog: Skalierung, Caching, Async/Warteschlangen, Datenspeicher und Konsistenz, API-Stile und Echtzeittransport, Ratenbegrenzung, ID-Generierung, Zuverlässigkeit, Beobachtbarkeit — jeweils mit "verwenden, wenn / vermeiden, wenn / Kompromisse". - Ordne das Feature einem kanonischen System zu, wenn eines passt ("Dies ist ein Benachrichtigungssystem: Warteschlange + kanalspezifische Worker + Deduplizierung", "Dies ist Newsfeed- Fan-Out", "Dies ist ein Ratenbegrenzer"). Der letzte Abschnitt des Katalogs listet die kanonischen Formen und ihre Standardbausteine auf. Die Analogie gibt dem Leser einen bekannten Referenzpunkt und eine Checkliste dessen, was solche Systeme normalerweise benötigen.
- Bevorzuge die vorhandenen Primitive des Repos und das einfachste Design, das die Zahlen mit ausreichender Reserve erfüllt. Sage explizit, welche Upgrades aufgeschoben werden und welches Signal sie auslösen würde ("Füge ein Read-Replica hinzu, wenn das p95 dieser Query 200 ms überschreitet oder die Tabelle 50 Mio. Zeilen überschreitet").
Schritt 5 — Deep Dive in das, was kaputtgehen kann
Wähle für L2 die ein oder zwei riskantesten Teile; für L3 gehe alle durch. Standardfragen in grober Reihenfolge, wie oft sie beißen:
- Parallelität & Idempotenz — Doppelte Übermittlung, Wiederholungen, zwei Schreiber, At-Least-Once-Zustellung. Wo ist der Idempotenzschlüssel? Was ist die eindeutige Einschränkung?
- Konsistenz — Wer liest veraltete Daten und wie lange; ist das akzeptabel; Cache-Invalidierungspfad; Read-Your-Own-Writes.
- Fehler einer Abhängigkeit — Anbieter ausgefallen, Warteschlange hinkt hinterher, Remote-Modul kann nicht geladen werden. Timeouts, Wiederholungen mit Jitter, Circuit Breaker, Graceful Degradation, was der Benutzer sieht.
- Hot Spots — Hot Keys, Star-Mandanten, unbegrenzte Listen, N+1, Full-Table-Scans, fehlender Index, Thundering Herd bei Cache-Ablauf.
- Wachstum — Die Tabelle/Liste/Warteschlange, die unbegrenzt wächst; Aufbewahrung, Archivierung, Paginierung (Cursor statt Offset), Partitionierung.
- Migration & Rollout — Backfill, Dual-Write-Zeitraum, Feature-Flag, Rollback-Pfad, rückwärtskompatible Vertragsänderungen.
- Sicherheit & Datenschutz — Autorisierung auf Datenebene (Mandantenisolierung), PII in Logs/Warteschlangen, Ratenbegrenzung auf öffentlichen Endpunkten, Eingabevalidierung.
- Beobachtbarkeit — Welche Metrik beweist, dass es funktioniert (SLI), welcher Alarm schlägt an, wenn es das nicht tut, was zu loggen ist, um eine einzelne Anfrage zu debuggen.
Schritt 6 — Zusammenfassen, Visualisierung anbieten
Diagramme kosten Tokens, also sind sie opt-in. Das Briefing selbst verwendet nur
einzeilige Textflüsse (Client → API → Postgres).
Beende für L2 und L3 das Briefing mit einer Frage zusammen mit den offenen Fragen in der Sprache des Benutzers:
Architektur zeichnen? 1 — Ist-/Soll-Diagramm im Terminal · 2 — plus Design-Ordner (Mermaid +
architecture.html) · 3 — nein
- Zeichne nur, nachdem der Benutzer 1 oder 2 gewählt hat, gemäß
references/visualization.md. Warte nicht auf die Antwort, um mit der Implementierung zu beginnen; wenn der Benutzer weitermacht, ohne zu antworten, ist es ein "Nein". - Überspringe die Frage und zeichne nur dann sofort, wenn der Benutzer bereits nach einem Diagramm, einem Bild, einer Visualisierung oder dem Design-Ordner gefragt hat.
- Wenn niemand antworten kann (ein nicht-interaktiver Durchlauf, CI, ein Eval), zeichne nicht und frage nicht; erwähne in einer Zeile, dass Diagramme auf Anfrage verfügbar sind.
- Biete es niemals für L0 oder L1 an.
Erstelle das Briefing (nächster Abschnitt), dann fahre mit der Aufgabe fort: implementiere gemäß dem Briefing, behalte das Briefing auch in der PR-/MR-Beschreibung und liste offene Fragen für den Autor auf, anstatt sie stillschweigend zu entscheiden.
3. Urteilsregeln
- Zahlen vor Patterns. Empfehle niemals Kafka, Sharding, CQRS, einen dedizierten Cache-Cluster oder Microservices ohne eine Schätzung, die sie benötigt. Einfachheit ist ein Feature; Komplexität muss sich ihren Platz verdienen.
- Erklären, nicht belehren. Jede Empfehlung bringt ein einziges "weil" mit sich, das der Autor überprüfen kann. Analogien zu kanonischen Systemen sind willkommen; Buzzword-Listen sind es nicht.
- Respektiere das Design des Autors. Präsentiere Meinungsverschiedenheiten als "X wird Y bei Z-Last verursachen; die billigste Lösung ist W". Wenn der Autor immer noch seinen Weg bevorzugt, implementiere seinen Weg und notiere das Risiko im Briefing.
- Bestehender Code ist Beweis. Lese ihn. Ein Briefing, das Komponenten beschreibt, die nicht existieren, ist schlimmer als kein Briefing.
- Trenne Muss von Kann. Markiere jede Empfehlung als "jetzt benötigt", "vor dem Start benötigt" oder "bei ~N Benutzern benötigt".
- Frontend zählt. Client-Caching, Paginierung, optimistische Updates,
Echtzeittransport, Bundle-Grenzen und Fehlerisolierung sind Systemdesign;
references/frontend.mddeckt die clientseitige Version jedes Schritts ab. - Bleibe in der Sprache und dem Wortschatz des Benutzers. Übersetze Pattern-Namen, wenn das Team es tut; behalte den englischen Begriff beim ersten Mal in Klammern.
4. Das Design-Briefing
Verwende diese Struktur für L2 und L3. Behalte die Überschriften; lasse einen Abschnitt nur dann weg, wenn er
wirklich leer ist, und sage es in einem Satz. Ziel ist eine Seite für L2.
references/brief-template.md enthält ein ausgefülltes Beispiel und die kompakte L1-Form.
# Design-Briefing: <Feature>
**Tiefe:** L2 · **Status:** Vorschlag · **Absicht des Autors:** <eine Zeile>
## 1. Umfang
Funktional: ...
Nicht-funktional (sofern nicht anders angegeben, abgeleitet): Skalierung · Latenz · Verfügbarkeit · Konsistenz · Sicherheit · Kosten
Außerhalb des Rahmens: ...
Annahmen: ...
## 2. Schätzungen
| Metrik | Jetzt | +12 Monate | Quelle |
| --- | --- | --- | --- |
| DAU / Mandanten | | | |
| Spitzen-QPS (Lesen / Schreiben) | | | |
| Speicherwachstum | | | |
Fazit: <was die Zahlen erlauben / verbieten>
## 3. Aktuelles Design (Ist-Zustand)
<einzeiliger Textfluss> · Zustandsbesitz · wiederverwendbare Primitive · geerbte Limits
Dateien: ...
## 4. Zieldesign (Soll-Zustand)
<einzeiliger Textfluss> · API-Vertrag · Datenmodell · kanonische System-Analogie
Pattern-Wahl: <Pattern> — weil <Grund>; <Alternative> verworfen, weil <Grund>.
## 5. Risiken und Deep Dives
1. <Risiko> → Absicherung (jetzt benötigt / vor dem Start / bei N)
...
## 6. Rollout, Migration, Beobachtbarkeit
Flags, Backfill, Rollback · SLI + Alarm · was zu loggen ist
## 7. Offene Fragen an den Autor
- ...
- Architektur zeichnen? 1 — Terminal-Diagramm · 2 — plus Design-Ordner · 3 — nein
## 8. Implementierungsplan
Schritte in Reihenfolge, jeder klein genug zum Reviewen.
5. Referenzen — was wann zu lesen ist
| Datei | Lesen, wenn |
|---|---|
references/framework.md | Erster L2+-Durchlauf in einer Sitzung: Fragenchecklisten pro Schritt, NFR-Liste, wie man die Absicht des Autors extrahiert, Analyse-Anti-Pattern. |
references/estimation.md | Immer, wenn du eine Zahl brauchst: Latenzleiter, Neunen, Kapazitäten pro Knoten, QPS-/Speicher-Mathematik, durchgerechnete Beispiele. |
references/patterns.md | Auswählen oder Rechtfertigen eines Patterns; Zuordnen eines Features zu einem kanonischen System (Chat, Feed, Benachrichtigungen, Such-Autovervollständigung, Dateisynchronisation, Ratenbegrenzer, KV-Speicher, ID-Generator, Zahlungen, ...). Hat ein Inhaltsverzeichnis. |
references/frontend.md | Die Aufgabe ist eine UI-/SPA-/Micro-Frontend-Änderung: Datenabruf-Cache, Paginierung, Echtzeit, Bundle-Grenzen, Fehlerisolierung, clientseitige Zahlen. |
references/brief-template.md | Schreiben des Briefings: vollständiges L2-Beispiel und die kompakte L1-Inline-Form. |
references/visualization.md | Nur nachdem der Benutzer nach Diagrammen gefragt hat (Schritt 6). Zeichnen: Terminal-Box-Diagramm-Regeln, Mermaid-Konventionen, Design-Ordner-Layout, wie man assets/architecture.html füllt. |