ARCHITECTURE · 03 / 06

Softwarearchitektur

Architektur ist die Summe der Entscheidungen, die später teuer zu ändern sind: wo die Grenze zwischen zwei Komponenten verläuft, welche Daten zusammengehören, welcher Vertrag an einer Schnittstelle gilt. Wir treffen diese Entscheidungen explizit, halten sie mit Begründung und verworfenen Alternativen fest und leiten daraus einen Migrationsweg ab, der in kleinen Schritten produktiv geht. Statt eines Zielbilds auf Folien entsteht eine Struktur, die sich an Code, Datenmodell und Telemetrie überprüfen lässt.

Ausgangslage

Woran Architektur in der Praxis scheitert

Die häufigste Ursache für Änderungsangst ist nicht schlechter Code, sondern ein unklarer Schnitt. Fünf Module lesen dieselbe Tabelle direkt, jedes mit eigener Annahme über Nullbarkeit und erlaubte Statuswerte. Eine Spaltenumbenennung wird damit zum organisationsweiten Vorgang. Wer die Abhängigkeit nicht kennt, entdeckt sie erst beim Deployment – und baut anschließend eine weitere Sonderbehandlung ein, statt die Grenze endlich zu ziehen.

Der Gegenreflex ist Aufteilung um jeden Preis. Aus einem Monolithen werden zwanzig Dienste, die synchron über HTTP aufeinander warten und weiterhin dieselbe Datenbank beschreiben. Statt Entkopplung entsteht ein verteilter Monolith: dieselbe Kopplung, zusätzlich Netzlatenz, Teilausfälle und Konsistenzprobleme über Dienstgrenzen. Die Fehlersuche verteilt sich auf viele Logdateien, ohne dass jemand Tracing eingeführt hätte. Die Auslieferungsfrequenz sinkt, anstatt zu steigen.

Entscheidungen sind meist getroffen, aber nirgends festgehalten. Warum die Warteschlange auf einem eigenen Broker läuft und nicht auf PostgreSQL mit SKIP LOCKED, weiß eine Person, die das Team verlassen hat. Neue Kollegen lesen den Zwischenstand als Absicht. Ohne festgehaltene Begründung lässt sich eine Entscheidung nicht überprüfen, wenn sich die Randbedingungen ändern – also bleibt sie bestehen, lange nachdem ihr Grund entfallen ist.

Dazu kommen Schnittstellen, die als internes Detail begonnen haben und inzwischen von Dritten benutzt werden: ohne Versionierung, ohne dokumentiertes Fehlerverhalten, ohne Zusage zur Kompatibilität. Jede Änderung ist dann ein Risiko, das niemand einschätzen kann. Ähnlich wirkt die Bindung an einzelne Anbieter, wenn proprietäre Trigger, verwaltete Warteschlangen und anbieterspezifische Identitätsmodelle in die Geschäftslogik wandern und den Betriebsort faktisch festlegen.

Vorgehen

Wie wir Architektur bearbeiten

Am Anfang steht eine Bestandsaufnahme am realen System, nicht am Wunschbild. Wir lesen Repositories und Build-Definitionen, ziehen das Datenbankschema mit Fremdschlüsseln und Indizes, sehen uns die teuersten Abfragen über pg_stat_statements an und prüfen Deploymentweg und Laufzeitkonfiguration. Daraus entsteht ein Abhängigkeitsbild, das Kopplungen benennt: geteilte Tabellen, gemeinsam genutzte Bibliotheken, implizite Reihenfolgen bei Migrationen, Aufrufe ohne Zeitlimit.

Der Schnitt folgt Datenhoheit und Änderungsrhythmus, nicht dem Organigramm. Jede Komponente besitzt ihre Tabellen; Zugriff von außen läuft über einen Vertrag – ein HTTP-Interface mit OpenAPI-Beschreibung, ein Ereignisformat mit Schema oder eine bewusst offengelegte Sicht, etwa über PostgREST. Verträge werden versioniert, additiv erweitert und in der Pipeline gegen Beispieldaten geprüft. Fehlerfälle, Zeitlimits und Idempotenz gehören in die Spezifikation, nicht in den Kopf der Implementierung.

