Warum sollten wir das tun?
- Im Zuge einer Softwaremodernisierung auch gleich die Vorzüge von Rust nutzen.
- Zertifizierung
- Security
- Höhere Entwicklungsgeschwindigkeit mit Rust (weniger Laufzeitfehler, weniger Debugging)
- Ein internes oder externes Tool oder Library existiert und wird auch in Rust benötigt.
- Vereinheitlichen des Software-Stacks in einer Firma oder einem Produkt
Garbage In – Garbage Out: Zwei Fälle
Wie reibungslos die Migration läuft, entscheidet sich an der Vorlage: gute Vorlage rein, reibungslose Migration. Bei schlechter Vorlage ist ein gutes Ergebnis zwar weiterhin möglich, aber nur mit mehr Aufwand.
Wir können die bestehende Struktur übernehmen
Die Architektur ist zweckmässig und genügt damit den funktionalen Anforderungen in guter Qualität. Es gibt eine sinnvolle Testabdeckung auf allen Ebenen. So können wir direkt mit dem Migrieren beginnen.
Die bestehende Software ist schwierig zu verstehen
Es ist unklar in welchen Teilen der Codebasis welche Funktionalität ist. Mangels Tests ist nicht ganz klar, welche Funktionen die Software überhaupt erfüllt. Qualitätsanforderungen sind weder formuliert noch umgesetzt.
In diesem Fall sind wir tief im Thema Softwaremodernisierung. Bei einer Softwaremodernisierung müssen wir uns zuerst über unsere Geschäftsziele, die funktionalen Anforderungen und die Qualitätsziele Gedanken machen. Daraus können wir eine Zielarchitektur herleiten. (Weiter Informationen zu Softwaremodernisierung in unserem Blog)

Rust vs modern C++
Rust trifft auf modernes C++: Ein fairer Vergleich einiger Sprachfeatures aus technologischer Sicht. Jetzt lesen auf Tech Insights – der bbv Blog von Techies für Techies.
Vorgehen
Inkrementelles Vorgehen
Weil wir der AI nicht trauen können und weil wir immer wieder einen funktionierenden Codestand haben wollen, drängt sich ein inkrementelles Vorgehen auf.
Es gibt einen fundamentalen AI Migration Loop, in dem Software mittels AI migriert wird.
- Die AI erhält als Input
- Einen Auftrag: das heisst, welches Stück Code migriert werden soll
- Einen Satz Regeln
- Architekturvorgaben
- Design Patterns
- Coding Guidelines
- Beispielcode
- Der AI-Output wird von Entwickler:innen reviewed. Hier ist echte Rust-Expertise gefragt, um beurteilen zu können, ob der generierte Code zweckmässig ist und good Practices erfüllt. Zum Beispiel:
- Sind geeignete Rust-Idiome eingesetzt?
- Sind Design Patterns sinnvoll eingesetzt?
- Ist die Testabdeckung sinnvoll?
Aus dem Review lernen wir und passen die Regeln an. Zum Beispiel können wir gewisse Muster als Design Pattern vorgeben oder unerwünschte Muster verbieten.
Zusätzlich gibt es einen inneren Loop, den die AI selbständig durchlaufen kann. Im Prinzip ist dies ein Red/Green/Refactor Loop bekannt von BDD und TDD. Dass die AI den inneren Loop anwenden soll, ist Teil des Regelsatzes.
- Test implementieren
- Code implementieren, so dass die Tests erfolgreich sind.
- Eine andere AI oder Subagent macht ein Codereview
- Code refactoring, damit der Code den Regeln genügt
- Nächster Test
Ein innerer Loop ist auch dadurch motiviert, dass die AI oft Regeln «vergisst». In einem Code Review einer anderen AI stehen diese Regeln aber im Fokus und gehen weniger im Kontext unter.
One-Shot
Bei diesem Ansatz gehen wir davon aus, dass die Ausgangscodebasis gut genug ist. Wir lassen die gesamte Codebasis auf einmal migrieren. Weil das Resultat aber fast ganz sicher ungenügend ist, verbessern wir den Code mit dem fundamentalen Loop.
Wenn wir feststellen, dass das Resultat derart schlecht ist, dass inkrementelle Verbesserungen nicht zielführend sind, kann das daran liegen, dass unsere Regeln nicht gut genug sind. In diesem Fall verbessern wir die Regeln und probieren es noch einmal. Falls dies wiederholt scheitert, haben wir es möglicherweise doch mit einer ausgewachsenen Softwaremodernisierung zu tun.
Slice by Slice
Wenn die Codebasis zu gross ist für One-Shot oder wenn wir schon gute Akzeptanztests für Features haben, können wir mit dem fundamentalen Loop Feature um Feature migrieren.
Modernisierungsansatz
Zuerst müssen wir die Zielarchitektur festlegen und mindestens in Grundzügen implementieren oder dokumentieren, damit sich die AI daran halten kann. Gewisse Features können aus der bestehenden Codebasis übernommen werden (sonst wäre es keine Migration sondern eine Neuentwicklung). AI hilft, um diese Features im bestehenden Code zu lokalisieren, isolieren und extrahieren. So kann Slice by Slice mit dem fundamentalen Loop migriert werden.
Übrigens:
Festlegen der Zielarchitektur ist in der Regel eine entscheidende Aufgabe, in die sowohl Business-Stakeholders als auch Entwickler:innen involviert sein sollten.

