Code is cheap, judgment is expensive

Warum im KI-Zeitalter die Grundlagen der Softwareentwicklung zurückkehren und warum die wichtigste Frage im Code-Review heute lautet: „Sollte es das in dieser Form überhaupt geben?“

2026 ist die wertvollste Fähigkeit in der Softwareentwicklung nicht mehr das Schreiben von Code. Es ist die Fähigkeit, einer KI zu sagen: Dieser Code ist falsch — und zu erklären, warum.

Das klingt nach einer Konferenzfolie. Fangen wir also mit etwas Unspektakulärem an: mit einem Pull Request.

Ein Agent bekommt die Aufgabe „Produktreservierung im Warenkorb hinzufügen“. Wenige Minuten später liegt ein PR vor: einige hundert Zeilen, ein neuer Endpoint, eine Migration, ein Dutzend Tests, alle grün. Die Beschreibung ist sorgfältiger als alles, was ein müder Mensch an einem Freitagnachmittag schreiben würde. Das Review dauert fünf Minuten, weil alles „gut aussieht“.

Drei Wochen später, während eines Sales, verkauft der Shop 40 Stück eines Produkts, von dem es 12 gab.

Der Code lief. Die Tests waren grün. Die Lösung war falsch. Zu diesem PR kommen wir noch zurück.

Dieser Text behauptet nicht, dass KI schlechten Code schreibt. Oft schreibt sie überdurchschnittlichen Code. Er behauptet etwas anderes: KI senkt die Kosten für das Erzeugen von Code radikal, erhöht aber den Wert der Fähigkeit zu beurteilen, ob dieser Code korrekt, sicher, wartbar und architektonisch richtig ist. Am wertvollsten ist heute nicht, wer am schnellsten Code produziert, sondern wer beurteilen kann, ob eine Lösung in dieser Form überhaupt entstehen sollte.

Kurz gesagt:

  • Code zu erzeugen wird schneller billiger, als ihn zu prüfen. Der Engpass hat sich vom Schreiben zu Review und Urteilsvermögen verschoben.
  • KI-Code ist selten einfach kaputt. Häufiger ist er lokal korrekt: Er besteht die Tests, hat aber ein falsches Datenmodell, eine Race Condition, eine Autorisierungslücke oder schadet dem Rest des Systems.
  • Urteilsvermögen, das einmal in Tests, Constraints und Berechtigungen festgehalten wird, skaliert. Urteilsvermögen, das bei jedem PR neu angewendet werden muss, nicht.
  • KI innerhalb einer Anwendung sollte die Berechtigungen der Person haben, für die sie handelt, und jede Datenänderung sollte ein Mensch freigeben.
  • Juniors, die ihre Arbeit vollständig an die KI delegieren, lernen deutlich weniger als diejenigen, die sich von der KI Dinge erklären lassen.

Code wird zur Massenware. Entscheidungen nicht

Simon Willison, Mitschöpfer von Django und Autor von Datasette, eröffnet den Leitfaden Agentic Engineering Patterns mit dem Kapitel „Writing code is cheap now“. Die These ist einfach: Die Kosten für eine erste funktionierende Version von Code sind fast auf null gefallen, guten Code zu liefern ist aber weiterhin teuer.

Interessanter als die These ist, wie Willison „guten Code“ definiert. Er muss funktionieren, aber auch überprüfbar sein, das richtige Problem lösen, Fehler sinnvoll behandeln, möglichst einfach sein, Tests und aktuelle Dokumentation haben, sich später ändern lassen und Qualitätsanforderungen wie Sicherheit oder Zuverlässigkeit erfüllen.

Von dieser Liste wird standardmäßig nur der erste Punkt billiger. Alles andere sind Entscheidungen.

Kent Beck, der Begründer von Extreme Programming, beschreibt dieselbe Verschiebung in einem Beitrag vom April 2023, geschrieben nach einem ersten Versuch mit ChatGPT: Der Wert von 90 % der eigenen Fähigkeiten sei auf null gefallen, die Hebelwirkung der übrigen 10 % um das Tausendfache gestiegen. Im ausführlicheren Essay zeigt sich, dass diese 10 % das Wissen sind, was sich zu tun lohnt und wonach man fragen sollte, nicht die Fähigkeit, Wörter geschickt aneinanderzureihen.

Es gibt auch eine einfachere, ökonomische Erklärung. In „Strategy Letter V“ aus dem Jahr 2002 erinnert Joel Spolsky an eine Grundregel: Wird ein Produkt billiger, steigt die Nachfrage nach seinen Komplementärgütern. Code und die Beurteilung von Code sind komplementär. Wird Code billiger, entsteht mehr davon, und jede neue Zeile braucht jemanden, der entscheidet, ob sie in Produktion gehen soll.

Die älteste Begründung stammt von 1986. In „No Silver Bullet“ unterscheidet Fred Brooks zwischen akzidenteller und essenzieller Komplexität. Die akzidentelle stammt aus unseren Werkzeugen: Syntax, Boilerplate, das Nachschlagen von Signaturen. Die essenzielle stammt aus dem Problem selbst: Was soll das System tun, welche Bedingungen müssen immer gelten, was passiert, wenn etwas ausfällt? Laut Brooks würde kein einzelnes Werkzeug einen Produktivitätssprung um eine Größenordnung bringen, weil keines die essenzielle Komplexität beseitigt.

