1 Punkte von GN⁺ 2 시간 전 | 1 Kommentare | Auf WhatsApp teilen
  • Nachdem eine vom Agenten geschriebene 17.155 Zeilen umfassende Rust-Datenzugriffsschicht schrittweise refaktoriert wurde, sank die Zahl der für dieselbe Funktionsänderung nötigen Eingabe-Token von 159.564 auf 27.360, also um 83 %
  • Die Gesamtmenge des Codes blieb fast unverändert, aber durch das Aufteilen zusammengehöriger Codesegmente in stark kohäsive Dateien konnte der Agent nur noch die für Änderungen minimal erforderliche Dateimenge lesen
  • Die Eingabe-Token gingen erst deutlich zurück, als die größte Datei ausreichend klein geworden war; am Ende wurde die Datenschicht in 19 Rust-Dateien aufgeteilt und die maximale Dateigröße von 17.155 auf 3.695 Zeilen reduziert
  • Ausgabe-Token und Umfang der Funktionsimplementierung blieben nahezu gleich, und auch Claude konnte geeignetes Refactoring weder selbst auswählen noch zuverlässig durchführen, sodass für Planung und Ausführung aktive menschliche Anleitung nötig war
  • Beim Eingabepreis von $3/MTok für Sonnet 5 beträgt die Ersparnis pro Änderung nur etwa $0,397, doch es zeigte sich, dass die Kosten bei künftigen Änderungen an der Datenzugriffsschicht wiederholt sinken könnten

Die 17.155-Zeilen-Datei eines Agenten

  • Die Anwendung zur Arbeitsunterstützung verfügt über eine Web-UI mit dynamischer Aktualisierung und Abfrage, Modals und Autosave, Anbindung externer Systeme, Machine Learning und Textanalyse, Hintergrundjobs sowie eine automatische Deployment-Umgebung
  • Von insgesamt etwa 150.000 Zeilen entfallen rund 120.000 auf Rust, der Rest auf TypeScript und Terraform; der Großteil wurde von Agenten mit Claude Code und teilweise mit Cursor geschrieben
  • Der Entwickler hat den Code kaum gelesen oder geprüft, abgesehen von gelegentlichen Blicken aus Interesse
  • Die Datenzugriffsschicht wuchs auf über 6.000 Zeilen an, weil bei allen Lese- und Schreibabfragen dieselben HTTP-Request-Einstellungen und JSON-Kodierungs-/Dekodierungslogik wiederholt wurden, und schließlich erreichte eine einzelne Rust-Datei 17.155 Zeilen
  • Dieses Modul hatte zwar keine Deduplizierung und keine interne Sprache, nur begrenzte Funktionsextraktion und fast keine Klassenextraktion, eignete sich aber wegen zu bewahrender Schnittstellen und klarer Grenzen gut für ein Refactoring-Experiment

Messmethode mit wiederholter identischer Änderung

  • Ziel war zu prüfen, ob sich durch eine aktuelle Investition in Refactoring der Token-Verbrauch künftiger Funktionsänderungen senken lässt
  • Da der Agent nicht aus früheren Aufgaben lernt, wurde in jeder Phase ein neuer Sub-Agent mit exakt derselben Änderung beauftragt, damit sich kein Lerneffekt einmischt
  • Das Experiment lief in folgender Reihenfolge ab
    • Erstellung eines Gesamtplans nach strengen Refactoring-Prinzipien
    • Definition einer repräsentativen Änderung in einem einzigen Prompt
    • Der Sub-Agent führt die Änderung aus und meldet den Token-Verbrauch, um einen Basiswert zu messen
    • Das Ergebnis der Änderung wird verworfen, danach wird eine Refactoring-Stufe angewendet
    • Dieselbe Änderung wird erneut ausgeführt und das Ergebnis wieder verworfen; dieser Vorgang wird wiederholt
    • Token-Kosten, Laufzeit und Codezeilen pro Stufe werden protokolliert
  • Da Claude keine verlässlichen Echtzeit-Tokenzahlen liefern konnte, wurden stattdessen die Anzahl gesendeter und empfangener Zeichen gemeldet und mit tiktoken durch Division durch 4 in Token angenähert

