Von Rust zu Ruby
(xlii.space)- Ein persönliches Projektexperiment, bei dem ein Rust-Webapp-Crate nach Ruby on Rails portiert wird; Ziel sind 14.943 Zeilen Code auf Basis von Tera und Axum
- Die bisherige Rust-Struktur erfordert für Tests Playwright-E2E, isolierte Datenbank-Namespaces, Mocking-Services und sogar ein internes API-Crate, wodurch der Testaufwand hoch ist
- Im LLM-Vergleich erzielt Rails mit insgesamt 710 Punkten mehr als Rust/Axum/Diesel mit 480; als Stärken gelten Entwicklungsgeschwindigkeit und einfache Unit-Tests
- Die One-Shot-Konvertierung mit Local Qwen3.6 dauerte etwa 30 Minuten, der Ruby-Code schrumpfte auf 3.322 Zeilen, wurde aber noch nicht durch Ausführung verifiziert
- Rails punktet mit vielen Grundfunktionen und kompakten Tests; die fehlende Typsicherheit von Ruby lässt sich mit Sorbet oder agentenbasierter Typ-Ergänzung abmildern
Hintergrund des Umstellungsexperiments
- Ein Rust-Webapp-Crate als Teil eines privaten Projekts wurde als Kandidat für die Migration zu Ruby on Rails ausgewählt
- Das Gesamtprojekt umfasst etwa 30.000 Zeilen, und das Ziel-Crate kommt einer mit Tera und Axum geschriebenen Webapp nahe
- Der zu migrierende Rust-Code umfasst insgesamt 14.943 Zeilen, die Kompilierung dauert etwa 10 Sekunden
- Der Code selbst ist nicht groß, hängt aber an einer Struktur mit vielen Abhängigkeiten
- Die bestehende Rust-Konfiguration verursacht hohe Testkosten
- Für E2E-Tests ist eine Playwright-Konfiguration erforderlich
- Weil Mocking schwierig ist, werden isolierte Datenbank-Namespaces und Mocking-Services benötigt
- Zusätzlich ist ein internes API-Crate nötig, damit Playwright im Headless-Modus mit der App interagieren kann
- Ruby und Ruby on Rails werden als kompakte Alternative betrachtet
- Ruby ist untypisiert, wodurch die Stabilität geringer sein kann als bei Rust
- Mit Sorbet lässt sich die Typsicherheit in Ruby teilweise ergänzen
- Ein Vergleich mit mehreren LLM-Instanzen zu Komplexität, Stabilität, Testbarkeit und weiteren Kriterien fiel zugunsten von Rails aus
- Rust/Axum/Diesel kommt insgesamt auf 480, Rails auf 710, Rails + Sorbet auf 695
- Rails wurde mit 90 für Eignung für Einzelentwickler, 90 für Entwicklungsgeschwindigkeit und 90 für einfache Unit-Tests hoch bewertet
- Rust/Axum/Diesel erzielt zwar 95 bei Sicherheit und 95 bei Performance, liegt aber bei Unit-Tests mit 20 und bei Integrationstests mit 30 deutlich niedriger
- Auf Basis der einfachen Gesamtsumme wurde geschlossen, dass eine Rails-App ein 1,47-fach besseres Ergebnis liefern könnte
Ergebnis der Konvertierung und Prüfpunkte
- Mit Local Qwen3.6 wurde ein relativ kleines Projekt in einem One-Shot konvertiert
- Die Konvertierung dauerte etwa 30 Minuten
- Es wurde noch nicht ausgeführt, daher ist die tatsächliche Funktionsfähigkeit nicht bestätigt
- Die größte Veränderung ist die Verringerung der Codezeilen
- Gesamte Zeilenzahl der Rust-Dateien: 14.943
- Gesamte Zeilenzahl der Ruby-Dateien: 3.322
- Die Zeilenzahl sank um 77 %, und eine Ruby-Zeile entspricht ungefähr 4,49 Rust-Zeilen
- Der konvertierte Ruby-Code wirkt im überflogenen Umfang sauber und idiomatisch
- Die Möglichkeit von Bugs bleibt bestehen
- Eine genauere Prüfung ist für später geplant
- Weitere Prüfpunkte sind Typ-Ergänzung, die Grundfunktionen von Rails und die Vereinfachung von Tests
- Wenn ein Agent Typen ergänzt, lässt sich das Problem fehlender Typsicherheit abmildern
- Ruby/Rails wird als näher an „batteries + kitchen sink included“ bewertet und damit besser als 3 GiB kompilierter Abhängigkeiten
- Es wird erwartet, dass Tests deutlich einfacher werden
- Das Ruby-Testbeispiel kapselt den LLM-Aufruf mit
VCR.use_cassette("llm_call")und prüft in kurzer Form die Größe des ErgebnissesVCR.use_cassette("llm_call") do result = LlmClient.match(entry, data_list) expect(result.results.size).to eq(data_list.size) end - Das Rust-Testbeispiel ist länger, weil ein Mock-Provider direkt implementiert werden muss
- Verwendet werden
Arc<RwLock<Vec<Response>>>,AtomicUsize,async_trait,tokio::testusw. - Es wird ein
MockProvidererstellt, der die Antwortliste und die Anzahl der Aufrufe verwaltet; anschließend wirdmatchdesProvider-Traits implementiert und im Test werden Ergebnis und Anzahl der Aufrufe geprüft
- Verwendet werden
- Da es sich um ein privates Projekt handelt, sind mutige Entscheidungen möglich; die Umstellung von Rust auf Ruby soll in Zukunft noch eingehend geprüft werden
1 Kommentare
Hacker-News-Kommentare
Kaum zu glauben. Das klingt für mich nach: „Es gab da einen technischen Juckreiz, den ich kratzen wollte, und lokale KI hat die Arbeit in 30 Minuten erledigt. Ich habe nicht einmal auf Start gedrückt, um zu sehen, ob es läuft, aber den Blogpost habe ich schon geschrieben …“
außer natürlich, Bots haben ihn nicht nach oben gepusht
2026: Schaut euch etwas an, das ich nicht selbst geschrieben habe!
2036: So habe ich 200 Zeilen in C geschrieben, dieser alten lateinischen Sprache
Erst dachte ich, das wird ein interessanter Artikel, aber in dem Moment, als erwähnt wurde, dass für die Migration ein LLM benutzt wurde, war mein Interesse sofort weg. Das ist ungefähr wie: „Ich wollte das machen lassen, also habe ich es einem Untergebenen aufgetragen, und jetzt erzähle ich euch davon.“
Er hat die Migration weder selbst gemacht noch besonders tief darüber nachgedacht, daher sehe ich keinen Grund, das zu lesen
true-Rückgaben eingebaut sindDann kann schon ein einfacher Smoke-Test so aussehen lassen, als wäre alles erfolgreich gewesen
Abgesehen von handwerklicher Programmierung wird die Programmiersprache selbst immer weniger wichtig
Je besser LLMs werden, desto mehr wird es am Ende nur noch darum gehen, Spezifikationen in irgendeiner Art von Sprache erzeugen zu lassen
Das UML- und RUP-Lager hat damit wohl doch noch seine Rache bekommen
Wie auch in anderen Kommentaren erwähnt, wurde das Ganze ziemlich umfassend geprüft. Es ist kein großes Projekt, und abgesehen von ein paar heiklen Stellen ist es größtenteils eine Web-App
Zu behaupten, es sei „nicht nachgedacht“ worden, halte ich für unfair. Das war kein Knopf-drücken-und-YOLO
Es wurden Trade-offs und Ergebnisse untersucht, die Unterschiede zwischen Rust-Codefragmenten und Rails waren real erheblich, und die Testbarkeit der Rust-App war zwei Monate lang ein Thema der Überlegung
Wie LLM-Fans gern sagen: Kontext ist wichtig ;)
Ich weiß nicht, ob irgendeine Sprache oder irgendein Framework das Glück der Entwickler so stark priorisiert wie Ruby on Rails
grep, um die View zu finden, die falsch rendert. Ich finde den Methodenaufruf, der den betreffenden Abschnitt rendert, grepe dann nach dem Methodennamen und bekomme null TrefferIrgendetwas wird irgendwo zusammengesetzt, ich kann nicht herausfinden, wo es ist, und am Ende höre ich mit meiner eigentlichen Arbeit auf und lese eine Stunde lang Dokumentation. Für Leute, die den ganzen Tag nur Rails machen, ist das vielleicht okay, aber Convention over Configuration ist für mich ein riesiges Anti-Pattern
method_missing, mit der man sich selbst ins Knie schießtGlück führt nicht immer zu Leistung. Mir fällt dabei das berühmte Logo-Beispiel von Twitter ein, bevor der Wechsel auf JVM und Scala kam
Ruby on Rails wurde zwar berühmt, aber ähnliche Erfahrungen gab es schon mit dem Tcl-basierten AOLServer und Vignette
In einem portugiesischen Startup wurde sogar eine eigene Abwandlung gebaut, und die Gründer haben später OutSystems geschaffen. Das war eines der frühen grafischen RAD-Tools für die Entwicklung von Websites und verteilten Systemen, als Low-Code/No-Code für JVM- oder CLR-Infrastruktur
Trotzdem freue ich mich inzwischen darüber, dass JIT in CRuby standardmäßig mitgeliefert wird
Ich habe bereits ein Gem-Bundle namens propel_rails gebaut, das ohnehin schon kompakten Ruby-on-Rails-Code noch weiter auf die Spitze treibt. Es erzeugt Oberklassen wie API-Controller und Concerns, und von dort aus entstehen komplette RESTful Resources (Modelle, Controller, Serializer, Unit-Tests und E2E-Tests) ganz ohne Boilerplate
Am Ende enthalten Controller nur noch die Liste der Attribute, die die API zulässt, weil die RESTful Actions automatisch generiert werden. Es ist etwas schwer, das vollständig zu erklären, aber die Kraft von Rubys Metaprogrammierung macht wirklich erstaunliche Dinge sehr einfach
Kann man es so verstehen, dass es vom Domain Model ausgeht?
Ich bin in einer ähnlichen Situation
Ich mag Go und Rust, und beides sind großartige Sprachen mit Vor- und Nachteilen. Aber leider konnte ich mit keiner von beiden eine SaaS-App bauen. Es fühlt sich an, als würde man einen quadratischen Stift in ein rundes Loch stecken
Vielleicht irre ich mich komplett, aber SaaS-Tools bringen eine Menge Dinge mit, die man nicht neu erfinden will
RoR ist „gut genug“. Man kann Typisierung einführen, wenn man sie will, man kann schnell bauen, und die Tools sind auch okay
Mein erster Job war mit PHP, und dort gab es zu viele Fallstricke. Ruby wirkte für mich etwas stärker in Richtung E-Commerce geneigt, was ich interessant fand, und wenn es für Shopify gut genug ist, reicht es wohl auch mir
Wenn es sinnvoll ist, von Rust auf Ruby umzusteigen, dann war schon die ursprüngliche Wahl von Rust ein Fehler
Wer denkt, Ruby sei langsamer als Rust, wäre vermutlich überrascht zu erfahren, dass Ruby heute in der Praxis schneller als Python ist und langsamer als Go oder Rust
Wenn man aber mehrere Background-Worker hat und jeder davon mehr als 2 GB Speicher frisst, summiert sich das schnell
Ich habe einen Rust-Service in Produktion geschrieben, und beeindruckender als die Geschwindigkeit war für mich, dass dieser Service mit 30 MB Speicher lief
Provokant formuliert: Für die gewöhnlichen Leute um dich herum ist Rust vielleicht gut, um mit 900+ IQ anzugeben, aber viele kluge und talentierte Entwickler mögen Rust schlicht nicht besonders. Manche ziehen es sogar vor, ihre eigene Programmiersprache und ihren eigenen Compiler zu bauen, statt auch nur eine Zeile Rust zu schreiben
Mir fallen da Jonathan Blows Jai und Ginger Bills Odin ein
Es gibt noch viele weitere Leute mit bewiesener Kreativität und Tiefe, die schöne, weit verbreitete Bibliotheken und Frameworks gebaut haben, aber ich will hier keinen Platz verschwenden
Rust hat allerdings einen coolen Macho-Club und eine eng verbundene Bruderschaft
Claude funktioniert bei Rails-Apps wirklich gut. Wie der Autor des Artikels auch anmerkt, ermöglicht Ruby mit wenig Code sehr viel, und Rails setzt auf Convention over Configuration, wodurch Rails-Apps noch kompakter werden
Eine mögliche Hypothese, warum Claude Rails-Apps so gut schreiben kann, ist Token-Effizienz
Ich habe einmal dieses Projekt gesehen, das die Token-Effizienz pro Projekt messen und vergleichen wollte, und Rails hat dort ziemlich gut abgeschnitten
https://felipemrvieira.github.io/SyntaxTax/dashboard/
Ich bin manchmal überrascht, wenn ich die Größe von Projekten sehe. Eine Codebasis mit 30.000 Zeilen soll klein sein? Mir ist klar, dass die Obergrenze hoch liegt, aber 30.000 Zeilen können eine enorme Menge an Information und subtilem Verhalten enthalten
Vielleicht liegt das an meinem Hintergrund, der eher auf Backend/Netzwerk mit Go fokussiert war. Sobald es über 10.000 bis 15.000 Zeilen hinausging, wurde es für mich normalerweise ziemlich belastend, das Gesamtmodell der Codebasis im Kopf zu behalten