LLMs sind der ernsthafteste Kandidat für eine Silver Bullet, den wir bisher gesehen haben. Doch ganz überwiegend greifen sie die akzidentelle Komplexität an. Die essenzielle ist geblieben, wo sie immer war — beim Menschen.


Mehr Code heißt nicht mehr Software

Wäre das Erzeugen von Code der Engpass, müsste billigerer Code direkt zu schnellerer Auslieferung funktionierender Software führen. Die Daten zeigen etwas Komplizierteres.

QuelleWas untersucht wurdeErgebnisEinschränkung
Faros AI, 2025Telemetrie von über 10.000 Entwicklerinnen und Entwicklern aus 1.255 Teamsin Teams mit hoher KI-Nutzung: +98 % gemergte PRs, +91 % Review-Zeit, +154 % durchschnittliche PR-Größe, +9 % Bugs pro Person; keine Verbesserung auf UnternehmensebeneAnbieter von Analysewerkzeugen; Korrelation, keine Kausalität
DORA, 2024Umfrage und statistisches Modell25 % mehr KI-Nutzung gingen mit 1,5 % weniger Liefer-Durchsatz und 7,2 % weniger Lieferstabilität einherModellschätzungen
DORA, 2025UmfrageKI erhöht erstmals den Durchsatz, erhöht aber weiterhin die Instabilität; sie verstärkt, was im Team bereits vorhanden istSelbstauskünfte
METR, 2025randomisierte Studie: 16 erfahrene Entwicklerinnen und Entwickler, 246 Aufgaben in gut bekannten Repositoriesmit KI dauerten Aufgaben 19 % länger, obwohl die Teilnehmenden glaubten, 20 % schneller gewesen zu seinWerkzeuge von Anfang 2025; neuere Daten von 2026 deuten auf eine Beschleunigung hin, METR selbst hält sie wegen Selektionseffekten aber für unzuverlässig
Stack Overflow, 2025Entwicklerumfrage66 % nennen KI-Antworten, die „fast richtig, aber eben nicht ganz“ sind, als größte Frustration; 46 % misstrauen ihrer Genauigkeit, 33 % vertrauen ihrSelbstauskünfte, keine Messung
CodeRabbit, 2025470 Open-Source-Pull-RequestsPRs mit KI-Beteiligung hatten im Schnitt 1,7× mehr Probleme und 75 % mehr LogikfehlerAnbieter eines KI-Review-Werkzeugs; automatisierte Analyse
GitClear, 2025211 Mio. geänderte Codezeilender Anteil verschobenen Codes, ein Näherungswert für Refactoring, fiel von 25 % (2021) auf unter 10 % (2024); kopierter Code stieg von 8,3 % auf 12,3 %fällt zeitlich mit der Ära der KI-Assistenten zusammen, kein Kausalitätsbeweis

Keine dieser Studien entscheidet die Frage für sich allein. Zusammen zeigen sie aber ein konsistentes Muster: Das Erzeugen wurde schneller, das Prüfen nicht.

Das ist Amdahls Gesetz, angewandt auf ein Team. Ein System ist so schnell wie seine langsamste Stufe. Wird das Schreiben von Code um ein Vielfaches schneller, während Review, Tests, Deployment und Fehlersuche ihr Tempo behalten, verschiebt sich der Engpass einfach. Von der Tastatur zum Urteilsvermögen.

Am beunruhigendsten ist das Ergebnis von METR, und zwar nicht wegen der 19 % an sich. Das Problem ist die Lücke zwischen Wahrnehmung und Wirklichkeit. Ein Team, das sich schneller fühlt, sucht nicht nach seinem Engpass.


Läuft ≠ richtig. Sechs Arten, wie KI korrekten, falschen Code schreibt

Die folgenden Beispiele haben eines gemeinsam: Sie bestehen die Tests, sehen professionell aus und würden ein eiliges Review überstehen. Es sind Zusammensetzungen typischer Muster, keine Beschreibungen konkreter Vorfälle. Sie passen aber zu dem, was OX Security im Bericht „Army of Juniors“ nach der Analyse von 300 Repositories beschrieben hat: KI-generierter Code ist hochfunktional, aber es fehlt ihm systematisch an architektonischem Urteilsvermögen. Zu den häufigsten Anti-Patterns zählt der Bericht Überspezifikation, das Vermeiden von Refactorings, das „Bei mir lief es“-Syndrom und vorgetäuschte Testabdeckung.

1. Abstraktion auf Vorrat

Aufgabe: „Nach bezahlter Bestellung eine E-Mail an den Kunden senden“.

type Notifier interface {
	Notify(ctx context.Context, n Notification) error
}

type NotifierFactory struct {
	registry map[Channel]func(cfg Config) (Notifier, error)
}

func (f *NotifierFactory) Register(ch Channel, ctor func(Config) (Notifier, error)) {
	f.registry[ch] = ctor
}

// EmailNotifier — fertig
// SMSNotifier, PushNotifier, WebhookNotifier — TODO

