RFCs und ADRs: Architekturentscheidungen dokumentieren

Datum
Kategorie
  • engineering

Jedes Engineering-Team trifft Architekturentscheidungen. Nur wenige schreiben sie auf.

Genau diese Lücke ist die Quelle der meisten langfristigen Schmerzen in einer Codebasis. Sechs Monate nach einer Entscheidung weiß niemand mehr, warum das Team die eine Message-Queue der anderen vorgezogen hat, welche Alternativen verworfen wurden oder auf welchen Kompromiss man sich geeinigt hatte. Die Entscheidung prägt das System weiterhin jeden Tag — nur eben unsichtbar, und jeder neue Entwickler muss sich die Begründung aus dem Code zurückkonstruieren.

Zwei schlanke Dokumente lösen das meiste davon: das RFC (Request for Comments) und das ADR (Architecture Decision Record). Das ist kein schwergewichtiger Prozess. Gut geschrieben passt jedes auf ein oder zwei Bildschirmseiten, und zusammen verwandeln sie „Wissen in den Köpfen“ in etwas, das ein Neuzugang an einem Nachmittag lesen kann.

Ich habe mich auf beide stark gestützt, als ich ein horizontales Core-Team bei einer großen europäischen Streaming-Plattform geleitet habe — das Team, das für die Architekturverträge zwischen den Produkt-Squads verantwortlich war. Die folgenden Konventionen sind die, die ich dort verfeinert habe und heute als kleines Set von Skills in jedem Projekt nutze. So funktioniert jedes Dokument — und so schreibt man eines, das tatsächlich lesenswert ist.

Zuerst: Entscheide, was du schreibst

Bevor du eine leere Seite öffnest, beantworte eine Frage: Entscheidest du noch, oder hast du bereits entschieden?

Diese eine Unterscheidung treibt alles Weitere:

RFCs sind zum Diskutieren. ADRs sind zum Festhalten.

Ein RFC ist ein lebendiges Dokument. Es existiert, während eine Entscheidung debattiert wird. Es darf lang, explorativ und voller Alternativen sein — seine Aufgabe ist es, gute Diskussion zu provozieren und Konsens herzustellen. Ein ADR ist ein unveränderlicher Eintrag. Es existiert, nachdem die Entscheidung gefallen ist. Es muss kurz, klar und entschieden sein — seine Aufgabe ist es, festzuhalten, was entschieden wurde und warum. Für immer.

Das ist der Entscheidungsbaum, den ich durchgehe, wenn ich unsicher bin:

  1. Hast du überhaupt eine Entscheidung zu dokumentieren? Wenn nicht, halt an — du brauchst noch kein Dokument.
  2. Gibt es bereits eine empfohlene Standardlösung dafür?
    • Ja, und sie ist dokumentiert → verweise auf das bestehende ADR. Fertig.
    • Ja, aber niemand hat sie aufgeschrieben → schreibe ein ADR, um sie nachzutragen.
  3. Es gibt noch keinen Standard. Hast du eine vorgeschlagene Lösung? Wenn nicht, ist es zu früh — recherchiere erst.
  4. Ist das eine große oder brechende Änderung? Also: das Brechen einer bestehenden API, das Ersetzen eines Kern-Frameworks, alles, was Teamgrenzen überschreitet oder einen unternehmensweiten Standard verändert.
    • Groß oder brechend → schreibe zuerst ein RFC, dann ein ADR, sobald sich der Staub gelegt hat.
    • Klein und risikoarm (eine Bibliothek innerhalb eines Teams einführen, ein bereits entstehendes Muster festschreiben) → überspring das RFC und schreibe direkt ein ADR.
Situation Was schreiben
Bestehende Lösung, nie dokumentiert ADR (Nachtrag)
Neues Problem, kleine / risikoarme Änderung ADR
Neues Problem, große / brechende Änderung RFC → dann ADR
Eine formale Prozess- oder Standardänderung RFC → dann ADR

Das Beruhigende daran: Sobald ein RFC Konsens erreicht hat, ist das Schreiben des ADR fast mechanisch. Das schwere Nachdenken ist erledigt — du hältst nur noch das Ergebnis im kanonischen Format fest.

Ein RFC schreiben

Ein RFC schlägt eine Lösung für ein Problem vor und lädt das Team ein, sie zu hinterfragen. Du schreibst eines, wenn die Änderung groß genug ist, dass du vor der Umsetzung Zustimmung brauchst — und wenn es noch keine etablierte Antwort gibt.

Gib ihm einen Titel, der eine Frage stellt

Ein guter RFC-Titel rahmt ein Problem oder eine Wahl. Er soll keine Entscheidung verkünden — die kommt später. Ich nutze ein strukturiertes Schema, damit jeder Titel sofort erkennbar und durchsuchbar ist:

RFC(<DOMAIN>-<NUMMER>): [<KONTEXT>] <Titel>
  • Domain (optional): der zuständige Bereich — Backend, Frontend, Infra, Video, Data. Weglassen, wenn die Änderung alles betrifft.
  • Nummer: eine eindeutige fünfstellige ID, damit das Dokument einen stabilen Anker hat.
  • Kontext (optional): eine Plattform oder Teil-Scope in Klammern, etwa [Web] oder [Android].
  • Titel: ein Problem, eine Frage oder eine Liste von Optionen.

Gute RFC-Titel lesen sich wie offene Fragen:

  • RFC(INFRA-00123): Sollten wir ECS oder EKS für unsere containerisierten Anwendungen nutzen?
  • RFC(DATA-00456): Welche Recommendation-Engine — Personalize, TurboPerso oder MagicTree?

Beginne mit dem Problem, nicht mit der Lösung

Der größte Fehler in RFCs ist, mit der vorgeschlagenen Lösung zu beginnen. Leser interessiert deine Lösung nicht, solange sie das Problem nicht spüren. Ein starkes RFC bewegt sich daher in dieser Reihenfolge:

  • Überblick — zwei, drei Sätze, damit ein Leser in 30 Sekunden entscheiden kann, ob ihn das betrifft. Schreib ihn zuletzt.
  • Ziele und Nicht-Ziele — was du erreichen willst, und ebenso wichtig, was du nicht angehst. Explizite Nicht-Ziele verhindern, dass eine Diskussion ausufert.
  • Hintergrund und Motivation — warum dieses Problem jetzt existiert, belegt mit Evidenz: Metriken, Incident-Reports, Benchmarks. „Jeder weiß, dass unser Setup chaotisch ist“ lässt sich abtun; „wir betreiben vier verschiedene HTTP-Client-Bibliotheken mit jeweils eigener Fehlerbehandlung“ nicht.
  • Vorgeschlagene Lösung — konkret, mit der Funktionsweise und wie du Erfolg misst.
  • Betrachtete Alternativen — eine kurze Tabelle der Optionen, die du untersucht und verworfen hast, mit Begründung. Diesen Teil überspringt man gern, und er ist der wertvollste: Er verhindert, dass die Diskussion bereits durchdachte Sackgassen neu aufrollt.
  • Schwierigkeiten, Risiken, Rollback — die erwarteten Störungen, die Dinge, die vielleicht schiefgehen, und wie du zurückrudern würdest, wenn es scheitert. Ein benanntes, ungelöstes Problem ist besser als ein verstecktes.

Ein Framing-Kniff, der zuverlässig funktioniert: Nutze Angst, wenn du ein schädliches Verhalten stoppen willst (was bricht, wenn wir uns nicht ändern?), und Hoffnung, wenn du ein neues einführen willst (was wird besser, wenn wir es tun?). Passe die Emotion an die Bitte an.

Durchlaufe seinen Lebenszyklus

Ein RFC lebt, und sein Status zeigt, wo es steht:

DRAFT → DISCUSSING → FINISHED (→ ADR geschrieben)
                   → ABANDONED

Du entwirfst es, setzt es auf DISCUSSING mit einem Zieldatum und verteilst es — an dein Team, an alle Betroffenen und an einen unternehmensweiten RFC-Kanal für breite Sichtbarkeit. Dann beteiligst du dich wirklich: Kommentare einarbeiten, das Dokument aktualisieren, Einwände beantworten. Wenn Konsens entsteht, setzt du es auf FINISHED und schreibst das ADR, das die Entscheidung festhält. Führt es zu nichts, setzt du es auf ABANDONED mit einem Satz zur Begründung — eine dokumentierte Sackgasse ist immer noch ein Geschenk an den Nächsten, der dieselbe Idee erwägt.

Ein ADR schreiben

Wenn das RFC die Debatte ist, ist das ADR das Urteil. Es dokumentiert, was entschieden wurde, warum und was daraus folgt — und nicht mehr. Es ist bewusst kurz: Wenn dein ADR länger als eine Bildschirmseite wird, schreibst du wahrscheinlich versehentlich ein RFC.

Die Entscheidungsformel

Jedes ADR dreht sich um einen Satz, geschrieben nach einer festen Formel:

Im Kontext von [Situation oder Einschränkung], um unserem Bedarf [Ziel] gerecht zu werden, nutzen wir [Lösung].

Zum Beispiel:

Im Kontext unserer containerisierten Microservice-Architektur und des Bedarfs, den operativen Aufwand der eigenen Cluster-Verwaltung zu senken, nutzen wir einen verwalteten Kubernetes-Dienst zum Hosten unserer containerisierten Anwendungen.

Diese Formel zwingt die drei entscheidenden Dinge — Kontext, Bedarf und Entscheidung — in eine einzige, zitierfähige Zeile. Alles andere im Dokument stützt nur sie.

Formuliere den Titel als Aussage

Wo ein RFC-Titel eine Frage stellt, beantwortet ein ADR-Titel sie. Schon der Titel allein sollte sagen, was zu tun ist:

ADR(<DOMAIN>-<NUMMER>): [<KONTEXT>] <Entscheidung>
  • ADR(INFRA-00123): Wir nutzen EKS zum Hosten unserer containerisierten Anwendungen
  • ADR(BACK-00013): Symfony ist das Framework für neue PHP-Services
  • ADR(FRONT-00789): [Web] React ist unser Frontend-Framework

