Startseite / Artikel / 30 Tage KI-Programmierung ohne eigene Hand: fünf Architekturfallen in einem echten SaaS

30 Tage KI-Programmierung ohne eigene Hand: fünf Architekturfallen in einem echten SaaS

Ein Monat, in dem KI den gesamten Code eines produktiven Micro-SaaS schrieb, brachte Architekturdrift, fehlerhafte Webhooks, Debug-Schleifen, Aufblähung und ein Junior-Problem ans Licht.

1507 Wörter

Ende 2026 kam das übliche Getöse: Softwareentwicklung ist tot, KI schreibt jetzt den ganzen Code, natürliche Sprache ist die einzige Syntax, die man braucht. Um zu sehen, wo der Hype aufhört und die Produktion beginnt, galt in einem 30-Tage-Experiment eine strikte Regel: kein Anwendungscode von Hand. KI war hier keine Tipphilfe und keine Autovervollständigung. Der Mensch agierte als Architekturaufsicht und Reviewer, definierte Schemas, schrieb Anforderungen, las Diffs und gab Änderungen frei, während das Modell Logik, Abfragen und Integrationen schrieb.

Das Projekt war keine Todo-Liste. Es war ein echtes Micro-SaaS: Login, Migrationen, Nutzer-Dashboards, Stripe-Webhooks und öffentliche APIs mit Rate Limits. Es funktioniert, ist deployt und bedient echten Traffic. Die ersten 40 % des Aufbaus fühlten sich wie Zauberei an. Dann überschritt das Repository 15.000 Zeilen, verteilter Zustand kam hinzu, und die Idee „KI schreibt alles“ stieß an harte technische Grenzen. Sieben Fehlerarten wurden protokolliert. Fünf davon folgen hier, samt den Lehren daraus.

Die ersten Tage sind wirklich schnell

Fairerweise zuerst das: Ein neues Greenfield-Projekt aufzusetzen ist praktisch ein gelöstes Problem.

  • Ein modernes Full-Stack-Setup mit Next.js, Tailwind, PostgreSQL, Drizzle ORM, Auth-Middleware und Docker-Konfiguration war an einem Nachmittag fertig.
  • Repetitive Zod-Schemas, Validierungshelfer, sortierbare Tabellen und Paginierung entstanden mühelos, und vorhersehbare CRUD-Endpunkte kamen sauber und ohne einen einzigen Tippfehler.
  • Als eine einzelne Abfrage einen schlechten Ausführungsplan hatte, entdeckte das Modell schnell einen Fremdschlüssel ohne Index und schlug genau die passende Index-Migration vor.

Sechs Tage lang schien es, als könnte klassische Entwicklung überholt sein. Dann begann die zweite Woche.

Falle 1: lokaler Fokus, globale Drift

Die heimtückischste Schwäche ist lokale Kurzsichtigkeit. Ein Modell beurteilt die Datei oder Funktion in seinem Kontextfenster bemerkenswert präzise, sieht aber keine Konventionen, die drei Verzeichnisse weiter festgelegt sind.

Architectural Drift Anti-Pattern
┌─────────────────────────────────────────────────────────────┐
│ Core Utilities (/src/lib/utils/format.ts):                  │
│ └── export const formatCurrency = (cents: number) => ...    │
└─────────────────────────────────────────────────────────────┘
                              ▲
                 (The AI ignores this file)
                              │
┌─────────────────────────────────────────────────────────────┐
│ New Billing Module (/src/modules/billing/invoice.ts):       │
│ └── export const formatPriceUSD = (amount: number) => ...   │
│     (Re-implements logic with different rounding edge cases)│
└─────────────────────────────────────────────────────────────┘

Innerhalb von zwei Wochen hatte der Agent drei leicht unterschiedliche Helfer zur Währungsformatierung in getrennten Modulen geschrieben, eine Inline-Sitzungsprüfung in einem neuen Route-Handler neu implementiert, statt die vorhandene Middleware-Pipeline zu nutzen, und zwei widersprüchliche UserProfile-Interfaces in verschiedenen Paketen deklariert, die 90 % ihrer Felder teilten, Datumswerte aber unterschiedlich serialisierten.