Der Code kompiliert, der Test für den E-Mail-Kanal ist grün, alles wirkt „enterprise“.

Das Problem: Wir haben jetzt vier Abstraktionen für einen einzigen Anwendungsfall. Jeder künftige Leser, ob Mensch oder Agent, muss Registry, Factory und Konfiguration verstehen, um eine E-Mail zu verschicken. Die leeren Kanäle geben vor, Erweiterungspunkte zu sein, die nie wirklich entworfen wurden. Kommt eine echte SMS-Anforderung, braucht sie ohnehin anderes: Einwilligungen, Kosten, Limits, andere Wiederholungsregeln. In das vorbereitete Interface passt sie trotzdem nicht.

Eine Funktion hätte gereicht: sendOrderPaidEmail(ctx, order). Eine Abstraktion lohnt sich, wenn der zweite echte Anwendungsfall auftaucht, nicht dann, wenn das Modell ein Entwurfsmuster kennt.

Die Frage, die Urteilsvermögen stellt: Wie viele echte Anwendungsfälle hat diese Abstraktion heute?

2. Ein Datenmodell, das nach einem Monat zu lügen beginnt

Aufgabe: „Bestellhistorie hinzufügen“.

CREATE TABLE order_items (
  id         BIGSERIAL PRIMARY KEY,
  order_id   BIGINT REFERENCES orders(id),
  product_id BIGINT REFERENCES products(id),
  quantity   INT NOT NULL
);
-- Bestellsumme: SUM(products.price * order_items.quantity)

Der Test legt ein Produkt und eine Bestellung an und prüft die Summe. Alles stimmt.

Bis zur ersten Preisänderung. Ab diesem Moment ändern historische Bestellungen und Rechnungen rückwirkend ihren Wert, weil die Bestellposition auf den aktuellen Zustand des Produkts zeigt, statt festzuhalten, was tatsächlich gekauft wurde. Ein Produkt aus dem Katalog zu entfernen, wird entweder vom Fremdschlüssel blockiert oder zerstört die Historie. Landet der Preis zusätzlich in einer FLOAT-Spalte, kommen Rundungsfehler bei Geldbeträgen hinzu.

Ein korrektes Modell speichert in der Bestellposition einen Snapshot: Stückpreis, Name, SKU und Währung zum Kaufzeitpunkt, und hält Beträge als NUMERIC oder als Ganzzahl in Cent. So arbeitet auch das Shop-Modell von GoatCMS: shop_order_item speichert eigene Werte für title, sku, unit_price und line_total, unabhängig von späteren Produktänderungen.

Fehler im Datenmodell sind die teuersten von allen, denn Code lässt sich in einer Minute neu erzeugen. Zwei Jahre Geschäftsdaten nicht.

Die Frage, die Urteilsvermögen stellt: Was ist eine historische Tatsache und was der aktuelle Zustand?

3. Eine Race Condition, die kein Unit-Test sieht

Zurück zum PR vom Anfang.

func Reserve(ctx context.Context, db *sql.DB, productID int64, qty int) error {
	var stock int
	err := db.QueryRowContext(ctx,
		`SELECT stock FROM products WHERE id = $1`, productID).Scan(&stock)
	if err != nil {
		return err
	}
	if stock < qty {
		return ErrOutOfStock
	}
	_, err = db.ExecContext(ctx,
		`UPDATE products SET stock = $1 WHERE id = $2`, stock-qty, productID)
	return err
}

Die Tests rufen diese Funktion nacheinander auf, also funktioniert alles. In Produktion lesen zwei Requests gleichzeitig stock = 1, beide bestehen die Prüfung, beide schreiben 0. Wir haben zwei Stück von einem verkauft. Das ist das klassische Check-then-Act-Muster und ein Lost Update.

Die Korrektur ist kürzer als das Original:

UPDATE products
SET stock = stock - $1
WHERE id = $2 AND stock >= $1;
-- 0 betroffene Zeilen bedeutet: nicht vorrätig

Dieselbe Problemklasse taucht bei Zahlungs-Webhooks wieder auf. Der Zahlungsanbieter wiederholt eine Benachrichtigung, also läuft der Handler zweimal. Ohne Idempotenzschlüssel und Unique-Constraint in der Datenbank gibt es zwei Lizenzen oder zwei Pakete.

Die Frage, die Urteilsvermögen stellt: Was passiert, wenn dieser Code zweimal gleichzeitig läuft? Und zweimal hintereinander?

4. Code, der Ausfälle versteckt

Aufgabe: „Das Dashboard stürzt ab, wenn die Zahlungs-API nicht antwortet — beheben“.

payments, err := client.ListPayments(ctx, since)
if err != nil {
	log.Println("could not fetch payments")
	return []Payment{}, nil
}

Das Dashboard stürzt nicht mehr ab. Ticket geschlossen.

Nur ist der Fehler jetzt zu Daten geworden. „Null Zahlungen“ ist nicht mehr von „wir wissen nicht, wie viele Zahlungen es gab“ zu unterscheiden. Das Log enthält weder Ursache noch Request-ID noch Antwortzeit. Es gibt keine Metrik und keinen Alert. Wer nachts Bereitschaft hat, sieht einen Umsatz von null und weiß nicht, ob die Integration ausgefallen ist oder das Geschäft ein Problem hat.

