Nach über 30 Jahren Softwareentwicklung — von frühen Client-Server-Systemen bis hin zu modernen Cloud-Architekturen — habe ich einige Narben angesammelt. Manche von Technologien, die sich nicht durchgesetzt haben. Andere von Entscheidungen, die damals richtig erschienen, aber schlecht gealtert sind.
Hier sind fünf Architekturentscheidungen, die ich anders treffen würde, wenn ich die Zeit zurückdrehen könnte.
1. Ich hätte Event-Driven Architecture früher eingesetzt
Jahrelang habe ich Systeme mit synchronen Request-Response-Mustern überall gebaut. Service A ruft Service B auf, der Service C aufruft, und wenn irgendeiner davon langsam oder offline ist, bricht die gesamte Kette zusammen.
Der Wendepunkt kam, als ich an einem System zur Verarbeitung pharmazeutischer Daten arbeitete, das regulatorische Einreichungen abwickeln musste. Der synchrone Ansatz erzeugte eine fragile Pipeline, in der ein einzelner langsamer Downstream-Service kaskadierende Ausfälle im gesamten System verursachen konnte.
Was ich stattdessen tun würde: Von Tag eins auf Events und Message Queues setzen. Nicht alles muss asynchron sein, aber ein Event-Backbone gibt einem Resilienz, Auditierbarkeit und die Möglichkeit, neue Consumer hinzuzufügen, ohne bestehenden Code anzufassen.
Die Lektion: Synchrone Kommunikation ist der Standard, sollte es aber nicht sein. Setzt auf asynchron als Default und entscheidet euch bewusst für synchron, wenn ihr eine sofortige Antwort braucht.
2. Ich hätte früher in Observability investiert
In den frühen 2000ern bedeutete „Monitoring“, zu prüfen, ob der Server läuft und vielleicht die CPU-Auslastung im Auge zu behalten. Logs waren etwas, durch das man mit grep suchte, wenn etwas kaputtging.
Ich erinnere mich an einen Produktionsvorfall, bei dem ein subtiler Datenkorruptionsfehler drei Wochen brauchte, bis er gefunden wurde — weil wir kein strukturiertes Logging, kein Distributed Tracing und keine Möglichkeit hatten, Events über Services hinweg zu korrelieren. Drei Wochen Kundenauswirkungen, weil wir nicht sehen konnten, was unser System tat.
Was ich stattdessen tun würde: Observability als erstklassiges Architekturanliegen behandeln. Strukturiertes Logging ab Tag eins. Distributed Tracing über Service-Grenzen hinweg. Business-Level-Metriken, nicht nur Infrastruktur-Metriken.
Die Lektion: Man kann nicht reparieren, was man nicht sehen kann. Und wenn einem klar wird, dass man Observability braucht, steckt man bereits mitten in einem Vorfall.
3. Ich hätte mich stärker gegen voreilige Microservices gewehrt
Um 2015 herum wurden Microservices zur Antwort auf jede Frage. Ich habe Projekte beobachtet (und manchmal mitgemacht), die Monolithen in Dutzende Services aufgesplittet haben, bevor das Team, die Tools oder die operative Reife dafür vorhanden waren.
Ein Projekt, das ich beraten habe, hatte 23 Microservices, die von einem Team aus vier Entwicklern verwaltet wurden. Sie verbrachten mehr Zeit mit dem Debugging von Inter-Service-Kommunikation, dem Management von Deployments und dem Umgang mit verteilten Transaktionen als mit dem Bauen von Features.
Was ich stattdessen tun würde: Mit einem gut strukturierten Monolithen starten. Services erst dann extrahieren, wenn es einen klaren operativen Grund gibt — unabhängige Skalierung, unabhängige Deployment-Zyklen oder Team-Autonomie-Grenzen. Nicht, weil „Microservices Best Practice sind“.
Die Lektion: Microservices sind ein organisatorisches Skalierungsmuster, kein technisches. Wenn euer Team in einen Raum passt, braucht ihr sie wahrscheinlich nicht.
4. Ich hätte Datenbankdesign von Anfang an ernster genommen
Früh in meiner Karriere habe ich die Datenbank als dumme Speicherschicht behandelt. Daten rein, Daten raus. Schemadesign war ein Nachgedanke, und Normalisierung etwas, das ich „später fixen“ würde.
„Später“ kam nie. Ich habe Systeme gesehen, in denen eine einzige schlecht entworfene Tabelle zum Flaschenhals der gesamten Anwendung wurde. Wo fehlende Indizes eine 50-ms-Abfrage in einen 30-Sekunden-Albtraum verwandelten. Wo fehlende referentielle Integrität zu verwaisten Datensätzen führte, die monatelang Geschäftsberichte verfälschten, bevor es jemand bemerkte.
Was ich stattdessen tun würde: Zeit in saubere Datenmodellierung investieren. Query-Patterns verstehen, bevor man Schemas entwirft. Constraints und referentielle Integrität nutzen — sie sind nicht optional, sie sind das Sicherheitsnetz.
Die Lektion: Euer Anwendungscode wird mehrfach umgeschrieben. Eure Daten überleben alles davon. Entwerft euer Datenmodell so, als wäre es die wichtigste Architekturentscheidung — denn das ist sie wahrscheinlich.
5. Ich hätte öfter „Nein“ gesagt
Das ist keine technische Entscheidung, aber eine Architekturentscheidung im Verkleidung. Jede Feature-Anforderung, die ein „Ja“ bekommt, fügt Komplexität hinzu. Jede Integration fügt eine Abhängigkeit hinzu. Jeder „Quick Hack“ wird zu permanenter Infrastruktur.
Ich habe Codebasen gesehen, deren Architektur nicht wegen schlechter technischer Entscheidungen degradierte, sondern wegen einer Anhäufung von „Ja“. Ja zur einmaligen Export-Funktion. Ja zur eigenen Reporting-Engine. Ja zur Unterstützung dieses Legacy-Protokolls „nur für diesen einen Kunden“.
Was ich stattdessen tun würde: Architektonische Einfachheit als Feature behandeln. Jede Erweiterung muss ihren Komplexitätsaufwand rechtfertigen. Die beste Architektur ist nicht die, die alles kann — sondern die, die die richtigen Dinge gut macht.
Die Lektion: Das schwierigste Wort in der Softwarearchitektur ist „Nein“. Aber es ist auch das wertvollste.
Die Meta-Lektion
Rückblickend haben diese fünf Entscheidungen ein gemeinsames Thema: Sie alle handeln davon, Komplexität zu widerstehen. Event-Driven Architecture reduziert Kopplungskomplexität. Observability reduziert Debugging-Komplexität. Der Verzicht auf voreilige Microservices reduziert operative Komplexität. Gutes Datenbankdesign reduziert Datenkomplexität. „Nein“ sagen reduziert Feature-Komplexität.
Nach 30 Jahren ist das Wichtigste, was ich gelernt habe: Das Ziel ist nicht, das ausgeklügeltste System zu bauen. Es ist, das einfachste System zu bauen, das das Problem löst.
Alles andere ist Ego.