Messergebnisse pro Stufe

  • Im Ausgangszustand hatten Datenzugriffsschicht und größte Datei jeweils 17.155 Zeilen, der gesamte Rust-Code 50.359 Zeilen, und die repräsentative Änderung benötigte 159.564 Eingabe-Token, 1.705 Ausgabe-Token und 342 Sekunden
  • Nach 15 Stufen umfasste die Datenzugriffsschicht 16.608 Zeilen, die größte Datei 3.695 Zeilen, der gesamte Rust-Code 49.812 Zeilen; benötigt wurden 27.360 Eingabe-Token, 2.113 Ausgabe-Token und 454 Sekunden Laufzeit
  • In den Zwischenstufen sanken die Eingabe-Token mit kleiner werdender größter Datei mit
    • Nach Stufe 7, der Extraktion von queries.rs, war die größte Datei 15.670 Zeilen groß, und die Eingabe sank auf 151.850 Token
    • Nach Stufe 8, der Extraktion von traits.rs, lag sie bei 13.845 Zeilen und 132.558 Token
    • Nach Stufe 12, der Aufteilung in store/, fiel sie auf 9.269 Zeilen und die Eingabe auf 104.080 Token
    • Nach der letzten store/-Aufteilung fiel die größte Datei auf 3.695 Zeilen und die Eingabe stürzte auf 27.360 Token ab
  • Die endgültige Datenzugriffsschicht bestand aus 19 Rust-Dateien, und die größte Datei war nun die Testbibliothek
  • Dasselbe Verfahren kann bei weiterem Refactoring auch auf diese Testdatei angewendet werden

Warum die Eingabe-Token um 83 % sanken

  • Die Eingabe-Token für dieselbe Aufgabe sanken von 159.564 auf 27.360, also eine Ersparnis von 132.204 Token
  • Da die Gesamtmenge des Codes in der Datenzugriffsschicht fast unverändert blieb, lag das nicht daran, dass insgesamt weniger Code zu lesen war
  • Der Agent identifizierte die minimal erforderliche Dateimenge für die Aufgabe und las schrittweise immer kleinere Codebereiche; das war auch in den Denk-Ausgaben und Dateilese-Zusammenfassungen von Claude Code zu sehen
  • Würde man Dateien nur willkürlich kleinteilig aufspalten, müssten für zusammenhängenden Code mehrere Dateien gelesen werden, wodurch sich derselbe Effekt schwer erreichen ließe
  • Der größte Rückgang trat bei der letzten Aufteilung auf, doch sie wurde erst möglich, weil in früheren Stufen Duplikate extrahiert und wiederkehrende Kernstrukturen geschaffen worden waren
  • Diese Reihenfolge wurde nicht im Voraus mit dem Ziel der Kostensenkung entworfen, sondern ergab sich aus einem allgemeinen Refactoring-Prozess, bei dem zuerst lokale Duplikate entfernt, dann gemeinsame Kerne sichtbar gemacht und anschließend in kleinere Dateien zerlegt werden

Ausgabe-Token und finanzieller Effekt

  • Die beim Erstellen der repräsentativen Änderung erzeugten Ausgabe-Token blieben fast unverändert, also konnte das Refactoring die Größe der eigentlichen Änderung nicht verringern
  • Der Preis für Ausgabe-Token war zwar fünfmal so hoch wie für Eingabe-Token, die absolute Menge war jedoch deutlich kleiner
  • Rechnet man mit dem Sonnet-5-Eingabepreis von $3/MTok, ergibt sich eine Ersparnis von etwa 39,7 Cent pro Änderung
  • Ob sich die Einsparungen auch bei Debugging, komplexeren Funktionen oder Refactorings über die gesamte Codebasis hinweg aufsummieren und wie hoch die Kosten des Refactorings selbst sind, wurde nicht geprüft
  • Ebenso bleibt unklar, ob Refactorings möglich sind, die auch Ausgabe-Token reduzieren; bei der einfachen repräsentativen Änderung überdeckte das Rauschen nichtdeterministischer Codegenerierung Unterschiede durch Strukturänderungen