Nichts davon löste einen Compilerfehler aus, und die Testläufe blieben grün. Doch in der Codebasis sammelte sich stille Architekturdrift an, jene strukturelle Fäulnis, die ein agiles Projekt in etwa sechs Monaten zu unwartbarem Altlasten-Chaos machen kann.

Falle 2: plausibler Code, der falsch ist

Die gefährlichsten von KI geschriebenen Bugs sind keine Abstürze oder Syntaxfehler, denn die ersten fängt der Compiler, die zweiten der Linter. Beängstigend sind die, die sich gut lesen, in lokalen Tests glatt laufen und still transaktionale Garantien brechen. Hier das tatsächliche Muster, das die KI für einen Stripe-Abrechnungs-Webhook produzierte:

// The AI's Initial Webhook Handler (Dangerous Anti-Pattern)
export async function handleStripeWebhook(req: Request) {
  const event = await parseStripeEvent(req);
  if (event.type === 'checkout.session.completed') {
    // 1. Immediately acknowledge event to Stripe
    sendImmediate200Response();     // 2. Perform async database update in unhandled background promise
    db.users.update({
      where: { customerId: event.data.object.customer },
      data: { isSubscribed: true }
    }).catch(err => logError(err));
  }
}

Auf einem Entwicklerrechner mit Testdaten besteht das jeden Test. Es bestätigt das Ereignis sofort, gibt 200 OK zurück und aktualisiert die lokale SQLite-Datenbank. In der Produktion unter Last ist es eine Katastrophe mit Ansage:

  • Läuft die Datenbank in diesem nicht abgewarteten Hintergrund-Promise in einen kurzzeitigen Verbindungs-Timeout oder einen Deadlock, verschwindet der Fehler spurlos.
  • Die Karte des Kunden wird belastet und Stripe verbucht den Webhook als zugestellt, aber das Konto wird nie hochgestuft.
  • Weil ein 200 zurückging, versucht Stripe es nie erneut, und die Transaktion ist endgültig verloren.

Wer je Race Conditions bei Zahlungen in der Produktion debuggt hat, erkennt es sofort: Webhooks müssen idempotent sein, die Verarbeitung muss innerhalb einer atomaren Transaktion abgeschlossen werden, und 200 OK darf erst zurückgehen, wenn der Zustand sicher gespeichert ist. Ein Junior, der den ordentlich aussehenden Diff übernimmt, hätte ihn ohne zu zögern freigegeben.

Falle 3: die endlose Selbst-Debug-Schleife

Immer wenn ein Bug von Zustand abhing, der außerhalb der gerade sichtbaren Datei verändert wurde, löste die Bitte an die KI, ihren eigenen Code zu reparieren, einen zermürbenden Kreislauf aus:

The Debugging Despair Loop
┌────────────────────────────────────────────────────────┐
│ 1. Bug Identified: State race condition in worker      │
└──────────────────────────┬─────────────────────────────┘
                           │
                           ▼
  [Prompt AI to Fix] ──► Confidently rewrites worker.ts
                           │
                           ▼
  [Run Tests] ─────────► Bug disappears; introduces memory leak
                           │
                           ▼
  [Point out Leak] ────► Confidently rewrites worker.ts again
                           │
                           ▼
  [Run Tests] ─────────► Re-introduces the original race condition!

Das Modell hatte keinen Laufzeit-Debugger, um Traces schrittweise zu durchlaufen, den Heap zu inspizieren oder verteiltes Timing zu beobachten, also stützte es sich auf Wahrscheinlichkeitsvermutungen aus Fehlermeldungen. Es erklärte den Bug fröhlich für behoben, zeigte einen sauberen Diff und brachte zwei Iterationen später den ursprünglichen Fehler zurück. Gelöst wurden solche Probleme nur, indem man manuell mit einem interaktiven Debugger eingriff und sich den rohen Thread-Zustand ansah.

Falle 4: kein Nein-Sagen möglich

Gute Technik hängt genauso davon ab, was man nicht baut, wie davon, was man ausliefert. Sollte das Modell ein Feature entwerfen, etwa eine Seite für Kontoeinstellungen, blähte es standardmäßig hemmungslos auf. Es lieferte 14 konfigurierbare Schalter, aufwendige Matrizen für Benachrichtigungseinstellungen und verschachtelte Tabs, nach denen kein Nutzer gefragt hatte. Bat man um Fehlerbehandlung, packte es jede interne Funktion in generische try/catch-Blöcke, die die eigentliche Exception verschluckten und "Something went wrong" zurückgaben, womit die Beobachtbarkeit dahin war.