Eine bessere Version gibt den Fehler oder einen expliziten Zustand „Daten nicht verfügbar“ zurück, loggt strukturiert mit Kontext, erhöht einen Fehlerzähler für die Integration und ergänzt einen Tracing-Span. Observability ist kein Logging „für alle Fälle“. Sie ist die Fähigkeit, einem laufenden System eine Frage zu stellen, die niemand vorhergesehen hat.

Die Frage, die Urteilsvermögen stellt: Wie erfahre ich, dass das nicht funktioniert, und warum?

5. Eine Schwachstelle, die man im Happy Path nicht sieht

// GET /api/orders/{id}, hinter einer Middleware, die Login verlangt
func (h *Handler) GetOrder(w http.ResponseWriter, r *http.Request) {
	order, err := h.repo.FindByID(r.Context(), r.PathValue("id"))
	if err != nil {
		http.Error(w, "not found", http.StatusNotFound)
		return
	}
	json.NewEncoder(w).Encode(order)
}

Der Endpoint ist „gesichert“, weil er eine Session verlangt. Trotzdem kann jede angemeldete Person fremde Bestellungen lesen, indem sie die ID in der URL ändert. Das ist Broken Object Level Authorization, Platz eins der OWASP API Security Top 10. Die Tests sind grün, weil beim Testen nur die eigenen Bestellungen abgefragt werden.

Die Korrektur ist eine auf den Eigentümer beschränkte Abfrage, etwa FindByIDForOwner(ctx, id, session.UserID), die für einen nicht existierenden und einen fremden Datensatz dasselbe 404 liefert, damit der Endpoint nicht verrät, welche IDs existieren.

Die Datenlage ist hier ungewöhnlich eindeutig. Veracode hat im Bericht von 2025 über 100 Modelle mit 80 Aufgaben getestet: In 45 % der Fälle enthielt der erzeugte Code eine Schwachstelle, und größere, neuere Modelle schnitten nicht deutlich besser ab. Abhängigkeiten sind eine eigene Risikoklasse. Eine auf der USENIX Security 2025 vorgestellte Studie ergab, dass kommerzielle Modelle in mindestens 5,2 % der Fälle nicht existierende Pakete vorschlugen, offene Modelle in 21,7 %. 43 % der erfundenen Namen tauchten in jeder von zehn Wiederholungen desselben Prompts wieder auf. Das macht sie zu einem vorhersehbaren Ziel: Man muss nur ein Paket mit diesem Namen registrieren. Der Angriff heißt Slopsquatting. Über die Risiken der Installation von Abhängigkeiten haben wir in npm install sollte nicht heißen: „Fremden Code ausführen“ geschrieben.

Die Frage, die Urteilsvermögen stellt: Wer kann diesen Code noch aufrufen, und an wessen Daten kommt er dabei?

6. Lokal korrekt, global schädlich

Aufgabe: „Der Integrationstest läuft manchmal in einen Timeout beim Preisdienst — Retry hinzufügen“.

for attempt := 0; attempt < 4; attempt++ {
	resp, err = pricing.Get(ctx, sku)
	if err == nil {
		break
	}
}

Lokal ist alles in Ordnung: Der wackelige Test wird grün.

Global haben wir gerade einen Ausfallverstärker gebaut. Das Google SRE Book beschreibt genau diesen Mechanismus: Wiederholen drei Schichten eines Systems jeweils dreimal, kann eine einzige Nutzeraktion 4 × 4 × 4 = 64 Versuche gegen einen Dienst erzeugen, der ohnehin schon Probleme hat. Retries ohne exponentielles Backoff, zufälligen Jitter und ein Retry-Budget machen aus einer Verlangsamung einen kaskadierenden Ausfall.

Der Agent hat eine Datei gesehen. Das Problem steckt im Aufrufgraphen, der nie in seinem Kontext war.

Die Frage, die Urteilsvermögen stellt: Was macht diese Änderung mit dem Rest des Systems, wenn bereits etwas ausfällt?

Test gegen Urteilsvermögen

BeispielWas der Test geprüft hatWas Urteilsvermögen fragt
Abstraktion auf Vorratwurde die E-Mail verschicktwie viele echte Anwendungsfälle hat diese Abstraktion?
Datenmodellstimmt die Bestellsummewas ist historische Tatsache, was aktueller Zustand?
Nebenläufigkeitfunktioniert die Reservierungwas, wenn der Code zweimal gleichzeitig läuft?
Observabilitybleibt das Dashboard stabilwie erfahre ich von einem Ausfall und seiner Ursache?
Sicherheitsieht der Eigentümer die eigene Bestellungwer kann das sonst noch aufrufen?
Retryist der Test grünwas macht die Änderung während eines Ausfalls mit dem System?

Keine dieser Fragen betrifft die Syntax. Alle betreffen Konsequenzen.


Seniorität: von „Wie schreibe ich das?“ zu „Sollte man das so machen?“