Refactoring mit Claude

  • Claude konnte nach Sichtung des Codes nicht selbst entscheiden, welches Refactoring anzuwenden ist; die tatsächlichen Ergebnisse entsprachen den direkt im Prompt vorgegebenen Aufgaben
  • Obwohl das Entwicklungs-Harness explizite Refactoring-Schritte enthielt, verbesserte Claude die 17.155-Zeilen-Datei dadurch nicht
  • Bei der Planung identifizierte Claude Code die Funktionsextraktion als ersten Schritt, während Claude.ai sogar die Extraktion der gesamten Client-Klasse erkannte
  • Für mechanische Änderungen wurden Python-Skripte mit grep und sed verwendet, die jedoch wegen der Einrückung häufig durcheinanderkamen
  • Die wertvollste Aufteilung der Store-Dateien fehlte im ersten Versuch und wurde später nachgeholt; deshalb stimmen die Zahl der Messstufen und die Planstufen im Anhang nicht überein
  • Das gesamte Experiment dauerte etwa 8 Stunden und lief größtenteils unbeaufsichtigt
    • Nach 6 Stunden und 40 Minuten wurde eine ausgelassene Stufe entdeckt, was einen einmaligen Eingriff erforderte
    • Nicht langsames Hotel-WLAN, sondern ein übermäßig angewachsener temporärer Cargo-Build-Cache war die Hauptursache für die stark verzögerte Testausführung

Prompt für die repräsentative Änderung

  • Jeder Sub-Agent erhielt nur die Codebasis und Architekturdokumentation und implementierte dasselbe asynchrone öffentliche Trait ItemWatchStore
  • Das Trait enthält die folgenden drei Methoden
    • watch_item(&self, item_id: &str, user_id: &str) -> Result<()>
    • unwatch_item(&self, item_id: &str, user_id: &str) -> Result<()>
    • watched_items_for_user(&self, user_id: &str) -> Result<Vec<String>>
  • Watch-Informationen werden in der Firestore-Collection item_watches mit den Feldern itemId, userId, createdAt gespeichert
  • Ohne separate Rust-Record-Struktur wird ein Vec<String> der Item-IDs zurückgegeben
  • Zu FakeStore wird ein In-Memory-Feld Vec<(String, String)> hinzugefügt, und FirestoreStore wird unter Beibehaltung des bestehenden HTTP-Musters implementiert
  • Am Ende der Antwort sollte als JSON ausgegeben werden, welche Dateien gelesen wurden, wie viele Zeichen sie umfassten und wie viele Zeichen die Antwort hatte; außerdem wurde angewiesen, den Code nicht zu committen

