Startseite / Artikel

Lektionen aus Bun’s von KI gestützter Umstellung von Zig zu Rust: Die Verifizierung ist die eigentliche Arbeit

Was Buns von seinem Agenten unterstützte Wechsel von Zig zu Rust über Test-Suiten als Verträge, Portierungsleitfäden, unsicheren Code und warum die Verifizierung heute das KI-Programmieren einschränkt, lehrt.

Verlag: REACTAPP.TOP12 Min. Lesezeit2857 Wörter

Quellen: Bun Rewrote Its Runtime in Rust With AI. The Real Story Is Bigger Than the Code

Die meisten Ingenieurteams betrachten eine Neuimplementierung einer Sprache in einem großen Produktionsystem als etwas, das so lange wie möglich vermieden werden sollte. Bun, die Laufzeitumgebung und Werkzeugkiste für JavaScript und TypeScript, hat Berichten zufolge seine Implementierung von Zig auf Rust verlegt, wobei künstliche Intelligenz-basierte Codieragenten den größten Teil der Umwandlung übernahmen – und die Zahlen sind beeindruckend. Die wichtigere Erkenntnis ist jedoch nicht, wie viel Code die Agenten erzeugten, sondern wie der zugrundeliegende Prozess entschied, welcher Teil dieses Codes vertrauenswürdig sein kann. Dieser Artikel erklärt diesen Prozess im Detail und zeigt Praktiken auf, die Sie bei Ihren eigenen mit KI unterstützten Refaktorierungen und Migrationen anwenden können.

Warum Neuimplementierungen normalerweise vermieden werden

Eine Sprachumstellung birgt eine bekannte Reihe von Risiken. Sie kann subtile Rückschritte verursachen, die monatelang niemand bemerkt, die Leistung in unerwartete Richtungen verschieben, eine Plattform lahmlegen, die nur von einer Handvoll Nutzern genutzt wird, und einen großen Teil der Kapazitäten eines Teams in Anspruch nehmen. Im schlimmsten Fall muss das Team sowohl die alte als auch die neue Implementierung nebeneinander warten und zweimal für jeden Fehlerbehebungsversuch bezahlen.

Deshalb zieht die Migration zu Bun Aufmerksamkeit auf sich. Zum Zeitpunkt der Erstellung beschreibt das Projekt-Repository Bun als einen auf JavaScriptCore basierenden JavaScript-Runtime in Rust, und Anthropic kündigte an, Bun im Dezember 2025 übernehmen zu wollen. Offizielle Berichte geben an, dass die Portierung etwa 535.000 Zeilen in Zig innerhalb von rund 11 Tagen umgesetzt wurden, wobei Agenten den größten Teil der Implementierungsarbeit innerhalb eines streng definierten Prozesses übernahmen.

Es ist verlockend, dies als einen weiteren Schlagzeilenartikel vom Typ „KI hat eine Menge Code geschrieben“ zu betrachten. Die bessere Frage lautet etwas anderes: Kann ein KI-System große Veränderungen durchführen, wenn Menschen einen zuverlässigen Mechanismus entwickeln, um zu überprüfen, ob das Ergebnis korrekt ist? Diese Frage ist weitaus wichtiger für die Art und Weise, wie in den nächsten Jahren Software entwickelt werden wird.

Eine Anpassung, keine Neugestaltung

Bun wurde ursprünglich größtenteils in Zig geschrieben, einer Systemsprache, die für ihre niedrige Ebene der Steuerung und vorhersagbare Leistung geschätzt wird. Die Migration wurde nicht als Neuanfang konzipiert. Ihr Ziel war bewusst eng gefasst: Die bestehende Architektur sowie das beobachtbare Verhalten beizubehalten und nur die Sprache zu ändern, in der die Implementierung geschrieben ist.

Diese Gestaltung ist die entscheidende Designentscheidung. Eine herkömmliche Überarbeitung ermutigt Ingenieure dazu, im Laufe des Prozesses neu zu gestalten – indem sie Datenstrukturen austauschen, Module umordnen, Abstraktionen hinzufügen und APIs anpassen. Jede dieser Entscheidungen stellt eine neue Quelle des Risikos sowie etwas dar, das überprüft werden muss. Indem das Bun-Team die meisten dieser Optionen ausschloss, verwandelte es eine offene kreative Aufgabe in eine mechanische mit einem eindeutigen Referenzpunkt: der aktuellen Implementierung sowie den Tests, die sie beschreiben.