Jahrelang beruhte ein Teil des Werts erfahrener Leute auf Geschwindigkeit: APIs kennen, die Fallen des Frameworks im Kopf haben, ohne Blick in die Dokumentation schreiben. Diesen Teil übernimmt heute ein Agent, der mehr APIs kennt als jeder von uns.

Übrig bleibt, was der Agent nicht im Kontext hat: das Wissen, was man nicht bauen sollte, wie man Daten modelliert, wie ein System ausfällt und was es kostet, eine Entscheidung rückgängig zu machen.

Der Bericht von OX Security beschreibt KI treffend als eine Armee talentierter, aber unerfahrener Juniors. Daraus folgt eine unbequeme Schlussfolgerung: Wer mit einem Agenten arbeitet, leitet eine solche Armee. Juniors, die nie müde werden, nie Fragen stellen und immer überzeugt klingen.

Addy Osmani von Google nennt diese Asymmetrie „das 70-%-Problem“: KI liefert schnell den Großteil einer Lösung, aber die letzten 30 % — Grenzfälle, Integrationen, Sicherheit und Performance — erfordern genau das Wissen, das das Werkzeug nicht ersetzt. Deshalb profitieren Erfahrene stärker von KI. Sie bewerten, korrigieren und verwerfen ständig. Weniger Erfahrene übernehmen das Ergebnis häufiger als Ganzes.

Noch tiefer geht Peter Naur. Der Essay „Programming as Theory Building“ von 1985 argumentiert, dass ein Programm vor allem eine Theorie in den Köpfen der Menschen ist, die es bauen, und der Code nur eine unvollständige Aufzeichnung dieser Theorie. Verlässt das Team, das die Theorie trägt, das Projekt, beginnt das Programm zu sterben, auch wenn der Code noch kompiliert.

KI kann Code ohne Theorie erzeugen. Osmani nennt die Folge Comprehension Debt, also Verständnisschulden: die wachsende Lücke zwischen der Menge an Code in einem System und der Menge, die irgendjemand wirklich versteht. Aus „The Elements of Programming Style“ von Kernighan und Plauger stammt die Beobachtung, dass Debuggen doppelt so schwer ist wie Schreiben. Entsteht Code an der Grenze unseres Verständnisses, werden wir ihn nicht debuggen können.

Willison formuliert eine praktische Regel: keinen Code committen, den man niemand anderem erklären könnte. Wurde von einem LLM geschriebener Code geprüft, getestet und verstanden, ist das schlicht Softwareentwicklung. Am anderen Ende des Spektrums steht Vibe Coding: bauen, ohne darauf zu schauen, wie der Code funktioniert.

Acht Fragen an jeden KI-generierten PR

  1. Welches Problem löst diese Änderung, und ist es ein Problem, das wir wirklich haben?
  2. Was berührt diese Änderung, das sie nicht berühren sollte?
  3. Welche Invarianten müssen nach der Änderung gelten, und was erzwingt sie: ein Test, ein Typ, ein Datenbank-Constraint oder Hoffnung?
  4. Was passiert bei zwei parallelen Aufrufen oder bei einer Wiederholung?
  5. Wie fällt das aus, und woher erfahren wir es?
  6. Wer kann das aufrufen, und auf welche Daten bekommt er Zugriff?
  7. Was kostet es, diese Entscheidung in einem halben Jahr rückgängig zu machen, wenn Daten, eine öffentliche API oder andere Teams davon abhängen?
  8. Kann ich diese Änderung erklären, ohne den Code laut vorzulesen?

Review ist der neue Engpass. Schneller lesen macht ihn nicht breiter

Seit Urteilsvermögen zum Engpass geworden ist, beginnen Organisationen, es explizit zu steuern.

Im März 2026 berichtete die Financial Times über interne Amazon-Unterlagen, die eine Reihe von Ausfällen mit „großem Explosionsradius“ mit Änderungen in Verbindung brachten, die mithilfe generativer KI entstanden waren. Laut FT sollten KI-gestützte Änderungen von Junior- und Mid-Level-Engineers künftig eine Freigabe durch Senior Engineers benötigen. Amazon widersprach: Nach Angaben des Unternehmens betraf nur einer der besprochenen Vorfälle KI, keiner betraf von KI geschriebenen Code, und eine solche Vorgabe sei nicht eingeführt worden. Wer auch immer im Detail recht hat: Schon der Streit zeigt, dass die Frage „Wer gibt eine KI-generierte Änderung frei?“ auf Vorstandsebene angekommen ist.

Der Thoughtworks Technology Radar führt „complacency with AI-generated code“, also unkritisches Vertrauen in KI-Code, im Ring Hold. Das Radar-Team weist darauf hin, dass Agenten immer größere Änderungssätze erzeugen und Entwicklerinnen und Entwickler immer weniger bereit sind, sie zu prüfen.

„Dann reviewen wir eben gründlicher“ reicht nicht. Gibt es doppelt so viele PRs und ist jeder zweieinhalbmal so groß, hört zeilenweises Lesen auf, eine Strategie zu sein.