Angewendeter Refactoring-Plan

  • Stufe 1 — Extraktion der Klasse FirestoreClient

    • Trennt die Verantwortung für Domänenabfragen von der Firestore-HTTP-Übertragung
    • Verschiebt reqwest::Client, project_id, MetadataAuth sowie URL- und Auth-Header-Behandlung in eine neue Struktur
    • Laut Plan werden in der Implementierung von FirestoreStore rund 1.200 Zeilen entfernt und dem Client etwa 120 Zeilen hinzugefügt
  • Stufe 2 — Extraktion der Funktionen extract_doc_id und new_link

    • Vereinheitlicht die ID-Extraktion in 20 Dokumentparsern und die 62-mal wiederholte Erzeugung von Link
    • Erwartete Einsparung: rund 500 Zeilen
  • Stufe 3 — Extraktion von Funktionen für die Link-Query-Pipeline

    • Vereinheitlicht das Sammeln von Query-Ergebnissen an etwa 15 Stellen und das Abrufen einzelner Ziel-IDs an etwa 8 Stellen
    • Erwartete Einsparung: rund 200 Zeilen
  • Stufe 4 — Extraktion von Link-Bedingungsfunktionen in FakeStoreInner

    • Trennt in etwa 15 Methoden die wiederholten Varianten von inner.links.iter() in zwei Methoden aus
    • Erwartete Einsparung: rund 120 Zeilen
  • Stufe 5 — Einführung von Funktionen zur Erzeugung von Firestore-Werten

    • Ersetzt mehr als 128 wiederholte json!-Ausdrücke für Strings, Timestamps usw. durch vier Funktionsaufrufe
    • Wandelt mehrzeilige Makros in einzeilige Aufrufe um und spart so voraussichtlich etwa 80 Zeilen
  • Stufe 6 — Extraktion von FieldsBuilder

    • Fasst das Muster zur Erzeugung von Feld-Mappings in rund 20 Encodern in einem Builder zusammen
    • Reduziert etwa 40 Zeilen lange Encoder auf rund 12 Zeilen und spart insgesamt voraussichtlich 500 bis 600 Zeilen
  • Stufe 7 — Auslagerung von queries.rs

    • Verschiebt 32 Konstanten des Typs LinkQuery und zugehörige Typen in ein separates Modul
    • Verringert mod.rs um rund 800 Zeilen, ohne bestehende Aufrufstellen zu ändern
  • Stufe 8 — Auslagerung von traits.rs

    • Verschiebt 17 öffentliche Traits und zugehörige Fehlertypen und exportiert sie erneut
    • Verringert mod.rs um rund 1.900 Zeilen, aber die neue Datei wird ebenfalls etwa 1.900 Zeilen groß
  • Stufe 9 — Domänenspezifische Aufteilung von traits/

    • Teilt die Traits in planning.rs, content.rs, people.rs und system.rs
    • Lässt Definitionen und Aufrufstellen unverändert und begrenzt die Dateigröße auf etwa 300 bis 650 Zeilen
  • Stufe 10 — Auslagerung von codec.rs

    • Verschiebt Dokument-Encoder/-Decoder, Parser, FieldsBuilder und Funktionen zur Werterzeugung
    • Wird nach Stufe 6 zu einem Modul von etwa 400 bis 500 Zeilen und reduziert mod.rs um etwa 500 Zeilen
  • Stufe 11 — Auslagerung von fake_store.rs

    • Verschiebt FakeStore, FakeStoreInner und 18 Trait-Implementierungen
    • Verringert mod.rs um rund 4.700 Zeilen
  • Stufe 12 — Aufteilung der Implementierung von FirestoreStore

    • In store/mod.rs bleiben Struktur, Konstruktor, FirestoreClient und MetadataAuth, während die Trait-Implementierungen in domänenspezifische Dateien aufgeteilt werden
    • Ersetzt eine Datei von rund 10.000 Zeilen durch 10 Dateien mit jeweils 120 bis 650 Zeilen und macht mod.rs zu einer etwa 100 Zeilen langen Re-Export-Datei
  • Stufe 13 — Platzierung der Tests bei den Zielmodulen

    • Verschiebt den Testcode unter die jeweiligen Implementierungsdateien, ohne die Tests selbst zu ändern
    • Reduziert mod.rs um rund 2.000 Zeilen; in den einzelnen Dateien kommen dafür je 200 bis 700 Zeilen relevanter Tests hinzu

Grenzen und Folgeexperimente

  • Die für Planung und Ausführung des Refactorings aufgewendeten Token wurden nicht separat gezählt, daher lassen sich die Investitionskosten des Refactorings nicht exakt berechnen
  • Eine Obergrenze auf Basis der Gesamtnutzung in diesem Zeitraum liegt bei 5 Millionen Token, darin sind jedoch auch das zweimalige Erstellen des Plans, Experimente und das Design der repräsentativen Änderung sowie weitere Arbeiten enthalten
  • Das Untersuchungsobjekt befand sich noch in der Greenfield-Phase und war eine einzelne große Anwendung, die von einem Entwickler aufgebaut und betrieben wird; die Ergebnisse lassen sich daher nicht verallgemeinern
  • Für Folgearbeiten sind eine präzise Messung der Refactoring-Token, komplexere Änderungen, Refactorings mit größerer Reichweite, kontinuierliches Refactoring und ein Vergleich des relativen Werts verschiedener Ansätze nötig
  • Dieses Experiment ist ein Ausgangspunkt, um sowohl den zeitlichen und finanziellen Wert von Refactoring als auch dessen eigene Kosten gemeinsam zu messen