Jede tragende Entscheidung wird als Architecture Decision Record im Repository abgelegt, üblicherweise unter docs/adr/ und versioniert mit dem Code. Ein solcher Eintrag beschreibt Kontext, geprüfte Optionen, Entscheidung, Konsequenzen und Status – vorgeschlagen, akzeptiert oder ersetzt. Damit ist nachvollziehbar, welche Annahme eine Struktur trägt. Fällt die Annahme weg, ist der Eintrag der Ausgangspunkt für die Revision und nicht der Anlass, dieselbe Diskussion von vorn zu führen.

Modernisierung läuft schrittweise nach dem Strangler-Fig-Muster: Ein Reverse Proxy leitet einzelne Routen auf die neue Implementierung um, das alte System bleibt lauffähig, jeder Schritt ist für sich rückrollbar. Doppelschreiben und Abgleichläufe sichern die Datenwanderung ab. Parallel wird gemessen – OpenTelemetry-Traces über Dienstgrenzen, Fehlerquoten und Latenzverteilungen je Route. Ob ein Schnitt trägt, entscheidet die Telemetrie, nicht das Diagramm.

Leistungsumfang

Was konkret dazugehört

01

Bewertung bestehender Systeme
Strukturierter Review von Code, Datenmodell, Build und Betrieb. Ergebnis ist eine priorisierte Liste von Kopplungen, Risiken und Aufwänden statt eines pauschalen Reifegradurteils.

02

Komponentenschnitt und Verantwortlichkeiten
Grenzen nach Datenhoheit und Änderungsrhythmus. Festgelegt wird, welche Komponente welche Tabellen besitzt und wer an einer Grenze wen aufrufen darf – und wer nicht.

03

Schnittstellen- und API-Design
HTTP-Interfaces mit OpenAPI-Beschreibung, Ereignisformate mit Schema, Versionierungsregeln und definierte Fehlercodes. Zeitlimits, Wiederholverhalten und Idempotenz von Schreiboperationen sind Teil des Vertrags.

04

Datenmodellierung
Fremdschlüssel, Check-Constraints und Transaktionsgrenzen in PostgreSQL statt Prüfungen allein in der Anwendung. Indizes anhand echter Abfragepläne, Migrationen abwärtskompatibel in mehreren Schritten.

05

Architecture Decision Records
Entscheidungen mit Kontext, Optionen und Konsequenzen im Repository, versioniert mit dem Code. Lesbar für neue Teammitglieder und revidierbar, sobald eine Annahme entfällt.

06

Migrationsplanung
Strangler-Fig-Schnitte Route für Route, mit Doppelschreiben, Abgleich und Rückrollpunkt pro Schritt. Kein Stichtag, an dem alles gleichzeitig funktionieren muss.

07

Technische Due Diligence und Zweitmeinung
Prüfung einer geplanten Architektur oder einer Codebasis vor Investitions- und Übernahmeentscheidungen, mit klarer Trennung von Befund, Bewertung und Empfehlung.

Einsatzfälle

Wann diese Leistung passt

Der Monolith bremst die Auslieferung

Ein gewachsenes System lässt sich nur als Ganzes deployen, jede Änderung erfordert eine Regression über alles. Wir bestimmen die ersten tragfähigen Schnitte und den Weg dorthin.

Verteiltes System ohne klare Grenzen

Viele Dienste, eine gemeinsame Datenbank, synchrone Aufrufketten. Wir führen zusammen, wo die Aufteilung nichts gebracht hat, und ziehen Verträge dort, wo Entkopplung wirklich nötig ist.

Zweitmeinung vor einer Investitionsentscheidung

Ein Zielbild liegt vor, Budget und Zeitplan sind knapp. Wir prüfen Annahmen, Betriebsaufwand und Ausstiegskosten und benennen die Stellen, an denen der Plan bricht.

Ablösung eines proprietären Kerns

Eine zentrale Funktion hängt an einem Anbieterdienst mit steigenden Kosten. Wir bewerten offene Alternativen, planen Datenmigration und Parallelbetrieb und definieren Abbruchkriterien.

Ergebnis

  • Änderungen bleiben lokal, weil Datenhoheit und Schnittstellenverträge festgelegt und automatisiert geprüft sind.
  • Entscheidungen sind nachlesbar, auch wenn die beteiligten Personen nicht mehr im Projekt arbeiten.
  • Modernisierung läuft in einzeln rückrollbaren Schritten statt über einen großen Umstellungstermin.
  • Ausstiegskosten sind vor der Entscheidung bekannt, nicht erst bei der nächsten Preisanpassung.
  • Der Betrieb bleibt messbar: Traces und Latenzverteilungen zeigen, ob ein Schnitt tatsächlich trägt.
  • Neue Teammitglieder finden Struktur und Begründung im Repository statt in mündlicher Überlieferung.