Eine interessantere Antwort zeigt OpenAI im Artikel über Harness Engineering vom Februar 2026. Ein kleines Team baute in fünf Monaten ein Produkt mit rund einer Million Codezeilen, ohne eine einzige davon von Hand zu schreiben. Menschen gestalteten die Arbeitsumgebung der Agenten, formulierten die Absicht und bauten Feedbackschleifen. Architekturgrenzen standen nicht in einem Dokument mit der Bitte, sie einzuhalten. Sie wurden von Lintern und strukturellen Tests erzwungen.

Birgitta Böckeler von Thoughtworks beschreibt einen solchen Harness als Kombination aus Guides, die den Agenten vor dem Handeln steuern, und Sensoren, die das Ergebnis danach prüfen. Böckeler merkt allerdings an, dass in der Beschreibung von OpenAI die Verifikation von Funktionalität und Verhalten fehlt. Linter bewachen die Struktur. Ob das System tut, was es soll, sagen sie nicht.

Daraus folgt die wichtigste Unterscheidung dieses Textes:

Urteilsvermögen, das einmal angewendet und als Test, Typ, Constraint oder Berechtigung festgehalten wird, skaliert. Urteilsvermögen, das bei jedem PR neu angewendet wird, nicht.

Ausführlicher über das Übersetzen von Entscheidungen in Verträge haben wir in From Vibe Coding to Contract-Driven AI Development (englisch) geschrieben. Hier sei nur ergänzt: KI kann beim Review helfen, aber ein Modell sollte nicht der einzige Richter über die eigene Arbeit sein. Jemand muss die Entscheidung verantworten, und Verantwortung lässt sich keinem Modell zuweisen.


Wenn KI zur Nutzerin der Anwendung wird: Urteilsvermögen in Berechtigungen

Bisher ging es um KI, die Code schreibt. Es gibt eine zweite, immer wichtigere Front: KI, die innerhalb der Anwendung arbeitet. Sie liest Daten, füllt Formulare aus, schlägt vor, einen Datensatz zu löschen.

Hier lautet die Frage nicht mehr „Ist dieser Code gut?“, sondern: Was darf dieser Agent tun, in wessen Namen, und wer gibt es frei?

Im Juli 2025 löschte ein Replit-Agent, der an einem von Jason Lemkin geführten SaaStr-Projekt arbeitete, trotz eines ausdrücklichen Code-Freeze eine Produktionsdatenbank. Laut The Register erzeugte der Agent außerdem rund 4.000 fiktive Datensätze, meldete falsche Testergebnisse und behauptete, eine Wiederherstellung der Daten sei unmöglich, was sich als falsch herausstellte. Der Agent selbst nannte sein Vorgehen „a catastrophic error of judgement“.

Das Problem war nicht die Intelligenz des Modells. Das Problem war, dass der Agent Berechtigungen hatte, bei denen niemandes Urteilsvermögen in der Schleife war.

Die Branche hat dafür bereits ein Vokabular. Die OWASP Top 10 for LLM Applications 2025 beschreiben das Risiko Excessive Agency und führen es auf drei Ursachen zurück: übermäßige Funktionalität, übermäßige Berechtigungen und übermäßige Autonomie. Eine der empfohlenen Maßnahmen ist eine menschliche Freigabe vor Aktionen mit großer Wirkung. Willison nennt die Kombination dreier Eigenschaften die „tödliche Dreifaltigkeit“: Zugriff auf private Daten, Kontakt mit nicht vertrauenswürdigen Inhalten und die Möglichkeit, nach außen zu kommunizieren. Meta schlägt die Agents Rule of Two vor: Ein unbeaufsichtigter Agent sollte höchstens zwei von drei Eigenschaften haben — nicht vertrauenswürdige Eingaben verarbeiten, Zugriff auf sensible Daten oder Systeme, und Zustand ändern oder nach außen kommunizieren. Braucht er alle drei, braucht er auch einen Menschen in der Schleife.

Wie das Harness-Modul von GoatCMS damit umgeht

Das Harness-Modul ergänzt das Admin-Panel um einen KI-Assistenten, der mit den Daten der Anwendung arbeitet. Am interessantesten sind darin die Entscheidungen darüber, was der Assistent nicht tun kann.

Risiko laut OWASP LLM06Antwort des Harness-Moduls
Übermäßige Funktionalitätjede freigegebene Entität bekommt drei generierte Werkzeuge: query_<entität>, open_<entität>_form und confirm_delete_<entität>; der Agent führt weder Code noch beliebiges SQL aus
Übermäßige Berechtigungender effektive Zugriff ist die Konjunktion aus der Rollenmaske der angemeldeten Person und der Harness-Maske der Entität
Übermäßige Autonomieder Agent schreibt oder löscht nie selbst Daten; er öffnet ein Formular oder einen Bestätigungsdialog, und ein Mensch entscheidet

KI ist eine weitere Nutzerin der Anwendung, kein Servicekonto. Der Agent arbeitet mit den Berechtigungen der Person, die mit ihm spricht. Er sieht keine Felder, die deren Rolle nicht lesen darf, selbst wenn die Entität sie dem Assistenten freigibt. Ebenso sieht er keine Felder außerhalb der für den Assistenten freigegebenen Liste, selbst wenn die Rolle sie lesen darf. Keine der beiden Masken reicht allein.

Diese Entscheidung steht im Anwendungsmodell, nicht im Prompt:

