# Evolutionary Architecture: Systeme, die sich ändern dürfen

URL: https://www.mikebild.dev/de/blog/evolutionary-architecture-wandel-einplanen/

Evolutionary Architecture ist kein Freibrief für Wildwuchs und auch kein zweites Wort für "agil". Neal Ford, Rebecca Parsons und Patrick Kua definieren sie in *Building Evolutionary Architectures* (O'Reilly 2017, zweite Auflage 2022) als eine Architektur, die "guided, incremental change across multiple dimensions" unterstützt. Drei Wörter tragen diese Definition. Geführt: Es gibt benannte Eigenschaften, die geschützt werden. Inkrementell: Die einzelne Änderung ist klein genug, um sie zurücknehmen zu können. Mehrdimensional: Gemeint ist nicht nur der Code, sondern ebenso Daten, Betrieb und die Organisation, die beides trägt.

Der Gegenentwurf ist das eingefrorene System. Vor drei Jahren sauber entworfen, für eine Welt, die es so nicht mehr gibt – und seither nicht mehr bewegt, weil jede Änderung zu riskant erschien. Die Diagramme hängen noch an der Wand, aber sie beschreiben ein Auto, das niemand mehr fährt. Dahinter steckt eine Grundannahme, die sich hartnäckig hält: Architektur sei etwas, das man einmal richtig macht und dann verteidigt, ein Zielbild, das man erreicht. Kein System, das produktiv genutzt wird, bleibt jedoch stehen. Anforderungen verschieben sich, Lastprofile ändern sich, Teams wachsen, Abhängigkeiten altern. Die Frage ist nie, ob sich ein System ändert, sondern nur, ob die Architektur diesen Wandel begleitet oder ihm im Weg steht.

Evolutionary Architecture dreht die Perspektive deshalb um: Statt Wandel als Ausnahme zu behandeln, die man nach dem Go-live möglichst vermeidet, macht sie ihn zur Norm, für die man von Anfang an baut. Ein System, das sich ändern darf – in kleinen Schritten, und ohne dass dabei die Eigenschaften kaputtgehen, die es wertvoll machen.

## Warum das Endzustands-Denken teuer wird

Der klassische Reflex heißt Big Design Up Front. Man denkt möglichst weit voraus, entscheidet früh alles Wichtige und gießt das Ergebnis in ein Zielbild. Das fühlt sich verantwortungsvoll an. Es ist auch nicht grundsätzlich falsch, früh nachzudenken – im Gegenteil. Falsch ist die Erwartung, dass diese frühen Entscheidungen dauerhaft tragen.

Der Denkfehler steckt im Zeitpunkt. Ganz am Anfang eines Vorhabens weiß man am wenigsten über die Domäne, die Nutzer und das reale Verhalten unter Last. Genau dann trifft man die weitreichendsten Entscheidungen. Jede spätere Erkenntnis muss sich dann gegen eine Struktur behaupten, die für sie nicht gemacht war. Das ist der Moment, in dem Teams anfangen, um die Architektur herumzuarbeiten statt mit ihr. Der Fachbegriff dafür ist architectural drift oder erosion: Das reale System entfernt sich Stück für Stück vom gedachten, bis das Diagramm an der Wand nur noch Folklore ist.

Der geschäftliche Schaden ist selten ein spektakulärer Ausfall. Er ist schleichend. Änderungen dauern länger. Jede Anpassung braucht mehr Abstimmung. Neue Features kollidieren mit alten Annahmen. Die Time-to-Market steigt, während die Zuversicht sinkt. Und irgendwann steht die Frage im Raum, ob man nicht besser alles neu bauen sollte – die teuerste aller Optionen.

## Der Perspektivwechsel: geführte Evolution statt fixiertes Ziel

Der Ausweg ist kein anderes Zielbild, sondern ein anderer Umgang mit Zielbildern. Statt einen Endzustand zu definieren und zu verteidigen, definiert man die Eigenschaften, die das System behalten soll, und lässt die Struktur sich innerhalb dieser Leitplanken entwickeln.

```mermaid
flowchart LR
  A[Change<br/>small increment] --> B[Deployment Pipeline]
  B --> C{Fitness Functions<br/>guardrails}
  C -->|pass| D[Learn & Adjust]
  C -->|fail| E[Stop & Fix]
  E --> A
  D --> A
```

Der Kern ist ein Regelkreis, kein Wasserfall. Eine kleine Änderung läuft durch die Deployment-Pipeline, wird gegen definierte Leitplanken geprüft, liefert eine klare Rückmeldung – bestanden oder nicht – und daraus lernt das Team für den nächsten Schritt. Klein, geführt, wiederholbar. Das ist der Unterschied zwischen einem System, das sich entwickelt, und einem, das nur älter wird.

Wichtig ist die Betonung auf geführt. Evolutionary bedeutet ausdrücklich nicht "keine Architektur" oder "wir lassen es wachsen, wie es will". Das ist der häufigste Trugschluss. Wildwuchs ist keine Evolution, sondern ihr Gegenteil. Ohne bewusst benannte, priorisierte Architektur-Charakteristika gibt es nichts zu schützen und nichts zu messen. Der erste Schritt ist deshalb keine Technik, sondern eine Entscheidung: Was genau muss dieses System auszeichnen? Antwortzeit unter einer bestimmten Grenze? Lose Kopplung zwischen fachlichen Bereichen? Nachweisbare Sicherheit an den Rändern? Erst wenn diese Ziele explizit sind, kann man sie verteidigen.

## Fitness Functions: Architektur, die man messen kann

Der Mechanismus, mit dem diese Ziele verteidigt werden, heißt Fitness Function. Der Begriff ist aus evolutionären Algorithmen entlehnt, wo eine Fitness-Funktion bewertet, wie nah eine Lösung am gewünschten Ergebnis ist. Übertragen auf Architektur heißt das laut den Autoren: "any mechanism that provides an objective integrity assessment of some architectural characteristic(s)". Also jeder Mechanismus, der objektiv prüft, ob eine architektonische Eigenschaft noch intakt ist.

Das Entscheidende an dem Wort ist objektiv. Eine Fitness Function ist kein Meeting, kein Bauchgefühl und kein Architecture Review Board, das einmal im Quartal tagt und über Slides urteilt. Sie ist ein automatisierter Test, der in der Pipeline läuft und ein eindeutiges Ergebnis liefert. Damit verschiebt sich Governance von manueller Kontrolle hin zu etwas Versioniertem, Ausführbarem, jederzeit Wiederholbarem – nicht umsonst trägt die zweite Auflage den Untertitel "Automating Software Governance".

Das einfachste und bekannteste Beispiel sind strukturelle Regeln. Mit einer Bibliothek wie ArchUnit lässt sich eine Architekturvorgabe als ganz normaler Unit-Test formulieren:

```java
@ArchTest
static final ArchRule domain_must_not_depend_on_infrastructure =
    noClasses().that().resideInAPackage("..domain..")
      .should().dependOnClassesThat().resideInAPackage("..infrastructure..");
```

Diese Regel sagt: Die Domänenschicht darf nicht auf die Infrastruktur zugreifen. Bisher stand so etwas in einem Wiki und wurde in Code Reviews hoffentlich bemerkt. Jetzt bricht der Build, sobald jemand die Grenze verletzt – am selben Tag, an dem es passiert, nicht drei Monate später in einer Refactoring-Retrospektive. Die Absicht wird vom Kommentar zum ausführbaren Fakt.

Und genau hier liegt der zweite große Trugschluss: Fitness Functions sind nicht auf solche Package- und Layering-Checks beschränkt. Das ist nur die sichtbarste Kategorie. Alles, was man an einer Architektur objektiv prüfen kann, ist Kandidat – Performance-Budgets, Security-Scans, Prüfungen auf zyklische Abhängigkeiten, sogar Chaos-Experimente oder monitoring-basierte Prüfungen im laufenden Betrieb.

Die Autoren gliedern das in eine kleine Taxonomie, die im Alltag hilft, Lücken zu erkennen. Fitness Functions können atomic sein (prüfen eine einzelne Eigenschaft) oder holistic (prüfen das Zusammenspiel mehrerer). Sie können triggered sein (laufen bei einem Ereignis, etwa im Build) oder continual (laufen dauerhaft in Produktion). Und sie können static sein (feste Schwelle) oder dynamic (Schwelle abhängig vom Kontext). Wer nur strukturelle, atomic-triggered Regeln hat, deckt eine Ecke ab und übersieht den Rest.

Ein Performance-Budget etwa ist eher holistisch und lässt sich als Gate in der Pipeline formulieren:

```yaml
fitness_functions:
  - name: p95_latency_budget
    metric: http_request_duration_p95_ms
    threshold: 300
    on_breach: fail_build
  - name: max_module_coupling
    metric: afferent_efferent_coupling_ratio
    threshold: 0.7
    on_breach: warn
```

Das Muster ist immer dasselbe: eine architektonische Eigenschaft, eine objektive Schwelle, eine definierte Konsequenz. Reißt die 95.-Perzentil-Latenz das Budget, bricht der Build. Steigt die Kopplung über den Grenzwert, gibt es zunächst eine Warnung. Man muss nicht alles hart erzwingen – aber man macht die Eigenschaft sichtbar und entscheidet bewusst, wie streng man sie behandelt.

## Kopplung ist die eigentliche Bremse

Wenn ein System sich nicht mehr in kleinen Schritten ändern lässt, liegt das fast immer an Kopplung. Nicht nur an der offensichtlichen zwischen Klassen, sondern auch an versteckter zeitlicher Kopplung und an Datenkopplung. Zwei Dienste, die immer gemeinsam deployt werden müssen. Ein Schema, das drei Teams gleichzeitig anfassen müssen, um ein Feld zu ändern. Solange diese Bänder bestehen, ist inkrementeller Wandel unmöglich, egal wie gut die Absicht ist.

Deshalb gehört zu den wichtigsten Fitness Functions die Kontrolle der Kopplung selbst. Und deshalb machen ein paar bewährte Muster hier den Unterschied. Die Strangler Fig Application von Martin Fowler beschreibt, wie man ein Altsystem inkrementell ablöst, indem man neue Funktionalität wie eine Würgefeige um den alten Kern wachsen lässt, bis der irgendwann verschwinden kann – ohne den einen großen, riskanten Umstieg. Auf Datenebene leistet das Expand-Contract-Muster (auch Parallel Change) dasselbe: Man erweitert ein Schema, migriert schrittweise, entfernt das Alte erst, wenn niemand es mehr braucht. Refactoring wird so zur normalen, sicheren Bewegung statt zum Kraftakt.

Auf der Betriebsebene sorgen Resilienz-Muster wie Circuit Breaker und Bulkhead aus Michael Nygards *Release It!* dafür, dass die lose gekoppelten Teile sich auch bei Störungen nicht gegenseitig mitreißen. Und an den Diensträndern hält Consumer-Driven Contract Testing die Grenzen ehrlich: Jeder Konsument beschreibt, was er von einem Dienst erwartet, und dieser Vertrag wird automatisiert geprüft. Ändert sich der Dienst inkompatibel, schlägt der Test an, bevor es der Nutzer merkt. Auch das ist eine Fitness Function – eine, die Änderbarkeit an den teuersten Bruchstellen absichert.

Ein Wort zu Conway's Law, denn Kopplung ist nicht nur technisch. Systeme spiegeln die Kommunikationsstrukturen der Organisationen, die sie bauen. Wer lose gekoppelte Software will, muss auch die Teams entsprechend schneiden. Das ist keine Randnotiz, sondern oft die Voraussetzung dafür, dass die technischen Leitplanken überhaupt greifen.

## Der Beweis, dass es sich rechnet

An dieser Stelle kommt der Einwand: Klingt gut, aber all diese Automatisierung und dieses ständige Ändern – geht das nicht auf Kosten der Stabilität? Schneller heißt doch riskanter?

Die Daten sagen das Gegenteil. Die DORA-Forschung, zusammengefasst in *Accelerate* (Forsgren, Humble, Kim, 2018), zeigt über tausende Organisationen hinweg, dass Geschwindigkeit und Stabilität keine Gegner sind, sondern gemeinsam steigen. Die leistungsstärksten Teams deployen häufiger *und* haben seltener Ausfälle *und* erholen sich schneller. Der vermeintliche Zielkonflikt zwischen Tempo und Verlässlichkeit ist ein Artefakt des alten Denkens – das Ergebnis von seltenen, großen, riskanten Releases.

Die vier klassischen DORA-Metriken lesen sich selbst wie systemweite Fitness Functions:

```text
Deployment Frequency     - wie oft deployen wir?
Lead Time for Changes    - wie lange von Commit bis Produktion?
Change Failure Rate      - wie viele Deployments verursachen einen Fehler?
Time to Restore Service  - wie schnell sind wir wieder online?
```

Sie messen nicht ein einzelnes Modul, sondern die Änderbarkeit des Gesamtsystems. Verkürzte Zyklen, weniger Reibung, höhere Qualität werden damit zu Größen, die man in dieselbe Regelkreis-Logik einhängen kann wie eine Latenzgrenze.

```mermaid
flowchart TB
  subgraph Old[Architecture as end-state]
    O1[Big Design Up Front] --> O2[freeze] --> O3[drift & erosion]
  end
  subgraph New[Architecture as guarded evolution]
    N1[named characteristics] --> N2[fitness functions] --> N3[small guarded change] --> N1
  end
```

Der Denkrahmen ist im Übrigen nicht auf Technik beschränkt. Er ist dasselbe Prinzip, das *The Lean Startup* für Produkte formuliert hat – Build, Measure, Learn: eine Hypothese, ein kleiner Schritt, eine Messung, eine Anpassung. Architektur-Evolution ist die technische Ausprägung derselben Haltung. Man behauptet nicht, die richtige Struktur zu kennen. Man baut so, dass man es günstig herausfinden kann.

## Fazit

Architektur ist kein Endzustand. Sie ist die Fähigkeit eines Systems, sich weiter verändern zu lassen, ohne die Eigenschaften zu verlieren, die es wertvoll machen. Wer das ernst nimmt, hört auf, ein Zielbild zu verteidigen, und fängt an, die richtigen Dinge zu schützen.

Der Weg dahin ist erstaunlich konkret. Erstens: die Architektur-Charakteristika benennen, die wirklich zählen – nicht alle, sondern die wenigen, die den Unterschied machen. Zweitens: für jede dieser Eigenschaften eine Fitness Function bauen, die objektiv, automatisiert und in der Pipeline prüft, ob sie noch hält – strukturell, aber eben auch bei Performance, Sicherheit und Kopplung. Drittens: Kopplung aktiv niedrig halten, technisch wie organisatorisch, damit kleine Schritte überhaupt möglich bleiben. Und viertens: dem Ganzen vertrauen, weil die Daten zeigen, dass Tempo und Stabilität zusammen wachsen.

Der Ansatz schafft noch keine kurzen Zyklen und garantiert keine stabile Qualität. Er macht benannte Eigenschaften bei kleinen Änderungen früher überprüfbar. Ob dadurch Reibung sinkt oder Änderungen schneller werden, zeigt erst der reale Lieferfluss. Die beste Architektur ist für mich deshalb nicht die, die für immer richtig sein soll, sondern eine, deren Annahmen sich prüfen und bei neuen Erkenntnissen ändern lassen.

## Weiterführende Quellen

- Neal Ford, Rebecca Parsons, Patrick Kua: *Building Evolutionary Architectures*, O'Reilly, 1. Aufl. 2017 / 2. Aufl. 2022 (mit Pramod Sadalage)
- Martin Fowler: [Foreword to Building Evolutionary Architectures](https://martinfowler.com/articles/evo-arch-forward.html)
- [DORA – Four Key Metrics](https://dora.dev/guides/dora-metrics-four-keys/)
- Nicole Forsgren, Jez Humble, Gene Kim: *Accelerate*, IT Revolution, 2018
- [ArchUnit – Unit-Tests für Architekturregeln](https://www.archunit.org/)
- [InfoQ – Fitness Functions for Your Architecture](https://www.infoq.com/articles/fitness-functions-architecture/)
- Michael Nygard: *Release It!*, Pragmatic Bookshelf, 2. Aufl. 2018