1 Kommentare

 
GN⁺ 2 시간 전
Hacker-News-Kommentare
  • Es ist interessant zu sehen, wie Best Practices für Entwickler, die die meisten IT-Unternehmen ignoriert haben, als Best Practices für KI neu erfunden werden.
    Früher fand man es langweilig, wenn jemand sagte, man solle Dokumentation im Code unterbringen, nicht einfach nur Jira-Tickets zuwerfen, sondern den gesamten Projektkontext vermitteln, und im Interesse langfristiger Produktivität refaktorisieren.
    Heute wird dieselbe Botschaft mit Interesse aufgenommen: KI-Dokumentation gehört in den Code und in CLAUDE.md, man soll nicht alles per Prompt bis ins Detail kontrollieren, und wir sollten für KI-Produktivität refaktorisieren.

    • Es ist viel einfacher, einen KI-Agenten dazu zu bringen, dieselbe Arbeit konsistent auszuführen, als einen menschlichen Kollegen.
      Menschen kennen vielleicht den richtigen Weg, sind aber beschäftigt oder verlieren die Konzentration; Agenten dagegen werden bei langweiligen Aufgaben nicht müde. Dadurch werden Verfahren realistisch möglich, die sich bei Menschen als wirksam erwiesen haben, aber schwer konsequent anzuwenden waren.
      Auf Basis einer gemeinsamen Spezifikation ließ man Implementierung und Tests von getrennten Agenten schreiben und von einem Audit-Agenten prüfen, damit ihre Ergebnisse einander nicht kontaminieren. Das ist im Grunde Cleanroom Engineering, das IBM in den 1980er-Jahren für Menschen entwickelt hat, nun breit und konsistent mit KI angewandt.
    • Die Person, die mit diesem Beitrag zusammenhängt, ist Martin Fowler, der vor über 20 Jahren das Buch 《Refactoring》 schrieb und den Begriff popularisierte.
      Es geht hier nicht darum, alte Praktiken im KI-Hype als etwas Neues zu verpacken, sondern mit Belegen zu zeigen, dass über 20 Jahre alte Best Practices weiterhin gültig sind.
    • Der große Unterschied zwischen vor und nach KI ist, dass Menschen über eine ziemlich gute Fähigkeit zum Management langfristigen Kontexts verfügen.
      Agenten müssen sich den Kontext in jeder Session neu aneignen, weshalb der Wert von Best Practices viel größer wird und ihre Wirkung sofort sichtbar ist.
    • Dank des KI-Booms bekommt man nun Budget für die gewünschten Verbesserungen der Developer Experience, auch wenn es bitter ist, dass der Grund dafür falsch ist.
      Trotzdem ist es schön, eine CLI in einer Stunde 100-mal ausführen zu lassen, um die Usability eines neuen Flags zu testen.
    • Menschen schaffen trotz veralteter SharePoint-Dokumentation, nebenbei in Meetings aufgeschnapptem Gesamtkontext und niedriger Refactoring-Priorität irgendwie Ergebnisse, auch wenn Qualität und Termine leiden.
      KI dagegen arbeitet ohne diese Grundlagen sehr schlecht oder funktioniert gar nicht; dadurch werden gesunde Engineering-Praktiken nicht zu einer langfristigen Verbesserungsmaßnahme, sondern zu einer notwendigen Voraussetzung.
      Selbst wenn es netto gar keinen Effekt hätte, ist es nützlich, KI in den Workflow aufzunehmen, weil man dadurch einen Vorwand bekommt, saubere Entwicklungspraktiken einzuführen.
  • Mir gefällt, dass dieser Beitrag KI-Tools auf Basis ihrer tatsächlichen Nutzung konkret und quantitativ kritisiert.
    Ein Text, der mit Messwerten zeigt, was KI nicht kann, ist viel hilfreicher als einer, der ohne reale Anwendungsfälle vage über gesellschaftliche Risiken spricht.
    Aus demselben Grund fand ich auch den Bericht beeindruckend, der durch Interviews mit Mitgliedern von Boko Haram untersucht, wie KI für Terrorismus genutzt wurde.

  • Ich mag Refactoring von Hand, ganz ohne KI, wirklich sehr.
    Es gibt zwar keine sichtbare Veränderung, aber es ist befriedigend, eine Website, deren Nutzen nicht sofort sichtbar wird, in Zukunft sehr viel leichter handhabbar zu machen.
    Es macht wie ein Puzzle Spaß, Stellen zu finden, an denen bizarre alte Workarounds erneut Probleme lösen, für die es längst etablierte Patterns gibt, und sie in Richtung Best Practices zu verschieben, ohne neue technische Schulden zu erzeugen.
    Ich habe alles bis hin zur Authentifizierung schlampig selbst implementiert und dadurch auf die harte Tour die inneren Funktionsweisen gelernt; als Ergebnis habe ich nun auch Refactoring-Stoff, an dem ich die nächsten zehn Jahre Freude haben kann.

    • Nach der Lektüre von Fowlers 《Refactoring》 bezweifelte ich, ob es auch bei Code für Wissenschaft und Forschung wirksam wäre. Nachdem ich es experimentell auf eine unbefriedigende Codestruktur angewandt hatte, änderte sich meine Sicht jedoch völlig.
      Ich verstand konkret, was es heißt, dass eine Codebasis ein System ist, und begann, Code auf höherer Ebene wie ein zusammenhängendes Gewebe oder Netz zu sehen, an dem man ziehen und drücken kann.
      Dass KI diesen Lernprozess eliminieren kann, macht das Problem mit Junior-Entwicklern deutlich. Intuition bekommt man nur, indem man selbst tief eintaucht; auch wenn Naur schon vor 40 Jahren davor gewarnt hat, wird diese Lektion immer wieder vergessen.
    • Vielleicht liegt es auch daran, dass man eine Dopamin-Belohnung bekommt, ähnlich wie beim Zuschauen des Defragmentierungsbildschirms von Windows 98.
    • Dieses Gefühl ist Stolz als Handwerker. Wer es versteht, braucht keine Erklärung; wer es nicht versteht, dem hilft keine Erklärung.
    • Mich würde interessieren, in welchem Umfang eine Testsuite als Sicherheitsnetz aufgebaut wurde, um Regressionen während des Refactorings zu verhindern.
    • Es macht Spaß, verschiedene Refactoring-Patterns und reale Anwendungsfälle zu studieren.
  • Wenn Agenten refaktorisieren, halte ich menschliche Beteiligung für unverzichtbar
    Ein generatives Modell konzentriert sich auf die erste Arbeit, und ein Review-Modell kann zwar übersehene Stellen finden; fraglich ist aber, ob es den Zweck des gesamten Projekts und die Art, wie der Code zusammenspielt, wirklich versteht und so Duplikate oder elegantere Strukturen erkennen kann
    Einem Coding-Agenten Refactoring zu überlassen, ist ähnlich, wie einen Unfallchirurgen zu bitten, die sportliche Leistungsfähigkeit zu steigern; um es richtig zu machen, braucht es eine ganzheitliche Perspektive
    Eine große Datei einfach in mehrere Dateien aufzuteilen, bleibt oberflächliches Refactoring. Ohne eine Theorie dazu, welcher Code zusammengehört und was in Utility-Funktionen extrahiert werden sollte, ist das eher so, als würde man eine große Zahl in kleinere Zahlen zerlegen und sie anschließend wieder addieren, nicht wie Faktorisierung
    Agenten bauen mitunter Systeme, die Werte erneut speichern und berechnen, die bereits aus einer API kommen; ein Mensch kann dagegen mit Blick auf das gesamte Projekt präzise erkennen, dass die benötigten Daten bereits in einem bestimmten JSON-Key vorhanden sind

    • Auch heutige LLMs machen das gut genug, wenn man ihnen für einen bestimmten Codeabschnitt ein konkretes Refactoring vorgibt. Sie können zum Beispiel auch eine komplexe Anforderung umsetzen, das Command Pattern statt mit Datenklassen mit functools.partial zu implementieren
      Auch die Idee, dass Dateigrenzen die Grenzen logischer Subsysteme markieren und damit das Reasoning erleichtern und dass Inhalte anderer Dateien grundsätzlich als opak behandelt werden, ist in den Trainingsdaten reichlich vorhanden
      Ich denke, der Vorteil dieser Struktur hat nicht nur mit zufälligen Eigenschaften menschlicher Kognition zu tun, sondern besitzt auch objektive Aspekte
    • Mit einem Menschen daneben, der die Richtung erklärt, wurde ein Refactoring, das Monate gedauert hätte, größtenteils in etwa einer Woche erledigt
      Geholfen haben Refactoring-Erfahrung, die Art, mit fremden Codebasen umzugehen, und der Umstand, als ursprünglicher Designer frühere und aktuelle Absichten erklären zu können
      Es war eine Nischensprache mit wenigen Abhängigkeitsproblemen und für LLMs gut handhabbar; nachdem der Bias in Richtung JavaScript und Python entfernt war, nahm die Arbeitsgeschwindigkeit deutlich zu
      Es war ein JSR-223-Projekt, bei dem Skripte in mehreren populären Sprachen geschrieben wurden, je nach Umgebungsanforderung aber alle auf der JVM liefen: https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform
    • Die Einschätzung, Agenten könnten nicht refaktorisieren, ist veraltet; inzwischen sind sie sehr gut darin
      Auf diesem Arbeitsmarkt muss man aktuelle Coding-Agenten auf Basis von Frontier-Modellen einsetzen und ihre Fähigkeiten und Grenzen genau kennen; eine gegenteilige Bewertung im Vorstellungsgespräch kann ein Ausschlussgrund sein
  • Kompakter Kontext senkt nicht nur den Token-Verbrauch, sondern verbessert auch das Reasoning und ermöglicht es, mehr Ebenen in einem Kontext intelligent zu handhaben
    Refactoring in Richtung guter Abstraktionen erzeugt Software, die besser generalisiert und mit höherer Wahrscheinlichkeit nicht nur für getestete Fälle, sondern auch für interpolierte und extrapolierte Fälle korrekt ist
    Dafür gibt es stützende Informationstheorie und bayessche Mathematik; dass wirtschaftlich und energieeffizientere Software auch korrekter wird, wirkt wie ein eleganter Zufall
    Der Kern ist, die Entropie des Codes zu reduzieren

    • Überall auf der Welt und im Universum kann Entropiereduktion als eine Form des Aufbauens verstanden werden
    • Wenn man menschliche Lesbarkeit als Ziel aufgibt und nur die Reduzierung des Token-Verbrauchs als Zielfunktion nimmt, ist schwer abzusehen, wo man landet
      LLMs erschließen Bedeutung schon heute auch mit wenig Kontext recht gut
  • Interessant ist, dass Daten vorgelegt werden; das deckt sich mit meinem Eindruck, dass LLMs von gut getrenntem Code stark profitieren, aber selbst nicht besonders gut darin sind, solchen Code zu erzeugen
    Die meisten menschlichen Entwickler dürften ähnlich sein

    • Ich plane separat Zeit für das Entfernen schlampigen Codes ein und mache genau das gerade im Fenster daneben
      Insgesamt ist der Nutzen von AI groß, aber Aufräumzeit ist ebenfalls nötig, und ich denke weiterhin, dass man jede Zeile lesen muss
      Um den Fortschritt anderer Teams nicht zu blockieren, habe ich manche Reviews verschoben und zahle später höhere technische Schulden als üblich zurück; zuerst den Engpass zu lösen, war dennoch wertvoll
      AI hat es in jeder Hinsicht leichter gemacht, technische Schulden aufzunehmen, und sie kann auch beim Abbau ziemlich gut helfen, wenn man sie richtig anleitet. Die Ergebnisse unterscheiden sich allerdings je nach Person: https://news.ycombinator.com/item?id=49035455
    • Im Grundzustand habe ich dasselbe Ergebnis gesehen, aber wenn man die Refactoring-Richtung konkret vorgibt, konnte sie besser getrennten Code erzeugen
      Beispiele für gut strukturierten Code oder Open-Source-Repositories zu zeigen, um deutlich zu machen, was zu tun und was zu vermeiden ist, hilft enorm
  • Der Großteil des wirtschaftlichen Nutzens von Refactoring entsteht eher durch besseres menschliches Verständnis als durch Token-Einsparungen
    Man löst Störungsalarme um 3 Uhr morgens schneller, reduziert Bugs in der Produktionsumgebung und kann schneller als die Konkurrenz ausliefern
    Vor allem: Wenn man ein System versteht, übernimmt man eher Verantwortung und Ownership, behebt Probleme schneller und bringt sich aktiver bei Verbesserungen ein

  • Der Punkt ist, dass Refactoring den Token-Verbrauch senkt, und es ist gut, dass der Effekt quantifiziert statt abstrakt diskutiert wird
    Fowler schrieb in Refactoring jedoch, dass robuste Tests eine zwingende Voraussetzung für Refactoring sind, und unabhängig von AI liegt aus meiner Sicht hier der eigentliche Vorteil
    Gute Tests verhindern Regressionen, egal ob sie von Menschen oder Robotern verursacht werden, und hinterlassen eine für beide Seiten lesbare Spezifikation im Code: https://www.oreilly.com/library/view/refactoring-improving-the/9780134757681/

    • Der Artikel erschien auf martinfowler.com, wurde aber nicht von Martin geschrieben; als Autor ist Giles Edwards-Alexander, CTO von Thoughtworks, angegeben
    • Der eigentliche Kern ist, dass die Ersparnis nur bei einigen Dutzend Cent liegt
      Rechnet man den Preis von Sonnet 5 mit 3 Dollar pro MTok, beträgt die Ersparnis bei einer künftigen Änderung an der Datenzugriffsschicht 39,7 Cent
      Angesichts von OpenAIs Preissenkungen, offenen Modellen und langfristig fallenden Token-Preisen passt das möglicherweise nicht zu den Kosten eines Senior Developers für etwa 100 Dollar pro Stunde, der das Refactoring anleitet
  • Der von Agents erzeugte Code ist zu einem riesigen Klumpen geworden, den nur noch Agents lesen und verstehen können; wichtiger als die Frage, ob das Feature, Bug oder emergente Eigenschaft ist, ist dabei die Realität selbst
    Um mit Code umzugehen, der mit AI-Tools erzeugt wurde, werden wir wieder von AI-Tools abhängig
    Allerdings haben auch Menschen längst furchtbar große Dateien und Monorepos geschaffen, und dank LLMs wird es überhaupt erst handhabbar, sie zu bearbeiten und zu refaktorisieren
    In einer Situation, in der Codebases zu groß und chaotisch geworden sind, um von Menschen verstanden zu werden, könnten LLMs uns retten; persönlich verabscheue ich riesige Dateien, aber es ist bitter, dass Fowlers Aufräumprinzipien vielleicht nicht mehr wichtig sind

    • Die Aussage, dass Agent-Code nur von Agents verstanden werden könne, ist grundsätzlich nicht wahr; wenn es sich so anfühlt, liegt es an einer falschen Nutzung von LLMs
    • Schlechter Code gab es schon immer, aber AI ist ein neues Problem, weil sie den Schadensradius schlechter Einstellungen um das 1.000-Fache vergrößert
      Selbst durchschnittliche oder gelegentlich gute Mitarbeitende können dadurch Dinge blitzschnell ausführen, die sie früher wegen Unternehmensprozessen nicht hätten tun können, und so eher zu schlechten Mitarbeitenden werden
    • Auch bei einer zu 100 % von einem LLM geschriebenen Codebase gab es keine Probleme, sie zu lesen oder die gewünschte Stelle zu finden, und es war nicht schwieriger als bei selbst geschriebenem Code
    • Ich habe noch nie gesehen, dass von Agents erzeugter Code schlechter war als der schlimmste von Menschen geschriebene Code
      Wenn ein Agent riesige Dateien oder Funktionen erzeugt, reicht es, ihn anzuweisen, das nicht zu tun, und er hält sich daran
  • Refactoring ist eines der besten Anzeichen für ein gesundes Entwicklungsteam, denke ich
    Refactoring hat zwar an sich Vorteile, aber für Product Owner oder in Feature-Task-Listen ist sein Wert kaum sichtbar
    Wenn ein Team zugunsten der Gesundheit der gesamten Software refaktorisiert, bedeutet das, dass Entwickler Vorschläge für gute Software ohne Hemmungen einbringen können und diese Vorschläge ernst genommen werden
    Software-Verfall ist am schlimmsten, wenn ein Team weder Motivation noch Befugnis hat, eine Vision hochwertiger Software umzusetzen; wenn ein Team seinem Urteil über Exzellenz folgen kann, ist das im Allgemeinen ein gutes Zeichen
    Natürlich gibt es auch Übertreibungen, etwa komplette Neuschreibungen von Ruby über Node und Rust bis hin zu wieder agentenfreundlichen Technologien, aber in Unternehmensumgebungen sind Teams, die das Gefühl haben, keine Erlaubnis für Verbesserungen zu haben, sehr viel häufiger