Zum Inhalt springen

Architekturentscheide festhalten

Auftrag

Die neue Freiwillige fragt, warum die App Pinia verwendet, warum die Kurs-API über einen Proxy läuft und warum das Formular beim Verlassen nicht mehr nachfragt. Der Freiwillige kennt nicht mehr alle Gründe, und Martina Hostettler kennt keinen davon.

Als Vorstand möchte ich, dass jeder wichtige Entscheid zur App mit seinen Gründen festgehalten ist, damit neue Freiwillige ihn verstehen und wir ihn später bewusst ändern können.

Die Akzeptanzkriterien lauten:

  1. Jeder wichtige Entscheid steht als kurzer Text mit Kontext, Entscheid und Konsequenzen im Repository.
  2. Ein Entscheid, der nicht mehr gilt, bleibt stehen und verweist auf den neuen.
  3. Ein Verzeichnis listet alle Entscheide mit ihrem Status.

Lernziele

Nach diesem Kapitel kannst du

  • erklären, wozu Architekturentscheide dienen,
  • einen Entscheid mit Status, Kontext, Entscheid und Konsequenzen festhalten,
  • einen Entscheid durch einen neuen ersetzen, ohne ihn zu löschen,
  • Optionen abwägen und festhalten,
  • erkennen, welche Entscheide ein eigenes Dokument verdienen.

Der Code zeigt, was eine App tut, aber nicht, warum sie es so tut. Michael Nygard hat dafür 2011 Architecture Decision Records vorgeschlagen, kurz ADR. Ein ADR hält einen einzelnen Entscheid fest, der die Struktur, Eigenschaften wie Leistung oder Sicherheit, Abhängigkeiten, Schnittstellen oder die Bauweise einer Software prägt. Es umfasst eine bis zwei Seiten und richtet sich an jemanden, der später an der Software arbeitet und die Gründe nicht kennt.

Nygard schlägt wenige Teile vor. Der Titel ist eine kurze Nominalphrase. Der Kontext beschreibt sachlich, welche Kräfte wirken. Der Entscheid steht in ganzen Sätzen und im Aktiv. Der Status sagt, ob der Entscheid gilt, und die Konsequenzen nennen alle Folgen, gute, schlechte und neutrale. Die Fallbeispiel-App hält ihre Entscheide in diesem Aufbau fest.

0003-shared-state-with-pinia.md
# 3. Geteilter Zustand mit Pinia
## Status
Angenommen in Teil 7, nachträglich festgehalten in Teil 8.
## Kontext
Kopf, Katalog, Guard und Formular brauchen die Anmeldung, die Favoriten und die Anfragen. `App` hat sie mit `provide` bereitgestellt, und jede neue Seite brauchte wieder einen Teil davon. Ein Modul mit `ref` hätte gereicht, zeigt seine Änderungen aber nicht in den Entwicklertools und lässt sich in Tests schwerer vorbereiten.
## Entscheid
Die App hält geteilten Zustand in Setup Stores von Pinia, je einen für Katalog, Anmeldung, Favoriten und Anfragen. Zustand, den nur eine Komponente braucht, bleibt in der Komponente, und der Filter bleibt in der Adresse.
## Konsequenzen
Die Vue DevTools zeigen die Stores, und Tests starten mit einem frischen Pinia. Die App hängt von einem weiteren Paket ab. Wer einen Store zerlegt, braucht `storeToRefs`, sonst gehen die Verbindungen verloren.

Der Kontext nennt auch, was gegen Pinia sprach, und die Konsequenzen nennen die zusätzliche Abhängigkeit. Gerade diese Sätze helfen später, wenn jemand den Entscheid überdenkt.

Jedes ADR bekommt die nächste Nummer, und eine Nummer wird nie ein zweites Mal vergeben. Ein neuer Entscheid beginnt als vorgeschlagen und wird angenommen oder abgelehnt. Ein angenommener Entscheid kann später veralten oder durch einen neuen ersetzt werden.

Der Status eines Architekturentscheids Ein Zustandsdiagramm. Ein Entscheid beginnt als vorgeschlagen und wird angenommen oder abgelehnt. Ein angenommener Entscheid kann später veralten oder durch einen neuen Entscheid ersetzt werden, der auf ihn verweist. Gelöscht wird kein Entscheid, er behält seine Nummer und bleibt im Verzeichnis. Vorgeschlagen Angenommen Abgelehnt Veraltet Ersetzt durch ADR n Kein Entscheid wird gelöscht, die Nummer bleibt.

In Teil 6 hat die App vor dem Verlassen eines halb ausgefüllten Formulars nachgefragt, in Teil 7 hat ein Entwurf im sessionStorage diese Rückfrage abgelöst. Der alte Entscheid bleibt stehen und verweist auf den neuen.

0002-warning-before-leaving.md
# 2. Rückfrage beim Verlassen eines Formulars
## Status
Ersetzt durch [ADR 5](0005-draft-in-session-storage.md).

Der neue Entscheid nennt den alten in seinem Status.

0005-draft-in-session-storage.md
# 5. Entwurf einer Anfrage im sessionStorage
## Status
Angenommen in Teil 7, nachträglich festgehalten in Teil 8. Ersetzt [ADR 2](0002-warning-before-leaving.md).