module:add --name=harness \
    --property:list:list="username,email" \
    --property:list:persist="role,username,email,phone,shipping_recipient,shipping_street,shipping_unit,shipping_postal_code,shipping_city,shipping_country,billing_recipient,billing_street,billing_unit,billing_postal_code,billing_city,billing_country"

Die Menge persist, also die Felder, die der Assistent in einem Formular vorausfüllen darf, lässt password und email_verified_at bewusst aus. Selbst wenn die Rolle das Passwort schreiben darf, kann der Agent keinen Wert für dieses Feld vorschlagen. Niemand muss bei jedem Review daran denken. Der Generator erzwingt es jedes Mal.

Lesen ist eng begrenzt und parametrisiert. Das Werkzeug query_<entität> ist rein lesend. Tabellen- und Spaltennamen stammen aus einer generierten Registry und werden validiert, und vom Modell gelieferte Werte gelangen ausschließlich als Abfrageparameter in SQL. Filter unterstützen nur Gleichheit, und Ergebnisse sind durch ein Zeilenlimit begrenzt. Eine Gesprächsrunde kann höchstens fünf Runden lesender Werkzeuge ausführen, sodass sich das Modell nicht endlos im Kreis drehen kann.

Zustandsänderungen laufen immer über einen Menschen. Frontend-Werkzeuge werden nie auf dem Server ausgeführt. Sie verwandeln die Anfrage des Agenten in eine Browser-Aktion: ein vorausgefülltes Formular oder einen Löschdialog mit den echten Daten des Datensatzes. Pro Gesprächsrunde ist höchstens eine solche Aktion möglich. Fordert der Agent eine an, ist die Chat-Antwort eine feste Servermeldung und kein vom Modell geschriebener Text. Das Modell kann also nicht „Erledigt, gelöscht“ schreiben, bevor ein Mensch irgendetwas bestätigt hat. Im Replit-Vorfall gehörten gerade die falschen Berichte des Agenten zu den gefährlichsten Elementen.

Fehlender Zugriff verrät nicht, dass Daten existieren. Existiert ein Datensatz nicht oder ist keines seiner Felder lesbar, bleibt die Vorschau einfach leer. Die ID eines fremden Gesprächs verhält sich so, als gäbe es dieses Gespräch nicht. Es ist dasselbe Muster, das im verwundbaren Bestell-Endpoint oben gefehlt hat.

Die Regeln „keine Daten ändern“ und „keine Feldnamen oder Datensatz-IDs erfinden“ stehen auch im System-Prompt. Dort sind sie jedoch Anweisungen an das Modell, keine Sicherheitsgrenze. Die Grenze ist Code, der nur ausführt, was die Masken erlauben.

Urteilsvermögen, das sich nicht automatisieren lässt

Fairerweise muss man sagen, was dieser Entwurf nicht löst.

Ergebnisse lesender Werkzeuge gehen als Teil des Gesprächs an den Modellanbieter. Ein Feld in die Menge list aufzunehmen, ist daher eine Entscheidung, es mit einem externen KI-Anbieter zu teilen. Kein Generator trifft diese Entscheidung für das Team.

Daten in Datensätzen können außerdem von Kundinnen und Kunden stammen, etwa aus Bestellanmerkungen. Das sind nicht vertrauenswürdige Eingaben, die versuchen können, die Vorschläge des Modells zu steuern. Genau deshalb endet jede Änderung in einem Formular, das ein Mensch sieht und abschickt.

Und schließlich haben Einschränkungen ihren Preis. Keine Bereiche und keine Sortierung in Filtern, eine Aktion pro Runde: Das macht den Assistenten weniger „magisch“. Es ist ein bewusst langweiliger Entwurf. Langweilige Systeme sind leichter vorherzusagen.

In diesem Modell ist KI die Assistenz der Nutzenden, nicht ihr Ersatz. Sie bereitet die Arbeit vor: findet Datensätze, füllt das Formular aus, zeigt, was gelöscht würde. Die Entscheidung trifft ein Mensch. Das ist die ganze These dieses Artikels im Kleinen: Einen Vorschlag zu erzeugen ist billig; ihn freizugeben hat Wert, weil Verantwortung dahintersteht.


Juniors: Lernt nicht Prompting statt Verstehen

Der häufigste Rat für Einsteigerinnen und Einsteiger lautet heute: „Lerne, gut zu prompten.“ Das ist eine nützliche Fähigkeit, aber eine, die man in Wochen beherrscht. Systeme zu verstehen dauert Jahre. Und genau dieses Verständnis entscheidet, ob man einer KI sagen kann, dass der erzeugte Code falsch ist.

Im Januar 2026 veröffentlichten Forschende von Anthropic ein Experiment mit 52 überwiegend unerfahrenen Entwicklerinnen und Entwicklern, die die unbekannte asynchrone Bibliothek Trio lernten. Die Hälfte durfte einen KI-Assistenten nutzen. In einem Verständnistest ohne KI erreichte die Gruppe mit Assistent im Schnitt 50 %, die Gruppe ohne 67 %. Die KI-Gruppe war dabei nicht statistisch signifikant schneller. Der größte Unterschied zeigte sich bei Fragen zum Debugging.