Die Anzahl der Zeilen klingt nach dem schwierigen Teil, ist es aber nicht. Die Erstellung syntaktisch korrekten Rust-Code ist im Vergleich dazu einfach. Die eigentliche Herausforderung liegt darin, sicherzustellen, dass der Rust-Code genauso funktioniert wie das Zig, das er ersetzt.

Der Testumfang als verhaltensbasiertes Vertragswerk

Stellen Sie sich einen Agenten vor, der lediglich den Befehl „Überschreiben Sie diese Codebasis in Rust.“ erhält. Diese Anweisung lässt alle wichtigen Entscheidungen offen: Welche Teile dürfen geändert werden und welche müssen unverändert bleiben? Welche Abkürzungen sind zulässig? Welches Speicherverhalten ist entscheidend? Und vor allem: Wie kann jemand wissen, dass das Ergebnis richtig ist?

Bun hatte bereits die Antwort auf die letzte Frage: ein umfangreiches, ausgereiftes Testframework. Sobald die Tests als Vertrag betrachtet werden, entwickelt der Agent keine Implementierung mehr selbst. Er reproduziert vielmehr ein bereits in ausführbarer Form festgelegtes Verhalten – jede von ihm erstellte Datei erfüllt entweder diesen Vertrag oder nicht.

Was Tests versprechen können und was nicht

Eine Testsuite ist kein Beweis für Korrektheit. Sie überprüft lediglich das Verhalten, das jemand in den Code einbauen wollte, und eine übersetzte Datei kann alle Tests bestehen, obwohl sie in einem noch nicht getesteten Pfad abweicht. Was die Tests jedoch bieten, ist ein Rückkopplungsschleifenmechanismus, der weitaus effektiver ist als das Verlangen an ein Modell, sein eigenes Ausgabeergebnis zu bewerten. Ohne sie kann eine generierte Überarbeitung völlig plausibel erscheinen, während gleichzeitig die Semantik heimlich verändert wird. Mit ihnen muss jede generierte Änderung sich ihren Platz verdienen.

Der beschriebene Bun-Arbeitsablauf setzte mehrere Kontrollschritte übereinander: Kompilierung, Testsuite, Überprüfungen auf unterstützten Plattformen, Code-Review sowie weitere Validierung. Das Modell erzeugte Kandidaten; der ingenieurwissenschaftliche Prozess entschied, welche davon überleben. Diese Arbeitsteilung ist die zentrale Idee, die man sich aneignen sollte.

Warum der Portierungsleitfaden genauso wichtig war wie das Modell

Bevor die Agenten Tausende von Dateien bearbeiteten, erstellte das Projekt angeblich eine detaillierte Portierungsanleitung, in der beschrieben wurde, wie Zig-Strukturen in Rust ausgedrückt werden sollten. Sie umfasste Typabbildungen, Namenskonventionen, wiederkehrende Übersetzungsmuster, wie Abhängigkeiten gehandhabt werden sollten sowie explizite Beschränkungen dafür, was den Agenten erlaubt war.

Dadurch wird eine vage Anfrage (“Schreibe diese Datei in Rust”) durch eine eingeschränkte ersetzt: Die Datei soll unter Verwendung der vereinbarten Abbildungen konvertiert werden, ihr beobachtbares Verhalten muss unverändert bleiben und die Architektur darf nicht verändert werden. In einer solchen Umgebung leisten die Agenten deutlich bessere Arbeit, da der Bereich der zulässigen Antworten klein und klar definiert ist.

Eine Anleitung macht außerdem die Überprüfung übersichtlicher. Anstelle der vagen Frage “Sieht das gut aus?” kann ein Prüfer zwei konkrete Fragen stellen:

  1. Verhält sich dieser Rust-Code genauso wie der Zig, den er ersetzt?
  2. Hat das Tool die Übersetzungsvorschriften befolgt, auf die sich das Projekt geeinigt hat?

Zu beiden Fragen gibt es überprüfbare Antworten, genau das ist bei einer enormen Anzahl an Änderungen in einem Überprüfungsprozess erforderlich.