Ein Modell hat kein Produktgespür und hält mehr Code für mehr Wert. Schnittstellen schlank halten, unnötige Abstraktionen streichen und lesbare Stacktraces bewahren bleiben menschliche Fähigkeiten.

Falle 5: die letzten 10 % kosten die Zeit

Software folgt einer harten Faustregel: Die ersten rund 80 % der Features verbrauchen 20 % des Zeitplans, die letzten 20 % die übrigen 80 %. KI automatisiert den ersten Teil vollständig. Oberflächengerüst, REST-Endpunkte und Standardformulare dauerten weniger als eine Woche. Die anderen drei Wochen gingen für die unordentliche Arbeit der echten Welt drauf:

  • Netzwerk-Jitter und Wiederholungen mit exponentiellem Backoff
  • Idempotente Datenbankschreibvorgänge über verteilte Webhooks hinweg
  • Wiederherstellungszustände für Randfälle, etwa wenn ein Nutzer mitten in einem OAuth-Callback auf Neu laden drückt
  • Speicherlecks in lange laufenden Hintergrund-Workern

Die KI denkt nicht an Randfälle, solange man nicht weiß, dass man sie danach suchen lassen muss, und dieses Wissen kostet Jahre an Narben aus der Produktion.

Das Junior-Paradox

Das Experiment widerlegte die simple Behauptung, KI werde Programmierer ersetzen. Automatisiert wurde die Einstiegsarbeit, die früher an Junior-Entwickler ging, nicht die Senior-Technik.

The Knowledge Pipeline Dilemma
Traditional Career Path:
[Junior: Scaffolding / CRUD] ──► [Mid-Level: Debugging / APIs] ──► [Senior: System Design]
                                                                        ▲
Today's Reality:                                                        │
[AUTOMATED BY AI]            ──► [AUTOMATED BY AI]            ──► [Senior Judgment Required]
                                                                        │
Question: Where do tomorrow's senior engineers build their intuition? ──┘

Boilerplate-Setup, Gerüste für Unit-Tests, CSS-Grid-Layouts und einfache CRUD-Abfragen sind genau das, woran Neulinge früher ihr mentales Modell von Softwaresystemen aufgebaut haben. Man kann nicht direkt in die Architektur verteilter Systeme springen, ohne Hunderte Stunden mit Syntax zu ringen, Off-by-one-Fehlern nachzujagen und zu lernen, warum schlecht entworfene Schemas unter Last zusammenbrechen. KI hat den Wert von Senior-Urteilsvermögen erhöht: plausibel falschen Code erkennen, unnötige Abstraktionen ablehnen und die gesamte Systemarchitektur im Kopf behalten, um Drift zu verhindern. Gleichzeitig hat sie die Leiter entfernt, auf der Juniors zu dieser Expertise aufgestiegen sind.

Was sich im Arbeitsablauf geändert hat

KI ist weiter im Einsatz, auch für den Großteil der rohen Textgenerierung, aber die Illusion, Code zu produzieren sei dasselbe wie Softwaretechnik, ist verflogen. Jetzt gelten drei Regeln:

  • Der Autor ist nie der Reviewer. Ein Agent, der einen Diff schreibt, sollte ihn nicht selbst prüfen. Setzen Sie einen separaten, gegnerischen Review-Agenten ein, der gezielt Randfallfehler suchen soll, oder lesen Sie jede Zeile selbst mit skeptischem Blick.
  • Bestandene Tests sind nur die Startlinie. Nehmen Sie nie einen Pull Request an, nur weil die Tests grün sind, denn Modelle schreiben gern Tests, die ihre eigenen fehlerhaften Annahmen bestätigen.
  • KI tippt, Menschen besitzen die Architektur. Lassen Sie die Maschine repetitive Syntax erzeugen, aber behalten Sie Datenmodelle, Systemgrenzen, transaktionale Garantien und betriebliche Invarianten unter menschlicher Führung.

Die Maschine schreibt Code schneller als jeder Mensch in der Geschichte. Trotzdem ist Code eine Verbindlichkeit, und das System, das er bildet, ist der Wert.