Blog
Teil 1 von 3 The Pragmatic Programmer

Broken Windows

4 min Lesezeit
bücher software-craft pragmatic-programmer

Stell dir vor: ein // TODO: fix later Kommentar in einer Codebase. Booking-Service, Retry-Logik. Schneller Hack, Freitagnachmittag, Sprint-Ende. “Mach ich Montag.”

Montag kommt. Passiert nicht.

Drei Monate später: git log --all --oneline | grep "TODO" | wc -l ergibt 47. Siebenundvierzig TODOs. Nicht alle vom selben Entwickler. Aber der erste war der Auslöser. Und als der nächste Kollege seine Retry-Logik genau so hacky schreibt, direkt neben dem ersten Hack ist klar: das war nicht sein Fehler. Das war das Signal.

The Pragmatic Programmer beschreibt genau diesen Moment. Und obwohl das Buch von 1999 ist, trifft es Dinge die heute noch schiefgehen.

Die Sache mit den kaputten Fenstern

Es gibt diese Studie aus den 80ern. Gebäude mit einem einzigen kaputten Fenster verfallen schneller als identische Gebäude ohne. Nicht weil das kaputte Fenster strukturellen Schaden anrichtet. Sondern weil es ein Signal sendet: hier kümmert sich niemand.

Software hat dieselbe Dynamik. Aber sie ist subtiler, weil du den Verfall nicht siehst. Du riechst ihn nicht. Du merkst ihn erst wenn ein neuer Entwickler im Team anfängt und nach zwei Wochen fragt: “Warum ist das alles so… so?”

So ein Hack ist ein kaputtes Fenster. Was danach typischerweise passiert, Schritt für Schritt:

  1. Woche 1: Ein // TODO: fix later in der Retry-Logik
  2. Woche 3: Ein Kollege schreibt Error-Handling im selben Service, ähnlich hacky. PR-Kommentar: “Analog zur bestehenden Retry-Logik”
  3. Woche 6: Neuer Microservice braucht ähnliche Logik. Copy-Paste aus dem ersten Service. Inkl. Hack.
  4. Woche 11: Jemand schlägt vor, die Retry-Logik in eine Shared Library zu extrahieren. Den Hack. Als Library.

Vom TODO zum institutionalisierten Workaround in elf Wochen.

“Don’t leave ‘broken windows’ unrepaired. Fix each one as soon as it is discovered.”

Das Buch hat recht. Aber es unterschlägt etwas: manchmal kannst du das Fenster nicht reparieren. Nicht am Freitag um 17 Uhr mit einem Deployment-Freeze vor dir. Und hier wird der Rat ein bisschen naiv. In der Realität hast du Deadlines, Stakeholder die auf Features warten, und eine Retry-Logik die funktioniert, nur halt hässlich. Was dann?

Was bei mir funktioniert hat: wenn ich den Hack nicht sofort fixen kann, schreib ich nicht // TODO. Ich schreib ein Ticket. Mit Akzeptanzkriterien. Und ich setz es in den nächsten Sprint. Nicht weil ich besonders diszipliniert bin, sondern weil TODOs im Code unsichtbar werden. Tickets in Jira sind unangenehm sichtbar. Und unangenehm sichtbar ist genau was du willst.

Der umgekehrte Effekt ist genauso real. Stell dir ein Projekt vor, das obsessiv sauber ist: 100% Lint-Compliance, kein einziger TODO im Code. Du schämst dich, dort unsauberen Code zu committen. Qualität erzeugt sozialen Druck. In beide Richtungen.

Aber hier ist die unbequeme Wahrheit: du machst das gerade. Irgendwo in deiner Codebase gibt es einen Hack den du vor Wochen geschrieben hast. Du weißt welchen. Und du weißt, dass inzwischen jemand anders daneben was Ähnliches gebaut hat.

Die perfekte API die niemand brauchte

Zweites Szenario.

Stell dir vor: Payment-API. Vier Entwickler, drei Monate. Jeder Edge Case abgedeckt: Partial Refunds mit Währungskonvertierung, idempotente Retry-Logik mit Idempotency Keys, Rate Limiting pro Merchant mit konfigurierbaren Tiers, Error Responses nach RFC 7807. 94% Test Coverage. Wunderschön.

Tag 1 in Production: 11 Requests. Elf. Davon 8 vom internen Healthcheck.

Die drei echten Requests benutzen alle denselben Endpoint: POST /payments. Keiner braucht Partial Refunds. Keiner benutzt die Währungskonvertierung. Keiner fasst die konfigurierbaren Rate-Limiting-Tiers an.

Drei Monate Arbeit. Drei Requests.

Das Buch sagt dazu:

“Great software today is often preferable to the fantasy of perfect software tomorrow.”

Und:

“Know when to stop.”

Das ist der Satz, der mir nicht mehr aus dem Kopf geht. Nicht “schreib schlechten Code.” Sondern: hör auf wenn es gut genug ist. Die Frage ist immer: gut genug für wen?

Ein internes Admin-Tool das drei Leute benutzen? Da reicht ein Handler, ein HTML-Template, und go run main.go. Ein Payment-System das echtes Geld bewegt? Da brauchst du Idempotency, Audit Logs, und Monitoring. Aber du brauchst das alles erst wenn du Nutzer hast die es brauchen.

Die vier Entwickler hätten in zwei Wochen eine API shippen können, die POST /payments und GET /payments/:id macht. Zwei Endpoints. Dann warten was die Merchants wirklich brauchen. Stattdessen haben sie drei Monate lang ihre eigenen Annahmen implementiert.

Perfektionismus in Software ist meistens keine hohen Standards. Es ist Angst. Angst, dass jemand einen Edge Case findet den du nicht abgedeckt hast. Angst vor einem Sentry-Alert. Angst vor dem Code Review. Und du baust diese Angst in drei Monate Arbeit ein, die niemand benutzt.

Welches Feature baust du gerade, von dem du schon weißt dass es wahrscheinlich niemand braucht?