Erfolgreiche Einführung von Rust in Ihrem Team
Wie schaffen Sie es, Rust in Ihr bestehendes Team einzuführen? Essenziell dafür sind motivierte Mitarbeitende, eine klare Roadmap und die Weitergabe von Wissen.
Nützliche Taktiken
Meine Testabdeckung ist ungenügend
Falls die Abdeckung mit formellen Tests nicht genügend ist, können wir uns mit Approval Tests behelfen.
Dies hilft, um den inneren Loop zu schliessen. So hat die AI einen konkreten Anhaltspunkt dafür, ob die Software wie gewünscht funktioniert.
Gewusst?
Approval Testing (auch Golden Master oder Snapshot Testing) vergleicht die tatsächliche Ausgabe eines Codes (z.B. ein serialisiertes Struct oder println-Output) gegen eine zuvor genehmigte Referenzdatei. Anders als beim klassischen Unit-Test schreibt man den Erwartungswert nicht selbst, sondern genehmigt die vom Werkzeug erzeugte Ausgabe. Stark, um das aktuelle Verhalten von Legacy-Code vor Refactorings abzusichern. Nachteil: Jede beabsichtigte Änderung lässt den Test brechen und erfordert ein erneutes Genehmigen.
Rust: insta
C++: ApprovalTests.cpp
C#: ApprovalTests.Net oder Verify
Ich kann ein Muster nicht 1:1 von der Ausgangssprache zu Rust übersetzen
Gewisse Muster sind von Sprache zu Sprache verschieden. Beispiele:
- Async Programmierung in Rust ist anders als in C#. In C und C++ behilft man sich manchmal mit Event Loops und State Machines, um Concurrency zu erreichen.
- Viele Sprachen haben Exceptions, um Fehler zu signalisieren. Rust setzt auf
als Rückgabetyp, der im Erfolgsfall vom TypResult<T,E>Tist und sonst vom TypEist. Dies ist aber nur die Mechanik. Wir müssen uns aber immer noch überlegen, auf welcher Stufe welche Fehlertypen behandelt werden. (siehe Error-Handling Blogbeitrag) - Rust kennt keine klassische Vererbung. Falls der originale Code stark auf Vererbung setzt, müssen wir das Datenmodell anpassen.
Zur Info:
Rust unterstützt OO-Konzepte, kennt aber keine klassische Vererbung. Eine typische OOP-Hierarchie (Basisklasse mit virtuellen Methoden, Subklassen) wird in Rust über Traits plus Komposition gelöst. Polymorphie entweder statisch über Generics (fn f<T: Trait>) oder dynamisch über Trait-Objekte (dyn Trait).
Diese Muster naiv zu migrieren mag zwar manchmal funktionieren, ist aber nicht idiomatisch und spielt fast sicher nicht die Stärken von Rust aus. In solchen Fällen lohnt es sich deshalb ein Konzept zu entwickeln, wie ein Muster oder ein Datenmodell in Rust geeignet umgesetzt wird. Um schnell verschiedene Varianten auszuprobieren, hilft AI offensichtlich auch. Das so etablierte Muster muss der AI als Beispielcode oder als Regel zugänglich gemacht werden, damit die AI den Code korrekt migrieren kann.
Wie gehe ich mit dem Borrow Checker um?
Der Borrow Checker ist gefürchtet von Novizen und geschätzt von Könnern. Wenn das Compilieren fehlschlägt mit einem Borrow Checker Error, handelt es sich in den meisten Fällen um eine Designschwäche.
Die AI «löst» dieses Problem oft mittels Arc<Mutex<T>> damit der Borrow Checker nicht anschlägt, anstatt das zugrundeliegende Designproblem zu lösen. Manchmal müssen Objekte aber tatsächlich shared werden. Hier kommen wiederum die Software-Ingenieure zum Zug, um zu entscheiden, ob dies ein legitimer Fall ist, um ein Objekt zu sharen. Eine Faustregel könnte sein, dass Arc<Mutex<T>> und Konsorten schlicht verboten werden und die AI zwingend Rücksprache mit Entwickler:innen halten soll. Eine häufige idiomatische Lösung ist, dass Objekte mittels Nachrichten kommunizieren und nicht mittels sharen von Objekten.
Kommunizieren mittels Nachrichten?
Der Slogan «Do not communicate by sharing memory; instead, share memory by communicating.» der auch in Go umgesetzt wird ist im «Rust Buch» im Kapitel Message Passing in Rust konkret beschrieben.
Was prüft der Borrow Checker?
Die Borrowing-Regeln sind:
1. Ein Objekt kann beliebig oft immutable ausgeliehen (immutable borrow) werden.
2. Ein Objekt kann nur einmal gleichzeitig als mutable ausgeliehen werden, es gibt also genau diese eine mutable Reference.
3. Nachdem der mutable borrow seinen Scope verlässt, können die immutable borrows wieder verwendet werden oder es kann wieder ein mutable borrow erstellt werden.
Es braucht etwas Gewöhnung daran, dass der Scope einer Reference mit ihrer letzten Verwendung endet und nicht mit dem tatsächlichen Scope-Block.
Fazit
Gute Software ist mit dem geeigneten Vorgehen leicht nach Rust zu migrieren. Vor dem Aufkommen von AI hätte man wohl in den meisten Fällen gesagt, dass eine Migration zu aufwändig ist. Heute können wir eine Migration leicht nebenher bewerkstelligen. Ganz auf die AI verlassen kann man sich aber nicht. Es braucht immer noch erfahrene Entwickler:innen, die die Geschäftsziele verstehen und diese in eine geeignete Architektur und geeignete Designs umsetzen können.
FAQ zu Rust Migration mittels KI
Nein, aber die AI beschleunigt die Migration erheblich, ersetzt aber das menschliche Review nicht. Der generierte Code wird in einem inkrementellen Loop von erfahrenen Entwickler:innen geprüft und die Regeln werden laufend nachgeschärft. Eine vollautomatische Migration ohne Kontrolle führt zu nicht-idiomatischem und oft fehlerhaftem Rust-Code.
Nicht ohne Review. Der erste Output ist fast nie ausreichend. Erst durch den Red/Green/Refactor-Loop, eine sinnvolle Testabdeckung und das Festhalten von Architekturvorgaben in den Regeln entsteht produktionsreifer Code. Typische Schwachstellen wie unnötiges Arc<Mutex<T>> deuten auf Designprobleme hin, die ein Mensch beurteilen muss.
Ja. Vor AI galt eine solche Migration meist als zu aufwändig. Mit AI geht sie heute entscheidend schneller und ist damit machbar, sofern die bestehende Software eine zweckmässige Architektur und eine sinnvolle Testabdeckung hat. Ist die Codebasis schwer verständlich und ungetestet, handelt es sich eher um eine Softwaremodernisierung als um eine reine Migration.
Dann steht zuerst die Modernisierung an: Geschäftsziele, funktionale Anforderungen und Qualitätsziele klären, daraus eine Zielarchitektur ableiten. Fehlt eine formale Testabdeckung, helfen Approval Tests (Golden Master), um das bestehende Verhalten abzusichern, bevor migriert wird. AI hilft dann beim Lokalisieren, Isolieren und Extrahieren einzelner Features für eine Slice-by-Slice-Migration.
