Read in English · Leer en español · Lire en français
Abschnitt 11.3 von 11.8 · Fortgeschritten · 27 Min. Lesezeit
Fitness Functions und evolutionäre Architektur
Videolektion
5 Min. · auf Englisch gesprochen, mit UntertitelnNur anhören (Audio)
Transkript lesen
Eine Bewertung ist eine Momentaufnahme. Schon am Tag danach kann jede Änderung still eine Entscheidung aushebeln, auf der sie beruhte. In dieser Lektion lernen Sie, wie Fitness Functions diese Entscheidungen automatisch und kontinuierlich prüfen.
Das Armaturenbrett eines Autos hat Warnleuchten für alles, was nie unbemerkt schiefgehen darf: Öldruck, Motortemperatur, Bremsen. Sie warten nicht auf die jährliche Inspektion, um zu erfahren, dass der Motor im März überhitzt ist. Eine Fitness Function ist eine Warnleuchte für eine Softwarearchitektur. Das Team legt fest, welche Qualitäten wirklich zählen, etwa wie schnell eine Bestellung bestätigt wird, und schreibt für jede eine automatische Prüfung. Diese Prüfungen laufen bei jeder Änderung der Software. Schlägt eine fehl, wird die Änderung gestoppt oder jemand alarmiert, solange das Problem noch klein ist.
Der Begriff stammt aus dem Buch Building Evolutionary Architectures von Neal Ford und seinen Mitautoren. Eine Fitness Function ist jeder Mechanismus, der ein Architekturmerkmal objektiv bewertet. Jeder Mechanismus: ein Unit-Test, ein Lasttest, ein Monitor, ein Chaos-Experiment, sogar ein geplantes manuelles Review. Objektiv: Das Ergebnis darf nicht davon abhängen, wer sie ausführt. Das Gefühl, der Code sei gut strukturiert, zählt nicht. Und eine Metrik beschreibt, aber eine Fitness Function entscheidet. Wird sie gebrochen, erzwingt das eine bewusste Wahl: den Code korrigieren oder die Regel ändern und festhalten, warum.
So ist eine aufgebaut. Am Anfang steht ein Merkmal, etwa die Bestelllatenz, und eine Messung dafür: das fünfundneunzigste und das neunundneunzigste Perzentil bei hundert Bestellungen pro Sekunde. Der Schwellenwert kommt direkt aus dem Antwortmaß des Szenarios: anderthalb Sekunden und drei Sekunden. Die Prüfung ist ein Lasttest in der Pipeline, und die Aktion bei einer Überschreitung ist, den Build abzubrechen. Eine Fitness Function sollte laut fehlschlagen, nicht ein Dashboard füllen, das niemand liest. Darunter verweist sie auf ihr Quellszenario. Und sie hat einen Verantwortlichen, einen Review-Termin und eine Begründung, festgehalten in einem Architecture Decision Record, kurz ADR.
Fitness Functions laufen entlang der gesamten Delivery-Pipeline. Atomare Prüfungen testen ein Merkmal, holistische mehrere zusammen. Bei jedem Build laufen günstige, schnelle, atomare Prüfungen: Abhängigkeitsregeln, Zyklenprüfungen, Komplexitätslimits und Abhängigkeiten mit bekannten Schwachstellen. In der Teststufe folgen langsamere, holistische Prüfungen: ein Lasttest mit Perzentil-Schwellenwerten, Schema- und Contract-Prüfungen und ein Failover-Test. Beim Canary werden Fehlerrate und Latenz der neuen Version mit denen der alten verglichen. Und in Produktion laufen ständig kontinuierliche Prüfungen: Monitore für Service Level Objectives, kurz SLOs, synthetische Bestellungen, Chaos-Experimente und Kosten pro Bestellung. Ausfälle und Drift fließen als neue Arbeit zurück, oft auch als neue Fitness Functions.
Jetzt macht die Plattform aus drei Szenarien Fitness Functions. Erstens: Bei hundert Bestellungen pro Sekunde werden fünfundneunzig Prozent der Bestellungen innerhalb von anderthalb Sekunden bestätigt und neunundneunzig Prozent innerhalb von drei. Fitness Function eins ist ein Lasttest gegen eine produktionsnahe Umgebung, nächtlich und vor jedem Release. Sie schlägt fehl, wenn eines der Perzentile über seinem Schwellenwert liegt oder mehr als null Komma eins Prozent der Anfragen fehlschlagen. Die anderthalb Sekunden werden außerdem in Budgets für Netzwerk, Gateway, Bestellungen, Preisgestaltung und Datenbank-Schreibvorgänge aufgeteilt; es bleiben fünfhundertfünfzig Millisekunden Reserve. Jeder Service testet sein eigenes Budget, sodass eine Regression dort erkannt wird, wo sie entsteht. Szenario zwei ist die Verfügbarkeit des Checkouts. Jede Woche bringt ein Chaos-Experiment im Staging den Zahlungsanbieter zum Hängen. Bestellungen müssen trotzdem innerhalb von zehn Sekunden als ausstehend angenommen und nach der Wiederherstellung alle abgeschlossen werden. Szenario drei: Ein neuer Kassensystem-Anbieter soll fünf Personentage Arbeit kosten, durch einen einzigen zusätzlichen Adapter. Eine Build-Regel verhindert, dass Restaurant- und Bestellcode das Software-Kit eines Anbieters importieren, sodass die Änderung lokal bleibt. Jede wird mit ihrem Quellszenario, ihrem Schwellenwert, ihrem Verantwortlichen, dem erklärenden ADR und einem Review-Termin dokumentiert.
Fitness Functions sind die Hälfte dessen, was diese Autoren evolutionäre Architektur nennen: gelenkte, inkrementelle Änderung über mehrere Dimensionen. Kleine deploybare Teile und schnelle Pipelines liefern die Inkremente. Fitness Functions liefern die Lenkung. Beginnen Sie klein. Wählen Sie die drei bis fünf Merkmale, die der Utility Tree am höchsten bewertet, und schreiben Sie für jedes eine zuverlässige Prüfung. Ein Dutzend vertrauenswürdiger Prüfungen ist mehr wert als hundert, die zufällig fehlschlagen. Nutzen Sie bei einem bestehenden System eine Ratsche. Erfassen Sie die heutigen Verstöße als Baseline, lassen Sie nur neue scheitern und verschärfen Sie die Baseline, während die Schulden abgebaut werden. Und halten Sie die Pipeline schnell: atomare Prüfungen in jedem Build, schwere holistische Prüfungen wie zehnminütige Lasttests nächtlich oder vor dem Release.
Der vollständige Abschnitt behandelt die Dimensionen von Fitness Functions und den Code für alle drei Prüfungen. Als Nächstes geht es in Abschnitt elf Punkt vier um Governance in agilen Organisationen. Bis gleich.
Was Sie wissen müssen
- Eine architektonische Fitness Function ist jeder Mechanismus, der ein Architekturmerkmal objektiv bewertet, idealerweise automatisiert und rückverfolgbar auf ein Qualitätsszenario, dessen Antwortmaß zu ihrem Schwellenwert wird.
- Fitness Functions werden eingeteilt in atomar oder holistisch, ausgelöst, kontinuierlich oder zeitgesteuert, statisch oder dynamisch, automatisiert oder manuell sowie geplant oder emergent; ein gesunder Satz mischt sie.
- Typische Beispiele sind Abhängigkeitsregeln für die Struktur, Lasttests und Latenzbudgets für die Performance, Schwachstellenscans für die Sicherheit, Chaos-Experimente für die Resilienz und Prüfungen der Schemakompatibilität für Daten.
- Evolutionäre Architektur (Ford, Parsons, Kua und Sadalage) unterstützt gelenkte, inkrementelle Änderung über mehrere Dimensionen; Fitness Functions liefern die Lenkung, kleine deploybare Einheiten und Pipelines liefern die Inkremente.
- Jede Fitness Function braucht einen Verantwortlichen, eine dokumentierte Begründung und einen Schwellenwert, und ein Fehlschlag erzwingt eine Entscheidung: den Code korrigieren oder die Regel ändern und festhalten, warum.
- Beginnen Sie mit wenigen zuverlässigen Prüfungen für die Merkmale mit der höchsten Priorität, nutzen Sie Baselines, um bestehende Systeme schrittweise zu verschärfen, und halten Sie langsame holistische Prüfungen aus jedem einzelnen Build heraus.
Von der einmaligen Bewertung zur kontinuierlichen Prüfung
Eine Bewertung wie die ATAM (Abschnitt 11.1) ist eine Momentaufnahme. Am Tag nach ihrem Ende beginnen Entwickler, das System zu ändern, und jede Änderung kann still eine Entscheidung rückgängig machen, auf die sich die Bewertung gestützt hat: ein bequemer Import über eine Modulgrenze hinweg, ein zusätzlicher synchroner Aufruf auf dem Bestellpfad, eine Bibliothek mit einer bekannten Schwachstelle. Abschnitt 1.7 hat das Ergebnis beschrieben: Erosion, wenn die Architektur verletzt wird, und Drift, wenn sie ignoriert wird. Regelmäßige Reviews fangen einiges davon ab, Monate zu spät. Die Idee dieses Abschnitts ist, die wichtigsten Architekturentscheidungen automatisch und kontinuierlich zu prüfen, so wie Unit-Tests das Verhalten prüfen.
Der Begriff stammt aus Building Evolutionary Architectures (O’Reilly, 2017) von Neal Ford, Rebecca Parsons und Patrick Kua, dessen zweite Ausgabe, mit Pramod Sadalage, im November 2022 erschien. Sie haben ihn aus der evolutionären Informatik entlehnt, wo eine Fitness Function bewertet, wie nah eine Kandidatenlösung am Ziel ist, damit der Algorithmus die besseren Varianten behalten kann. In der Architektur ist das Ziel die Menge der Merkmale, die das System behalten muss, während sich alles andere ändert.
Was eine Fitness Function ist
Die zweite Ausgabe definiert eine architektonische Fitness Function als jeden Mechanismus, der eine objektive Integritätsbewertung eines oder mehrerer Architekturmerkmale liefert. Drei Wörter in dieser Definition tragen die Last. Jeder Mechanismus: Ein Unit-Test, eine Regel der statischen Analyse, ein Lasttest, ein Monitor, ein Chaos-Experiment oder sogar ein geplantes manuelles Review kommen alle infrage. Objektiv: Das Ergebnis darf nicht davon abhängen, wer die Prüfung ausführt; „der Code fühlt sich gut strukturiert an“ ist keine Fitness Function, „kein Paket in der Domänenschicht importiert das Web-Framework“ schon. Architekturmerkmal: Die Prüfung schützt eine Qualität, für die die Architektur da ist (Performance, Verfügbarkeit, Änderbarkeit, Sicherheit, Datenkompatibilität), keine Geschäftsregel; das ist die Aufgabe gewöhnlicher Tests.
In der Praxis hat eine nützliche Fitness Function noch einige weitere Eigenschaften. Sie ist auf eine Anforderung rückführbar, idealerweise auf ein Qualitätsszenario, dessen Antwortmaß zu ihrem Schwellenwert wird (Abschnitt 2.3). Sie hat einen Verantwortlichen, der entscheidet, was bei einem Fehlschlag passiert. Sie schlägt laut fehl, indem sie einen Build abbricht oder jemanden alarmiert, statt ein Dashboard zu füllen, das niemand liest. Und ihr Schwellenwert samt Begründung ist dokumentiert, meist in einem ADR, damit ein späteres Team eine Regel, die etwas Wichtiges schützt, von einer willkürlichen Zahl unterscheiden kann.
Abschnitt 3.8 hat die wichtige Abgrenzung zu Metriken gezogen: Eine Metrik beschreibt, eine Fitness Function entscheidet. Eine Kopplungsmetrik auf einem Dashboard zeigt Ihnen, dass es schlechter wird; eine Fitness Function kodiert eine Entscheidung, die das Team bereits getroffen hat, sodass ihr Bruch eine bewusste Wahl erzwingt: den Code korrigieren oder die Regel ändern und festhalten, warum.
Anatomie einer Fitness Function
Kategorien von Fitness Functions
Ford und seine Mitautoren ordnen Fitness Functions entlang mehrerer unabhängiger Dimensionen ein. Die Einteilung ist weniger als Taxonomie nützlich denn als Denkanstoß beim Entwurf: Die Frage „Sollte das atomar oder holistisch, ausgelöst oder kontinuierlich sein?“ führt oft zu einer besseren Prüfung als der, die einem zuerst eingefallen ist.
Dimensionen von Fitness Functions
| Dimension | Optionen | Was sie bedeutet | Beispiel |
|---|---|---|---|
| Bereich | Atomar oder holistisch | Atomar prüft ein Merkmal in einem Kontext; holistisch prüft mehrere Merkmale, die in einem gemeinsamen Kontext zusammenwirken | Atomar: keine Zyklen zwischen Paketen. Holistisch: Bestelllatenz, gemessen mit eingeschalteter Verschlüsselung, Audit-Logging und eingeschaltetem Caching |
| Wann sie läuft | Ausgelöst, kontinuierlich oder zeitgesteuert | Ausgelöst läuft bei einem Ereignis wie einem Commit, Build oder Deployment; kontinuierlich läuft ständig gegen das Live-System; zeitgesteuert schlägt nach Ablauf einer Frist an, als Erinnerung, etwas erneut zu prüfen | Ausgelöst: Abhängigkeitsscan bei jedem Build. Kontinuierlich: SLO-Burn-Rate-Alarm in Produktion. Zeitgesteuert: Build abbrechen, wenn eine fixierte Framework-Version älter als 12 Monate ist |
| Art des Ergebnisses | Statisch oder dynamisch | Statisch vergleicht mit einem festen Schwellenwert; dynamisch passt den Schwellenwert an den Kontext an, etwa an die Last | Statisch: p95 unter 1,5 s. Dynamisch: p95 darf über 150 Bestellungen/s auf 2 s steigen, wie für extreme Spitzen vereinbart |
| Wie sie ausgeführt wird | Automatisiert oder manuell | Automatisiert ist vorzuziehen; manche Merkmale, etwa rechtliche oder Usability-Anforderungen, brauchen weiterhin Menschen, idealerweise nach Zeitplan | Manuell: vierteljährliches Barrierefreiheits-Review gegen WCAG 2.2 AA |
| Planung | Geplant oder emergent | Geplante Prüfungen werden im Voraus aus bekannten Anforderungen entworfen; emergente kommen hinzu, während das Team lernt, was wichtig ist | Emergent: eine Prüfung auf Consumer-Lag, eingeführt nach einem Incident |
Holistische Prüfungen verdienen Aufmerksamkeit, weil Qualitäten zusammenwirken: Sicherheitsmaßnahmen kosten Latenz, Caching erschwert die Aktualität der Daten, und ein atomarer Test jeder einzelnen kann bestehen, während die Kombination scheitert. Kontinuierliche Prüfungen sind wichtig, weil manche Merkmale nur in Produktion existieren: echte Nutzerlatenz, echte Ausfallarten, echte Kosten. Ein gesundes Portfolio kombiniert schnelle, atomare, ausgelöste Prüfungen im Build mit einer kleineren Zahl langsamerer holistischer Prüfungen vor dem Release und kontinuierlichen Prüfungen in Produktion.
Wo Fitness Functions laufen
Fitness Functions über die Qualitäten hinweg
Die meisten Teams beginnen mit der Struktur, weil Strukturprüfungen günstig, schnell und deterministisch sind, und ergänzen dann Prüfungen für Performance, Sicherheit, Resilienz und Daten, während die Pipeline reift. Die Tabelle nennt typische Beispiele; Werkzeuge ändern sich, die Muster nicht.
Beispiele nach Qualität
| Qualität | Fitness Function | Art | Typische Werkzeuge |
|---|---|---|---|
| Struktur | Schichten- und Abhängigkeitsregeln, keine Zyklen, Module nutzen einander nur über öffentliche APIs (Abschnitt 3.4) | Atomar, ausgelöst, statisch | ArchUnit, import-linter, dependency-cruiser, Spring-Modulith-Verifikation |
| Performance | End-to-End-Lasttest mit Perzentil-Schwellenwerten; Latenzbudgets pro Service in der eigenen Pipeline jedes Service | Holistisch, ausgelöst | k6, Gatling, JMeter, Locust; Schwellenwerte, die den Job scheitern lassen |
| Sicherheit | Build abbrechen bei Abhängigkeiten mit bekannten hohen oder kritischen Schwachstellen; keine Secrets im Code; Container-Images nur aus der freigegebenen Registry | Atomar, ausgelöst | pip-audit, npm audit, OWASP Dependency-Check, Trivy, Secret-Scanner; Policy as Code (Abschnitt 11.4) |
| Resilienz | Chaos-Experimente, die Instanzen beenden oder Abhängigkeiten verlangsamen und prüfen, dass der stabile Zustand erhalten bleibt (Abschnitt 9.8) | Holistisch, ausgelöst oder kontinuierlich | Toxiproxy, Chaos Toolkit, Fault-Injection-Dienste der Cloud-Anbieter |
| Daten | Prüfungen der Schemakompatibilität für Events und APIs; Migrationen, an Daten in Produktionsgröße geprobt (Abschnitt 7.7) | Atomar, ausgelöst | Kompatibilitätsprüfungen der Schema Registry, buf breaking, Consumer-Driven-Contract-Tests |
| Betreibbarkeit und Kosten | Jeder Service stellt Health Checks und Standardmetriken bereit; die Kosten pro Bestellung bleiben unter einem Zielwert | Atomar oder kontinuierlich | Pipeline-Prüfungen für Service-Templates; Kosten-Dashboards mit Alarmen |
Evolutionäre Architektur und inkrementelle Änderung
Fitness Functions sind die eine Hälfte dessen, was Ford, Parsons, Kua und Sadalage evolutionäre Architektur nennen: eine Architektur, die gelenkte, inkrementelle Änderung über mehrere Dimensionen unterstützt. Jeder Teil dieser Formulierung ist eine Entwurfsanforderung.
Inkrementelle Änderung hat eine Entwicklungs- und eine Betriebsseite. Entwickler müssen kleine Änderungen sicher vornehmen können; das hängt von Modularität und angemessener Kopplung ab (Kapitel 3) und davon, jeden unabhängig deploybaren Teil, das Architekturquantum aus Abschnitt 5.1, klein genug zu halten, um ihn ohne Abstimmung mit anderen zu ändern. Der Betrieb muss kleine Änderungen häufig und sicher ausliefern können; das hängt von einer Deployment-Pipeline, schrittweisem Rollout und schnellem Rollback ab (Abschnitt 10.5). Gelenkt ist der Punkt, an dem Fitness Functions ins Spiel kommen: Sie definieren, was „fit“ bedeutet, und verhindern, dass Inkremente es verschlechtern. Mehrere Dimensionen erinnert daran, dass Architektur nicht nur Codestruktur ist: Daten, Sicherheit, Betrieb, Teamstruktur und Kosten entwickeln sich alle weiter und müssen alle geschützt werden.
Der Ansatz verändert, wie Architekten über die Zukunft denken. Statt jede Anforderung vorherzusagen und im Voraus Flexibilität dafür einzubauen, was, wie Abschnitt 3.8 gezeigt hat, teuer und oft falsch ist, hält das Team das System leicht änderbar und schützt nur die Merkmale, die zählen, während es andere Entscheidungen auf den Last Responsible Moment verschiebt (Abschnitt 1.6). Kritiker weisen auf echte Grenzen hin. Nicht jede Qualität lässt sich automatisch oder günstig prüfen; schlecht gewählte Schwellenwerte erzeugen Rauschen, das Teams zu ignorieren lernen; und manche Entscheidungen, etwa für eine Datenbank oder einen Cloud-Anbieter, bleiben Einwegtüren, wie gut die Pipeline auch ist. Evolutionäre Architektur ist eine Disziplin, die umkehrbaren Teile umkehrbar und die wichtigen Teile geschützt zu halten, kein Versprechen, dass sich später alles ändern lässt.
Ausgearbeitetes Beispiel
Ausgearbeitetes Beispiel: drei Szenarien aus Kapitel 2 als Fitness Functions
Abschnitt 2.8 hat einen Utility Tree für die Essenslieferplattform erstellt. Das Team macht aus drei seiner Blätter Fitness Functions, eine ausgelöst und holistisch, eine ein Chaos-Experiment, eine strukturell, nachdem die ATAM in Abschnitt 11.1 zur asynchronen Zahlungsautorisierung geführt hat.
| Szenario 1: Bestelllatenz (H,H) | Bei der Freitagsspitze von 100 Bestellungen/s kommen 95 % der Bestellbestätigungen innerhalb von 1,5 s und 99 % innerhalb von 3 s zurück |
|---|---|
| Fitness Function 1 | Holistisch, ausgelöst: ein k6-Lasttest gegen eine produktionsnahe Umgebung, nächtlich und vor jedem Release, der fehlschlägt, wenn p95 oder p99 den Schwellenwert übersteigt oder mehr als 0,1 % der Anfragen fehlschlagen. Ergänzt durch kontinuierliches Monitoring derselben Perzentile aus echtem Verkehr in Produktion |
| Latenzbudgets | Die 1,5 s werden in Budgets aufgeteilt: Mobilfunknetz und TLS 400 ms, Gateway 50 ms, Bestellungen 250 ms, Preisgestaltung 100 ms, Datenbank-Schreibvorgänge 150 ms; bleiben 550 ms Kapazitätsreserve, seit die Kartenautorisierung nicht mehr auf dem Pfad liegt. Die Pipeline jedes Service führt einen atomaren Komponenten-Lasttest gegen das eigene Budget aus, sodass eine Regression in dem Service erkannt wird, der sie verursacht hat |
| Szenario 2: Verfügbarkeit des Checkouts (H,H) | Wenn beim Zahlungsanbieter während der Spitze ein Timeout auftritt, werden Bestellungen angenommen und in eine Queue gestellt, keine bestätigte Bestellung geht verloren, und die Kunden werden innerhalb von 10 s informiert |
| Fitness Function 2 | Holistisches Chaos-Experiment, wöchentlich im Staging und vierteljährlich als Game Day in Produktion mit kleinem Blast Radius: Der Anbieter wird zum Hängen gebracht; Bestellungen müssen innerhalb von 10 s als ausstehend angenommen werden und nach der Wiederherstellung alle abgeschlossen werden. Verantwortlich: Bestellteam |
| Szenario 3: neuer Kassensystem-Anbieter (M,L) | Ein neuer Anbieter von Restaurant-Kassensystemen wird in 5 Personentagen integriert, indem ein Adapter hinzugefügt wird |
| Fitness Function 3 | Atomar, ausgelöst, statisch: Ein import-linter-Contract verbietet den Restaurant-Domänen- und API-Modulen sowie dem Bestellpaket, ein Anbieter-SDK zu importieren, und ein zweiter Contract hindert Adapter daran, einander zu importieren, sodass die Änderung lokal bleibt. Ergänzt durch eine manuelle Prüfung: Der Aufwand jeder echten Anbieterintegration wird erfasst und mit dem Ziel von 5 Tagen verglichen |
| Zu jeder dokumentiert | Quellszenario, Schwellenwert, Verantwortlicher, das erklärende ADR und ein Review-Termin |
Jedes Antwortmaß wurde ohne Umdeutung zu einem Schwellenwert; das ist der Ertrag, wenn man Szenarien von Anfang an gut formuliert.
Das Änderbarkeitsszenario lässt sich nicht vollständig automatisieren: Die Strukturregel schützt die Voraussetzungen für eine Änderung in 5 Tagen, und die manuelle Messung prüft das Ergebnis.
Latenzbudgets machen aus einer holistischen Zahl atomare Prüfungen, die das richtige Team über eine Regression informieren.
import http from 'k6/http';
import { check } from 'k6';
export const options = {
scenarios: {
friday_peak: { executor: 'constant-arrival-rate', rate: 100, timeUnit: '1s',
duration: '10m', preAllocatedVUs: 300 }, // 100 orders per second
},
thresholds: { // the scenario's response measure, as pass/fail rules
'http_req_duration{name:place_order}': ['p(95)<1500', 'p(99)<3000'],
'http_req_failed{name:place_order}': ['rate<0.001'],
},
};
const order = { restaurantId: 'r-42', items: [{ sku: 'pad-thai', qty: 1 }] };
export default function () {
const res = http.post(`${__ENV.BASE_URL}/orders`, JSON.stringify(order), {
headers: { 'Content-Type': 'application/json' }, tags: { name: 'place_order' } });
check(res, { 'order accepted': (r) => r.status === 201 || r.status === 202 });
}# Fitness function: checkout keeps accepting orders when payments hang (illustrative)
# Runs weekly in staging; toxiproxy, api and ledger are test fixtures.
def test_orders_survive_payment_provider_outage(toxiproxy, api, ledger):
toxiproxy.add_latency("payment-provider", latency_ms=30_000) # provider hangs
placed = [api.place_order(sample_order()) for _ in range(200)]
assert all(r.status in (201, 202) for r in placed) # still accepted
assert all(r.json()["state"] == "PENDING_PAYMENT" for r in placed)
assert max(r.elapsed_seconds for r in placed) < 10 # told within 10 s
toxiproxy.remove_toxics("payment-provider") # provider recovers
ledger.wait_until_settled(timeout_seconds=300)
assert ledger.lost_orders(placed) == [] # none lost# .importlinter: only the POS adapters may use vendor SDKs
[importlinter]
root_package = fooddelivery
include_external_packages = True
[importlinter:contract:pos-vendors-isolated]
name = Vendor POS SDKs are used only inside the POS adapters
type = forbidden
source_modules =
fooddelivery.restaurant.domain
fooddelivery.restaurant.api
fooddelivery.ordering
forbidden_modules =
tillpro_sdk
kitchenlink
[importlinter:contract:adapters-independent]
name = POS adapters do not import each other
type = independence
modules =
fooddelivery.restaurant.pos_adapters.tillpro
fooddelivery.restaurant.pos_adapters.kitchenlinkDie Datenkompatibilität wird auf dieselbe Weise geschützt. Bevor eine Änderung am Event OrderPlaced gemergt werden kann, fragt die Pipeline die Schema Registry, ob das neue Schema nach der Kompatibilitätsregel des Subjects mit der zuletzt registrierten Version kompatibel ist, und schlägt fehl, wenn nicht:
# Data fitness function: block the merge if the new event schema would break consumers
curl -s -X POST -H "Content-Type: application/vnd.schemaregistry.v1+json" \
--data @build/order-placed-v7.request.json \
"$SCHEMA_REGISTRY_URL/compatibility/subjects/order-placed-value/versions/latest" \
| jq -e '.is_compatible == true'Fitness Functions entwerfen, die Bestand haben
Beginnen Sie klein und mit dem Wichtigen. Wählen Sie die drei bis fünf Merkmale, die der Utility Tree am höchsten bewertet, schreiben Sie für jedes eine Fitness Function und sorgen Sie dafür, dass sie schnell und zuverlässig sind, bevor Sie weitere hinzufügen. Ein Dutzend vertrauenswürdiger Prüfungen ist mehr wert als hundert, die zufällig fehlschlagen.
Nutzen Sie bei bestehenden Systemen eine Ratsche. Verletzt eine Codebasis eine Regel bereits, erfassen Sie die aktuellen Verstöße als Baseline und lassen Sie nur neue scheitern; verschärfen Sie die Baseline, während das Team die Schulden abbaut. Dasselbe funktioniert für die Performance: Bei Regressionen über eine vereinbarte Marge gegenüber dem letzten Release scheitern, während man auf das Ziel des Szenarios hinarbeitet.
Machen Sie Schwellenwerte explizit und geben Sie ihnen Verantwortliche. Halten Sie Schwellenwerte in versionierter Konfiguration neben einem Verweis auf das ADR, das sie begründet, mit einem namentlich genannten Verantwortlichen. Schlägt eine Fitness Function fehl, entscheidet der Verantwortliche zwischen Codekorrektur und Regeländerung, und die Entscheidung wird dokumentiert. Behandeln Sie eine Fitness Function, die häufig übergangen wird, als Befund: Entweder ist die Regel falsch, oder die Architektur steht unter echtem Druck.
Halten Sie die Pipeline schnell. Atomare Prüfungen gehören in jeden Build; schwere holistische Prüfungen wie zehnminütige Lasttests laufen nächtlich, vor dem Release oder auf dem Release Candidate. Kontinuierliche Prüfungen in Produktion brauchen dieselbe Sorgfalt wie jeder Alarm: an Auswirkungen auf Nutzer gekoppelt, mit einem Runbook und still, wenn nichts falsch ist.
Häufige Fragen
Sind Fitness Functions einfach Tests?
Viele sind als Tests umgesetzt, aber ihr Gegenstand ist ein anderer. Gewöhnliche Tests prüfen, dass sich Features korrekt verhalten; Fitness Functions prüfen Architekturmerkmale wie Struktur, Latenz, Resilienz oder Kompatibilität. Manche, etwa Monitore in Produktion und manuelle Reviews, sind überhaupt keine Tests.
Wer schreibt Fitness Functions: Architekten oder Entwickler?
Beide. Architekten bestimmen meist die Merkmale und Schwellenwerte und schreiben oft die ersten Prüfungen, was ein guter Weg ist, praktisch beteiligt zu bleiben (Abschnitt 1.4). Die Teams besitzen und pflegen sie wie jeden anderen Code.
Wie hängen Fitness Functions mit SLOs zusammen?
Ein SLO mit einem Alarm auf sein Error Budget ist eine kontinuierliche, holistische Fitness Function für Verfügbarkeit oder Latenz in Produktion (Abschnitt 9.5). Fitness Functions in der Pipeline versuchen, dieselben Regressionen abzufangen, bevor sie die Nutzer erreichen.
Prüfen Sie Ihr Verständnis
Was ist der Unterschied zwischen einer Metrik und einer Fitness Function?
Eine Metrik beschreibt eine Eigenschaft; eine Fitness Function kodiert eine Entscheidung mit einem Schwellenwert und einer Aktion, sodass ihr Bruch einen Build scheitern lässt oder einen Alarm auslöst und eine bewusste Wahl erzwingt.
Nennen Sie je ein Beispiel für eine atomare und eine holistische Fitness Function.
Atomar: eine Regel, die Importe aus der Web-Schicht in die Domäne verbietet. Holistisch: ein Lasttest, der die Bestelllatenz mit aktivierter Sicherheit, aktiviertem Logging und Caching misst.
Was fügt ein Latenzbudget einer End-to-End-Latenz-Fitness-Function hinzu?
Es teilt das End-to-End-Ziel in Limits pro Service auf, die jeder Service in seiner eigenen Pipeline prüft, sodass eine Regression in dem Service erkannt wird, der sie verursacht hat.
Was sind die drei Teile der Definition von evolutionärer Architektur?
Sie unterstützt gelenkte (durch Fitness Functions), inkrementelle (kleine, sichere Änderungen und Releases) Änderung über mehrere Dimensionen (Code, Daten, Sicherheit, Betrieb, Teams und mehr).
Quellen und weiterführende Literatur
Haben Sie eine Frage zu diesem Abschnitt? ArchitectBot, der KI-Lernassistent des Kurses, antwortet zuerst aus dem Kurs.
Fragen: „Welche drei Fitness Functions sollten wir zuerst für einen Service schreiben, der Bestellungen schnell bestätigen und einen Ausfall des Zahlungsanbieters überstehen muss?“