Ablauf

Wie die Zusammenarbeit läuft

  1. 01 Analyse Bestandsaufnahme von System, Code und Betrieb. Am Ende steht eine belastbare Beschreibung des Ist-Zustands statt einer Vermutung.
  2. 02 Architektur Schnitt der Komponenten, Datenflüsse und Schnittstellen. Entscheidungen werden begründet und schriftlich festgehalten.
  3. 03 Entwicklung Umsetzung in kleinen, überprüfbaren Schritten. Jede Änderung ist nachvollziehbar, reviewbar und rückrollbar.
  4. 04 Automatisierung Alles, was mehr als einmal passiert, wird automatisiert: Build, Tests, Deployment und Infrastruktur.
  5. 05 Testing Tests dort, wo sie Risiko abdecken. Ziel ist Vertrauen in Änderungen, keine Abdeckungsquote als Selbstzweck.
  6. 06 Betrieb & Weiterentwicklung Software ist mit dem ersten Deployment nicht fertig. Betrieb, Beobachtbarkeit und Updates gehören zur Arbeit.

Fragen

Häufige Fragen zu Softwarearchitektur

Monolith oder Microservices – was empfehlen Sie?

Das hängt davon ab, ob unabhängige Auslieferung und unabhängige Skalierung tatsächlich gebraucht werden. Ein gut geschnittener Monolith mit klaren Modulgrenzen und einer Datenbank ist für die meisten Teams der günstigere Ausgangspunkt, weil er verteilte Transaktionen, Netzfehler und zusätzlichen Betriebsaufwand vermeidet. Aufteilen lohnt sich dort, wo Teile eines Systems unterschiedliche Lastprofile, Freigabezyklen oder Verfügbarkeitsanforderungen haben. Diese Frage entscheiden wir pro Grenze, nicht pauschal für das ganze System.

Können Sie eine bestehende Architektur bewerten, ohne sie umzubauen?

Ja, das ist ein eigenständiger Auftrag. Wir lesen Code, Schema, Build und Betriebskonfiguration und liefern einen Befund mit priorisierten Risiken, benannten Kopplungen und Aufwandsschätzungen je Schritt. Sie können damit intern weiterarbeiten oder anschließend einzelne Schritte umsetzen lassen. Zum Befund gehört auch, was wir nicht prüfen konnten und welche Annahmen in der Bewertung stecken.

Wie lange dauert eine Modernisierung?

Eine belastbare Zahl gibt es erst nach der Bestandsaufnahme, weil Umfang und Risiko am Datenmodell und an der vorhandenen Testabdeckung hängen. Planbar ist dagegen der Zuschnitt der Schritte: Jeder einzelne Schritt soll innerhalb weniger Wochen produktiv gehen und rückrollbar sein. So entstehen früh nutzbare Ergebnisse, statt eines Projekts, dessen Nutzen erst am Ende eintritt.

Was steht in einem Architecture Decision Record?

Kontext und Auslöser der Entscheidung, die geprüften Optionen mit ihren Nachteilen, die getroffene Entscheidung, die Konsequenzen und der aktuelle Status. Die Einträge liegen als Markdown-Dateien unter docs/adr/ im Repository und werden mit dem Code versioniert. Ersetzt eine neue Entscheidung eine alte, wird die alte nicht gelöscht, sondern als ersetzt markiert und verlinkt.

Wie vermeiden Sie Bindung an einzelne Anbieter?

Durch Trennung von Geschäftslogik und Plattformspezifika sowie durch Standards mit mehreren Implementierungen: SQL auf PostgreSQL, Container-Images nach OCI-Spezifikation, Telemetrie über OpenTelemetry, Infrastrukturbeschreibung im eigenen Repository. Anbieterspezifische Dienste werden hinter einer eigenen Schnittstelle isoliert, sodass sich der Aufwand eines Wechsels vorab abschätzen lässt. Vollständige Unabhängigkeit ist selten das Ziel – bekannte Ausstiegskosten dagegen immer.

Weiter im Zusammenhang

Kontakt

Softwarearchitektur besprechen

Beschreiben Sie kurz Ihr System und die offene Frage. Wir antworten mit einer fachlichen Einschätzung – ohne Vertriebsschleife.