Was eine nützliche Portierungsanleitung enthält

Falls Sie eine ähnliche Migration planen, auch in viel geringerem Umfang, legt eine solche Anleitung in der Regel dar:

  • wie jede Quelltyp, Container-Struktur und Fehlerbehandlungsmethode in die Zielsprache übertragen wird
  • Namensregeln, damit der generierte Code in allen Dateien und Tools konsistent ist
  • welche Abhängigkeiten eingeführt werden dürfen und welche verboten sind
  • Muster, die das Tool auf keinen Fall verwenden darf, selbst wenn sie dazu führen würden, dass eine Datei kompiliert
  • was als „abgeschlossen“ für eine einzelne Datei oder ein Modul gilt

Die allgemeingültige Lehre gilt weit über Bun hinaus: Das Anweisungssystem um einen Agenten kann die Qualität des Ergebnisses fast genauso stark beeinflussen wie die Wahl des Modells. Teams, die bereits Anweisungsdateien für Agenten pflegen, werden dieses Muster erkennen; unser Leitfaden zur Erstellung einer effektiven CLAUDE.md-Datei behandelt denselben Grundsatz für die alltägliche Arbeit.

Echter Rust ist nicht immer idiomatischer Rust

Jeder, der erwartet, dass der portierte Code wie eine von Grund auf entwickelte Rust-Lösung aussieht, wird enttäuscht sein – und das ist beabsichtigt. Eine echte Portierung sollte genauso aussehen wie das Original, von dem sie übertragen wurde.

Dies führt zu einem sichtbaren Kompromiss. Zig kann bestimmte niedrigschwellige Operationen prägnant ausdrücken, während Rust in der Regel explizit mit Typen, Lebenszeiten, Eigentumsverhältnissen sowie den Grenzen unsicheren Codes umgeht. Eine kompakte Zig-Funktion kann daher zu einer deutlich längeren Rust-Version werden. Die zusätzliche Länge ist eine Folge der Optimierung für verhaltensbezogene Äquivalenz statt für Eleganz und kein Beweis dafür, dass das Ergebnis fehlerhaft ist.

Es hilft, zwei Aussagen voneinander zu trennen:

  • "Das ist nicht der Rust, den ich von Grund auf geschrieben hätte."
  • "Dieser Rust ist fehlerhaft."

Die erste ist ein Stilurteil; die zweite ist ein Defekt. Sie als dasselbe zu betrachten führt zu fehlplatzierten Kritiken an mechanischen Portierungen.

Zuerst den Port erstellen, danach aufräumen

Der beschriebene Ansatz betrachtete die mechanische Übersetzung sowie die anschließende Verbesserung als getrennte Phasen. Zuerst soll Rust sich wie Bun verhalten, danach wird Rust weiter verbessert. Dadurch, dass die Arbeit auf diese Weise aufgeteilt wird, muss das Team nicht gleichzeitig mit zwei großen, miteinander verbundenen Änderungen umgehen. Falls während der Aufräumarbeiten eine Regression auftritt, kann diese dem Aufräumen zugeschrieben werden, da die Ausgangsversion bereits anhand derselben Tests überprüft wurde.

Richtige Interpretation der unsafe-Blöcke

Besucher, die den Port durchsahen, bemerkten eine große Anzahl an unsafe-Blöcken und betrachteten dies als Zeichen für von schlechter Qualität geprägten Rust. Diese Reaktion ist verständlich, ignoriert jedoch, wie der Code in diesen Zustand gelangt ist.

Rust erfordert, dass potenziell gefährliche Operationen wie das Aufrufen von Rohzeigern oder das Aufrufen fremder Funktionen explizit mit unsafe markiert werden. Zig verfügt über kein äquivalentes Markierungsmerkmal. Bun’s ursprünglicher Code ist voller niedrigschwelliger Speichermanipulationen, Zeigeroperationen sowie Aufrufe in C- und C++-Komponenten, wodurch eine getreue Übersetzung naturgemäß einen Großteil davon als unsafe in Rust darstellt. Darüber hinaus embeddet Bun JavaScriptCore und kommuniziert mit anderen nativen Bibliotheken, wodurch die Grenze zwischen Rust- und C- oder C++-Code per Definition unsichere Operationen erfordert.