Wer später fragt, warum die App nicht mehr nachfragt, findet beide Gründe, den für die Rückfrage und den für ihren Ersatz.

War die Wahl nicht offensichtlich, lohnt sich ein Abschnitt mit den Optionen, die zur Wahl standen. Die Vorlage MADR, in Version 4.0.0 von 2024, sieht dafür «Considered Options» vor und auf Wunsch Vor- und Nachteile jeder Option. Der Entscheid sagt dann, welche Option gewählt wurde und warum die anderen nicht.

ADRs gehören ins Repository, neben den Code, den sie erklären. Nygard schlug doc/arch/adr-NNN.md vor, MADR legt sie in docs/decisions ab, und die Fallbeispiel-App in docs/adr mit einer Datei README.md, die alle Entscheide mit ihrem Status auflistet. Auch Verwaltungen arbeiten damit, die britische Regierung hat 2025 ein Rahmenwerk für ADRs für den öffentlichen Sektor veröffentlicht.

Ein ADR verdient, was schwer rückgängig zu machen ist oder was eine neue Person überraschen würde, etwa das Framework, die Ordnung der Dateien, der Ort des Zustands, die Datenquelle, die Art der History im Router oder der Ort der Veröffentlichung. Namen von Variablen oder die Farbe eines Knopfs verdienen keins.

Dein README enthält laut Projektauftrag die wichtigen Entscheide als kurze Architekturentscheide. Der Mindestumfang verlangt globalen Zustand für einen sinnvollen Bereich oder einen begründeten Verzicht darauf als Architekturentscheid. Halte einen Entscheid fest, sobald du ihn triffst, die Gründe kennst du dann noch. Die README-Vorlage enthält ein Beispiel.

Arbeite mit den Entscheiden der Fallbeispiel-App im Kursrepo im Ordner case/08-architecture/de/docs/adr. Lies zuerst, bevor du etwas schreibst.

  1. Lies ADR 3. Welcher Satz im Kontext würde dir am meisten fehlen, wenn er nicht dastünde?
  2. Vergleiche ADR 2 und ADR 5. Was bleibt von ADR 2 übrig, und warum lohnt es sich, ihn zu behalten?
  3. Die Anmeldung mit einem Cookie mit HttpOnly aus Kapitel 7.4 hat noch kein ADR. Schreib in zwei Sätzen seinen Kontext.
  4. Welche dieser Entscheide verdienen ein ADR? Die Farbe der Kopfzeile, Pinia für den Zustand, die Sortierung nach Name als Vorgabe, der Hash-Modus für die Demo.

Die Aufgaben halten Entscheide zu den Favoriten und zur Suche fest. Du findest das Projekt im Kursrepo im Ordner exercises/08-architecture/adr/de. Die Entscheide schreibst du in docs/adr, template.md zeigt den Aufbau, und ADR 1 dient als Beispiel. Die Tests prüfen Aufbau, Status und Verweise, nicht den Inhalt.

Terminal-Fenster
npm install
npm test

Aufgabe Einstieg

Mitglieder verlieren ihre Favoriten, sobald sie die Seite neu laden, und der Verein hat keinen Server, der sie speichern könnte. Die App speichert sie darum im localStorage. Halte diesen Entscheid als ADR 2 «Favoriten im localStorage» mit den Abschnitten Status, Kontext, Entscheid und Konsequenzen fest, in ganzen Sätzen, und trag ihn ins Verzeichnis docs/adr/README.md ein.

Lösung
0002-favorites-in-local-storage.md
# 2. Favoriten im localStorage
## Status
Ersetzt durch [ADR 3](0003-favorites-on-the-server.md)
## Kontext
Mitglieder markieren Dinge als Favoriten und verlieren sie, sobald sie die Seite neu laden. Der Verein hat keinen Server, der die Favoriten speichern könnte.
## Entscheid
Die App speichert die Nummern der Favoriten als JSON im localStorage unter dem Schlüssel `lorraine-commons-favorites` und liest sie beim Start wieder.
## Konsequenzen
Die Favoriten überstehen das Neuladen und gelten in allen Tabs. Auf einem anderen Gerät fehlen sie, und wer die Daten des Browsers löscht, verliert sie.

Der Status lautet in deiner Fassung «Angenommen». Die Lösung zeigt schon den Status nach der Vertiefung.

Aufgabe Vertiefung

Mitglieder wollen ihre Favoriten auch am Tresen und auf dem Handy sehen. Die API des Vereins soll sie für angemeldete Mitglieder speichern. Halte das als ADR 3 «Favoriten auf dem Server» fest, das ADR 2 ersetzt. ADR 2 bleibt stehen, sein Status lautet «Ersetzt durch» mit einem Link auf ADR 3, und ADR 3 nennt in seinem Status ADR 2 mit einem Link. Pass das Verzeichnis an.