Wichtiger ist ein anderes Ergebnis. Wer die KI nach Konzepten fragte und sich Dinge erklären ließ, erreichte 65 % und mehr. Wer das Schreiben des Codes vollständig delegierte, lag unter 40 %. Dasselbe Werkzeug. Eine andere Art, es zu nutzen.

Eine Studie von Microsoft Research und Carnegie Mellon aus dem Jahr 2025, basierend auf einer Umfrage unter 319 Wissensarbeiterinnen und Wissensarbeitern, zeigte einen ähnlichen Mechanismus: Je größer das Vertrauen in KI, desto weniger kritisches Denken. Je größer das Vertrauen in die eigenen Fähigkeiten, desto mehr.

Dieses Paradox beschreibt bereits Lisanne Bainbridges klassische Arbeit „Ironies of Automation“ von 1983. Automatisierung überlässt dem Menschen die schwierigsten Aufgaben: Überwachung und Eingreifen, wenn etwas schiefgeht. Gleichzeitig nimmt sie ihm die tägliche Praxis, durch die er die nötige Kompetenz aufbauen könnte.

Deshalb sollte man auch den Einstieg dieses Textes hinterfragen. Code zu schreiben ist nicht mehr die wertvollste Fähigkeit. Aber es ist immer noch der beste Weg, zu lernen, Code zu beurteilen.

In der Praxis:

  • Versuche ein Problem zuerst selbst zu lösen und vergleiche deine Lösung dann mit der der KI. Die Unterschiede sind dein Lernmaterial.
  • Frage die KI „Warum?“ und „Was kann hier schiefgehen?“, nicht nur „Schreib das“.
  • Debugge regelmäßig ohne Agenten: Stacktrace, Debugger, Logs, Profiler.
  • Lerne die Dinge, die man in einer einzelnen Datei nicht sieht: Datenmodellierung, Transaktionen und Isolationsstufen, HTTP, Authentifizierung und Autorisierung, Logs, Metriken und Tracing.
  • Lies öffentliche Postmortems von Ausfällen. Sie sind verdichtetes Urteilsvermögen von Menschen, die für ihre Fehler bezahlt haben.
  • Halte dich an Willisons Regel: Committe keinen Code, den du nicht erklären kannst.

Für Teamleads gilt das spiegelbildlich: Lasst Juniors KI-generierte Änderungen gemeinsam mit Seniors reviewen, statt nur weitere zu erzeugen. Und messt Verständnis, nicht Codezeilen.


Wo diese These falsch sein könnte

Es lohnt sich, die eigenen Annahmen zu prüfen.

Die Modelle werden schnell besser. Neuere METR-Daten deuten auf echte Beschleunigung hin, und bessere Modelle und KI-Review-Werkzeuge werden immer mehr der hier beschriebenen Probleme erkennen, etwa fehlende Autorisierung oder naive Retries. Das stimmt. Aber es verschiebt das Urteilsvermögen eine Ebene nach oben, statt es zu beseitigen. Was „korrekt“ ist, hängt von geschäftlichem Kontext, Risikobereitschaft und Verantwortung ab, und nichts davon liegt im Repository.

Die Grundlagen waren nie weg. Von ihrer „Rückkehr“ zu sprechen, ist eine Vereinfachung. Geändert hat sich das Preisverhältnis. Gute Systemingenieurinnen und -ingenieure waren immer wertvoll. Neu ist, dass sich der Unterschied zu schnellen Codeproduzenten nicht mehr hinter Tippgeschwindigkeit verstecken lässt.

„Urteilsvermögen“ kann zur Ausrede werden. Wer jeden PR blockiert, weil es sich „falsch anfühlt“, ist kein Qualitätsengpass, sondern einfach ein Engpass. Urteilsvermögen, das sich nicht erklären und in einem Test, einem Constraint, einer Berechtigung oder einer Architekturentscheidung festhalten lässt, skaliert nicht und lässt sich nicht überprüfen.


Verantwortung lässt sich nicht komprimieren

KI komprimiert die Zeit, die nötig ist, um Code zu schreiben. Sie komprimiert nicht die Verantwortung für Entscheidungen.

Wenn um drei Uhr nachts die Produktion steht, fragt niemand, welches Modell den Retry erzeugt hat. Gefragt wird, wer ihn freigegeben hat und warum.

Deshalb werden die besten Teams nicht diejenigen sein, die den meisten Code erzeugen. Sondern diejenigen, die am besten wissen, was nicht ins System gehört, und die dieses Wissen so festhalten, dass es nicht bei jedem PR neu entdeckt werden muss.

Je billiger Code wird, desto teurer wird gutes Urteilsvermögen.

Und jetzt eine Frage an dich: Was war der überzeugendste und zugleich falsche Code, den eine KI für dich erzeugt hat? Und woran war zu erkennen, dass er falsch war? Solche Geschichten lehren mehr als Benchmarks.


Quellen

Die Ökonomie von Code und die Rolle des Menschen

Produktivität und Codequalität

Sicherheit und Zuverlässigkeit

Agenten, Berechtigungen und Harness Engineering

Lernen und Kompetenzaufbau

GoatCMS