Sei ehrlich über die Konsequenzen

Der Abschnitt, der einem ADR sein Vertrauen verdient, sind die Konsequenzen — und sie müssen in beide Richtungen schneiden. Liste die Vorteile, ja — aber ebenso die Kompromisse und die neuen Verpflichtungen, die die Entscheidung schafft („alle neuen Services müssen bis zum nächsten Quartal migrieren“). Ein ADR, das nur Vorteile auflistet, liest sich wie Werbung, und man glaubt ihm nicht mehr. Jede echte Entscheidung kostet etwas; benenne es.

ADRs sind unveränderlich

Das ist die Regel, die am häufigsten gebrochen wird. Sobald ein ADR akzeptiert ist, bearbeitest du es nicht mehr. Ändert sich die Entscheidung, schreibst du ein neues ADR, das das alte ablöst, und markierst das alte als SUPERSEDED mit einem Link nach vorn. Der Eintrag, was du wann geglaubt hast, bleibt intakt.

DRAFT → PROPOSED → ACCEPTED
                 → REJECTED
ACCEPTED → SUPERSEDED (wenn ein neueres ADR es ablöst)

Ein paar Anti-Muster zum Vermeiden: Liste nicht die abgewogenen Optionen auf („wir haben A, B und C betrachtet…“) — das ist RFC-Inhalt. Lavier nicht herum („wir nutzen vielleicht X, je nachdem…”) — ein ADR ist eine Entscheidung, kein Vielleicht. Und wenn Unterabschnitte wuchern, tritt zurück und frag dich, ob du in Wahrheit ein RFC schreibst.

Prüfen, bevor du teilst

Ein Entwurf ist nicht fertig, nur weil er geschrieben ist. Bevor ein RFC in die Diskussion geht oder ein ADR zur Freigabe ansteht, lass es bewusst eine Prüfung durchlaufen. Ich bewerte jedes Dokument auf drei Dimensionen:

  • Klarheit — kann jemand außerhalb der Domäne folgen? Wenn ein Dokument nur für die drei Leute Sinn ergibt, die ohnehin im Raum sind, ist es als Eintrag gescheitert.
  • Vollständigkeit — sind alle tragenden Abschnitte vorhanden und gehaltvoll? Ein RFC ohne Alternativen ist ein Verkaufsgespräch. Ein ADR ohne Konsequenzen ist ein Wunsch.
  • Konformität — folgt es den Konventionen: Titelformat, gesetzter Status, Entscheidungsformel, die richtigen Labels?

Ich sortiere meine Funde in drei Eimer, damit der Autor weiß, was dringend ist:

  • Kritisch — muss vor dem Teilen behoben werden. Bei einem RFC: keine klare Problemstellung, keine vorgeschlagene Lösung, eine fehlende Eigenschaftentabelle. Bei einem ADR: eine Entscheidung, die sich wie eine Debatte liest, oder ein Titel, der die Entscheidung nicht benennt.
  • Wichtig — sollte behoben werden. Keine betrachteten Alternativen, Behauptungen ohne Evidenz oder ein Konsequenzen-Abschnitt, der nur die Vorteile auflistet.
  • Vorschlag — würde es stärken. Ein knapperer Überblick, definierte Erfolgsmetriken, benannte Stakeholder, die informiert bleiben sollen.

Der nützlichste Review-Zug ist schlicht, die problematische Zeile dem Autor zurückzuzitieren und zu erklären, warum sie einen Leser stolpern lässt. „Unsere Architektur ist chaotisch“ ist keine Problemstellung — „wir haben vier HTTP-Clients mit inkonsistenter Fehlerbehandlung“ schon. Konkret schlägt höflich.

Warum das wichtig ist

Nichts davon ist Bürokratie um ihrer selbst willen. Der ganze Sinn ist Geschwindigkeit, die hält. Wenn das Fundament dokumentiert ist — wenn ein neuer Entwickler nachlesen kann, warum jede wichtige Entscheidung getroffen wurde — bewegen sich Teams schnell und bleiben schnell. Wenn nicht, verlangsamen sie sich bis zum Stillstand, und niemand kann genau erklären, warum.

Ein RFC kostet dich einen Nachmittag Schreibarbeit und eine Woche Diskussion. Ein ADR kostet dich fünfzehn Minuten. Die Entscheidungen, die sie festhalten, prägen dein System über Jahre. Das ist ein außergewöhnlicher Tausch.

Das ist derselbe Maßstab, den ich an meine eigenen Produkte anlege — jede Architekturentscheidung in Transcriber, Migrate und e.Vernetzt ist eine, die ich erklären kann, weil ich sie aufgeschrieben habe, als ich sie traf. Wenn dein Team damit ringt, architektonische Integrität über eine wachsende Codebasis hinweg zu erhalten, bin ich immer offen für ein Gespräch. Erreichbar unter marcelo@binarieslab.com — der Kaffee geht auf mich.