Lösung
0003-favorites-on-the-server.md
# 3. Favoriten auf dem Server
## Status
Angenommen, ersetzt [ADR 2](0002-favorites-in-local-storage.md)
## Kontext
Mitglieder wollen ihre Favoriten am Tresen und auf dem Handy sehen, nicht nur im Browser, in dem sie sie markiert haben. Die API des Vereins kennt angemeldete Mitglieder.
## Entscheid
Die API speichert die Favoriten angemeldeter Mitglieder. Ohne Anmeldung bleiben die Favoriten im localStorage, und nach der Anmeldung schickt die App sie einmal an die API.
## Konsequenzen
Favoriten folgen einem Mitglied auf jedes Gerät. Die App braucht zwei Wege für Favoriten und eine Regel, wenn beide verschiedene Listen haben, und jede Markierung wird zu einer Anfrage an den Server.
README.md
# Architekturentscheide
| Nummer | Entscheid | Status |
|---|---|---|
| 1 | [Entscheide festhalten](0001-record-decisions.md) | Angenommen |
| 2 | [Favoriten im localStorage](0002-favorites-in-local-storage.md) | Ersetzt durch ADR 3 |
| 3 | [Favoriten auf dem Server](0003-favorites-on-the-server.md) | Angenommen |
| 4 | [Der Suchtext ohne Store](0004-search-text-without-a-store.md) | Vorgeschlagen |

Aufgabe Knobelei

Eine neue Freiwillige schlägt vor, den Suchtext in einen Store zu legen. Halte das als ADR 4 mit dem Status «Vorgeschlagen» fest. Zwischen Kontext und Entscheid steht ein Abschnitt «Optionen» mit mindestens zwei Optionen als Liste, und der Entscheid sagt, welche Option du vorschlägst und warum.

Lösung
0004-search-text-without-a-store.md
# 4. Der Suchtext ohne Store
## Status
Vorgeschlagen
## Kontext
Eine neue Freiwillige schlägt vor, den Suchtext in einen Store zu legen, wie Anmeldung und Favoriten. Nur der Katalog braucht den Suchtext, aber Mitglieder schicken einander Links auf Suchen.
## Optionen
- Ein Store mit Pinia, wie für die Favoriten
- Ein `ref` in der Seite des Katalogs
- Die Query in der Adresse, etwa `?q=säge`
## Entscheid
Der Suchtext lebt in der Query der Adresse. Ein Store bringt nichts, weil nur eine Seite den Text braucht, und ein `ref` ginge beim Teilen eines Links verloren.
## Konsequenzen
Ein Link zeigt dieselbe Suche, und der Zurück-Knopf stellt sie wieder her. Die Seite muss den Text aus der Adresse lesen und Änderungen mit einer Pause hineinschreiben.

Ein Vorschlag wird erst nach einer Besprechung angenommen oder abgelehnt. Bis dahin hält das ADR fest, worüber das Team entscheidet.

FehlerWas hilft
Ein ADR beschreibt, was gebaut wurde, aber nicht warum.Im Kontext die Kräfte nennen, die zum Entscheid geführt haben.
Ein überholter Entscheid wird gelöscht oder überschrieben.Stehen lassen, den Status auf «Ersetzt durch» mit einem Link setzen und im neuen ADR auf den alten verweisen.
Die Konsequenzen nennen nur Vorteile.Auch Nachteile und offene Punkte nennen, sie helfen bei späteren Entscheiden.
Jede Kleinigkeit bekommt ein ADR.Nur Entscheide festhalten, die schwer rückgängig zu machen sind oder Neue überraschen würden.
Ein KI-Assistent schreibt ein ADR mit Gründen, die im Projekt nie eine Rolle spielten.Kontext und Gründe kommen von dir. Prüf jeden Satz gegen das, was im Projekt wirklich passiert ist.

Selbstcheck

  1. Welche Teile hat ein ADR nach Nygard?
  2. Warum bleibt ein ersetzter Entscheid stehen?
  3. Wann lohnt sich ein Abschnitt mit Optionen?
  4. Nenne zwei Entscheide in deinem Projekt, die ein ADR verdienen.
Antworten
  1. Titel, Kontext, Entscheid, Status und Konsequenzen.
  2. Er erklärt, warum die App früher anders war, und der neue Entscheid baut auf seinen Gründen auf. Die Nummer bleibt eindeutig.
  3. Wenn mehrere Lösungen in Frage kamen und die Wahl nicht offensichtlich war.
  4. Etwa das Framework, die Datenquelle, der Ort des Zustands oder der Ort der Veröffentlichung.

Auftrag

Die Entscheide der App stehen jetzt in docs/adr, und die neue Freiwillige liest dort nach. Kurz darauf meldet Martina Hostettler einen alten Fehler. Nach einer Änderung an den Regeln nimmt die App wieder Anfragen an, deren erster Tag schon vorbei ist, obwohl das einmal behoben war. Das nächste Kapitel sorgt mit Tests dafür, dass ein solcher Fehler nicht ein drittes Mal zurückkommt.

Texte und Abbildungen stehen unter CC BY-SA 4.0, der Code unter der MIT-Lizenz und die Daten des Kurses unter CC0 1.0. Die Schrift der Abbildungen ist Kalam unter der SIL Open Font License 1.1. Die Quellen liegen auf GitHub.