Anders ausgedrückt: Die Portierung hat keine neuen Gefahren hinzugefügt; sie hat bereits vorhandene Gefahren sichtbar gemacht. Eine reine Anzahl der unsafe-Blöcke sagt wenig über die Qualität aus. Aussagekräftigere Fragen lauten:

  • Warum muss diese spezielle Operation unsicher sein?
  • Ist das unsichere Gebiet klein genug, um es bewerten zu können?
  • Verhindert der sichere Code drumherum, dass Aufrufer ihn missbrauchen?
  • Ist sein Verhalten durch Tests abgedeckt?
  • Kann es in einem späteren Schritt eingeschränkt oder entfernt werden?
  • Diese Fragen liefern auch einen natürlichen Fahrplan für die Aufräumphase: Unsichere Bereiche verkleinern, sie in sichere Abstraktionen einpacken und die Invarianten dokumentieren, auf denen jede davon beruht.

    Wenn die Übersetzung Verbesserungen aufzeigt

    Auch eine wörtliche Übertragung kann noch Chancen aufzeigen, die durch das ursprüngliche Design verdeckt wurden. Ein berichtetes Beispiel betraf einen Codepfad, bei dem die Zig-Implementierung in C++ wechselte, um Informationen abzurufen. In Rust konnte die entsprechende thread-lokale Datenstruktur direkter erreicht werden, wodurch dieser Zwangruf weggelassen werden konnte.

    Fazit ist nicht, dass Rust in Bezug auf Geschwindigkeit Zig übertrifft; eine solche Verallgemeinerung würde einer genauen Prüfung nicht standhalten. Der Punkt ist enger und nützlicher: Das Verschieben von Code über Sprachgrenzen zwingt jemanden oder etwas dazu, jeden Aufrufpfad genau zu prüfen, und diese Prüfung bringt gelegentlich Arbeit zum Vorschein, die nie notwendig war. Solche Erkenntnisse verdienen eine Einzelbewertung, nicht die Einbeziehung in eine Sprachdebatte.

    Wohin sich die ingenieurtechnische Arbeit verlagert hat

    Die Migration hat die ingenieurtechnische Arbeit nicht beseitigt; sie hat sie lediglich umgesiedelt. In der traditionellen Entwicklung geht ein großer Teil der Arbeitszeit darauf aus, Implementierungscode einzutippen. Bei entwicklungshelfenden Agenten verschiebt sich ein größerer Teil dieser Zeit auf:

    • die Definition von Einschränkungen und Übersetzungsvorschriften
    • die Gestaltung des Arbeitsablaufs, in dem die Agenten agieren
    • das Schreiben und Verbessern von Tests
    • die Überprüfung der erzeugten Änderungen
    • die Diagnose von Fehlern
  • Die Entscheidung darüber, welche Dateien und Systeme die Agenten ändern dürfen
  • Die Verstärkung des Feedback-Zyklus nach jeder Runde
  • Der Ingenieur ist für das System verantwortlich, das Code erzeugt und überprüft, anstatt für jede einzelne Zeile des Codes selbst. Bei einem großen Projekt sieht der Zyklus ungefähr so aus: Spezifikation, anschließend Erstellung, dann Kompilierung, danach Testing, danach Überprüfung, anschließend Korrektur – und wieder von vorn. Das Modell ist an mehreren dieser Schritte beteiligt, doch die Gestaltung des Zyklus bestimmt, ob das Ergebnis von Wert ist. Genau dieser Arbeitsablauf, und nicht die Anzahl der Zeilen, stellt die eigentliche Innovation dar.

    Warum Bun ein guter Kandidat war

    Nicht jede Codebasis eignet sich für diesen Ansatz, und Bun hatte mehrere Vorteile:

    • eine funktionierende Implementierung als Referenz
    • eine bekannte, stabile Architektur
    • Ein Verhalten, das über ein vorhandenes Testumfeld beobachtet werden konnte
    • eine klar gewählte Zielsprache
    • eine Codebasis, die in relativ unabhängige Dateien und Komponenten aufgeteilt werden kann
    • ein einziges, messbares Ziel: Das Programm beibehalten und die Sprache ändern

    Vergleichen Sie das damit, einem Agenten zu bitten, ein neues Produkt zu entwerfen – es gibt dabei keine Referenzimplementierung und was „richtig“ ist, hängt von der Meinung ab. Die allgemeine Regel lautet: Je genauer das gewünschte Verhalten definiert werden kann, desto mehr der Implementierung kann automatisiert werden. Das bedeutet jedoch nicht, dass Agenten jederzeit große Projekte übernehmen können. Es bedeutet vielmehr, dass die Automatisierung am besten funktioniert, wenn das Ziel messbar ist.

    Was die Migration nicht beweist

    Es ist leicht, ein solches Ergebnis überzubewerten, daher lohnt es sich, seine Grenzen klar zu benennen. Der Bun-Port zeigt nicht, dass KI Softwareentwickler ersetzen kann. Er zeigt auch nicht, dass jede Codebasis auf diese Weise übersetzt werden kann, dass generierter Code automatisch wartbar ist oder dass Rust immer schneller als Zig ist. Und er rechtfertigt sicherlich nicht die Einbeziehung riesiger, von KI generierter Pull-Requests in gewöhnlichen Produktcode.

    Im Gegenteil: Er zeigt gerade das Gegenteil. Die Arbeit hing von umfangreichen Tests, klaren Regeln, Validierung, Überprüfung, Debugging sowie ständiger menschlicher Aufsicht ab. Die Analyse des veröffentlichten Workflows weist außerdem darauf hin, dass die Agenten nicht unüberwacht laufen durften; Menschen überwachten den Prozess und passten ihn an, sobald Probleme auftauchten. Das ingenieurtechnische Urteilsvermögen wurde nicht weniger wichtig – es wurde vielmehr zu dem Fundament, auf dem alles andere beruhte.

    Die Überprüfung wird zum Engpass

    Seit Jahrzehnten gilt das Schreiben von Code als der langsame Schritt. Angenommen, ein Agent kann 10.000 Zeilen in der Zeit erzeugen, die ein Entwickler früher für 500 Zeilen benötigte. Die offensichtliche Reaktion ist, diese Geschwindigkeitssteigerung zu feiern – bis die nächste Frage auftaucht: Wer wird diese 10.000 Zeilen überprüfen?

    Das Erstellen von Code ist heute kostengünstig. Doch die Überprüfung auf Richtigkeit bleibt teuer, und der Aufwand steigt besonders bei Laufzeiten, Compilern, Datenbanken, Betriebssystemen sowie sicherheitskritischen Code-Teilen, bei denen ein kleiner Fehler zu großen Fehlern führen kann. Das deutet auf einen wachsenden Wert all dessen hin, was überprüft statt erstellt wird: Testsets, Observabilität, statische Analyse, Fuzzing, formale Methoden, Sandboxing sowie feindliche Überprüfungen. Die Teams, die am meisten von Coding-Agents profitieren, sind möglicherweise jene mit den stärksten Überprüfungssystemen – nicht unbedingt diejenigen, die Zugang zum besten Modell haben.

    Methoden, die Sie für Ihre eigenen AI-gestützten Anpassungen übernehmen können

    Um diese Erkenntnisse anzuwenden, benötigen Sie kein Projekt im Laufzeitumfang. Sie funktionieren genauso gut bei der Migration eines Services zwischen Frameworks oder bei der Umwandlung einer JavaScript-Codebasis in TypeScript.

    Führen Sie Tests vor der großen Änderung durch

    Eine gründliche Testsuite ist eine ausführbare Spezifikation. Je mehr Verhaltensweisen Sie automatisch überprüfen können, desto mehr Implementierungsarbeit können Sie sicher weitergeben. Ist die Abdeckung gering, ist deren Verbesserung der erste Meilenstein der Migration – und nicht eine nachträgliche Überlegung.

    Schreiben Sie die Regeln auf

    Vermeiden Sie Anfragen wie „Überschreiben Sie das.“ Legen Sie Architektur, Namenskonventionen, erlaubte und verbotene Abhängigkeiten, tabuisierte Abkürzungen, Erwartungen an die Fehlerbehandlung sowie die Akzeptanzkriterien für jede Arbeitseinheit fest.

    Trennen Sie Erstellung und Überprüfung voneinander

    Ein Agent sollte niemals der einzige Beurteiler seiner eigenen Ausgabe sein. Ein unabhängiger Überprüfungsschritt – sei es ein Mensch, ein zweiter Agent mit anderer Aufgabe oder beides – bringt eine neue Perspektive und erkennt Probleme, die der Erstellungsprozess übersehen hat.

    Pilotprojekt mit einer kleinen, repräsentativen Stichprobe

    Führen Sie den Prozess zunächst an einer Handvoll typischer Dateien durch. Falsche Annahmen sind leicht zu beheben, wenn sie zehn Dateien betreffen, aber äußerst teuer, wenn sie sich auf zehntausend Dateien erstrecken.

    Geben Sie generierten Code bis zum Beweis des Gegenteils als unzuverlässig an

    Code, der kompiliert wird, ist noch kein funktionierender Code. Die Kompilierung ist nur eine von mehreren Kontrollstufen und kein Beweis für Richtigkeit.

    Sorgen Sie dafür, dass Menschen für die wichtigen Entscheidungen verantwortlich sind

    Agenten können sehr schnell einen riesigen Raum möglicher Implementierungen durchsuchen. Die Entscheidung darüber, was das System tun muss und welche Risiken akzeptabel sind, bleibt weiterhin die Verantwortung des Menschen.

    Jenseits der Debatte Zig gegen Rust

    Es ist verlockend, die Situation als Zig gegen Rust, handgeschriebener Code gegen KI oder Menschen gegen Agenten darzustellen. Keine dieser Darstellungen erklärt viel. Die Bun-Portierung sollte eher als Experiment verstanden werden, wie Software entwickelt wird, wenn die Erstellung von Code fast nichts kostet. Sobald ein System Hunderttausende von Zeilen übersetzen kann, ändert sich die zentrale Frage von „Können wir das umsetzen?“ zu „Können wir einen zuverlässigen Prozess entwickeln, der uns sagt, ob die Umsetzung richtig ist?“ Das sind völlig unterschiedliche ingenieurwissenschaftliche Probleme.

    Wie das Ergebnis beurteilt werden sollte

    Die anfängliche Übersetzung ist nur die erste Phase. Eine mechanisch übertrugene Codebasis kann im Laufe der Zeit idiomatischer gestaltet werden: unsichere Bereiche werden überprüft und reduziert, Abstraktionen verbessert, die Leistung optimiert und Kompatibilitätsschichten abgeschafft. Wie jedes Produktionsystem wird es letztendlich danach beurteilt, ob es für echte Nutzer funktioniert. Die Quellmaterialien weisen darauf hin, dass Bun nach der Migration weiterhin Versionen veröffentlicht hat; prüfen Sie den Repository- und Changelog des Projekts für dessen aktuellen Status.

    Die aussagekräftige Bewertung ergibt sich eher aus langfristigen Anzeichen als aus der Größe der Überarbeitung:

    • ob die Laufzeit über verschiedene Versionen hinweg stabil bleibt
    • ob der Code einfacher zu warten ist
    • ob die Leistung weiterhin konkurrenzfähig bleibt
    • ob memorierelevante Fehler seltener auftreten
    • ob Mitwirkende den neuen Code verstehen und verbessern können

    Kernpunkte

    • Der Wert der Bun-Migration liegt im Zyklus aus Regeln, Tests, Überprüfung und Korrektur – nicht in der Menge des generierten Codes.
    • Durch die Darstellung einer Neuimplementierung als portierter Code, der das ursprüngliche Verhalten beibehält, erhalten Agenten ein messbares Ziel und Überprüfer eine konkrete Checkliste.
    • Ein Portierungsleitfaden reduziert den Bereich der zulässigen Ausgabe und macht eine umfassende Überprüfung möglich.
    • Ausführlicher oder auf unsafe-Code angewiesener Rust in einer getreuen Portierung ist oft der unvermeidliche Preis für Äquivalenz; unsafe-Code sollte anhand seiner Grenzen beurteilt werden, nicht nach ihrer Anzahl.
    • Sobald die Codegenerierung günstiger wird, liegt der Unterschied zwischen Teams in der Investition in die Überprüfung – und das Entwerfen dieses Rückkopplungsschleifens wird zunehmend zum Kern der Ingenieurarbeit.