3 Punkte von GN⁺ 2024-10-07 | 1 Kommentare | Auf WhatsApp teilen
  • Selbst beim Bau kleiner Web-Apps in Rust fehlt eine integrierte Erfahrung wie bei Django; dadurch wächst der Aufwand, Routing, Login, DB und Admin-Funktionen selbst zusammenzusetzen
  • Das benötigte Framework sollte Routing/Handler, Templates, Bereitstellung statischer Dateien, Login, Berechtigungen, DB-Interface, Admin-Werkzeuge, WebSockets und Hot Reloading standardmäßig bündeln
  • Es gibt minimalistische Frameworks wie actix-web und axum sowie SPA-Frameworks wie Dioxus, Leptos und Yew, aber sie setzen nicht die gesamte Web-App-Konfiguration für einen zusammen
  • Starter-Templates reduzieren zwar die anfängliche Einrichtung, doch nachdem sich ein Projekt verzweigt hat, bleiben das Zusammenführen von Änderungen und Bibliotheks-Updates als Wartungsaufwand bestehen
  • newt versteht sich als Web-Toolkit, das bestehende Komponenten auf meinungsstarke Weise bündelt; Ziel ist, kleine Web-Apps nicht in Tagen, sondern in wenigen Minuten starten zu können

Rust-Webentwicklung fehlt ein integrierter Einstiegspunkt

  • Selbst bei kleinen Webprojekten in Rust ist deutlich mehr anfängliche Verknüpfungsarbeit nötig als mit Django oder ähnlichen Frameworks
  • Der übliche Ansatz in der Rust-Community ähnelt eher dem eigenhändigen Zusammenstecken der benötigten Bauteile
    • Auch Are We Web Yet? weist darauf hin, dass man in der Rust-Webentwicklung typischerweise selbst verbinden muss und beim Start mit zusätzlicher Einrichtungsarbeit rechnen sollte
  • Diese zusätzliche Arbeit ist nicht einfach nur „ein bisschen mehr“, sondern umfasst viele Punkte, die erledigt werden müssen, bevor man wirklich mit dem Projekt beginnt
  • Mit einem integrierten Web-Framework ließe sich Rust leichter als Wahl für Web-Apps vermitteln
    • Als Vorteile von Rust werden das Typsystem, Performance und die Kaffeepausen während der Compile-Zeit genannt

Grundbausteine, die fast jede Web-App braucht

  • Routing/Handler

    • Eingehende Requests müssen an den passenden Handler geleitet werden
    • Pfadparameter müssen verarbeitet werden, idealerweise mit Typinformationen
    • Query-Parameter und Formularverarbeitung wären ebenfalls nützlich
  • Templates

    • HTML muss erzeugt werden, je nach Fall auch JSON oder XML
    • Grundlegende Logik wie Bedingungen, match/switch und Schleifen ist nötig
  • Bereitstellung statischer Dateien

    • Assets wie CSS müssen ausgeliefert werden
    • Das kann auch über einen separaten Server laufen, aber für lokale Entwicklung und kleine Deployments ist es praktisch, wenn es im selben Webserver enthalten ist
  • Login

    • Apps sind meist Mehrbenutzersysteme oder werden in öffentlichen Netzwerken bereitgestellt, daher ist Login-Funktionalität fast immer erforderlich
    • Weil es lästig ist, sie jedes Mal selbst zu integrieren, sollte sie von Anfang an einfach nutzbar sein
    • Anpassung und Opt-out sollten möglich sein
  • Berechtigungen

    • In Systemen mit mehreren Nutzern unterscheiden sich zugängliche Daten oder Rollen
    • Schon ein Muster wie check(user, object, action) trägt recht weit
  • DB-Interface

    • Es braucht eine Möglichkeit, App-Daten zu speichern
    • Ein Ansatz nahe an einem ORM kann nützlich sein, leichtere Varianten sind aber ebenfalls möglich
    • Da es für Login, Berechtigungen und Admin-Werkzeuge verwendet wird, wird es zu einem Grundbaustein
  • Admin-Werkzeuge

    • Beim Einrichten einer Anwendung lokal oder in Produktion muss mindestens ein Benutzer oder ein Teil der Daten gebootstrapped werden
    • Einige gemeinsame Admin-Aufgaben sollten eingebaut sein, damit die Erfahrung reibungslos ist
  • WebSockets

    • Damit lässt sich Funktionalität bauen, die Daten nahezu in Echtzeit an verbundene Nutzer pusht
  • Hot Reloading

    • Änderungen an Code oder Templates sollten so schnell wie möglich sichtbar werden; das ist für die Developer Experience sehr wichtig

Ergänzende Funktionen für langlebige Projekte

  • Hintergrundjobs

    • Es entstehen Funktionen, die nach Zeitplan laufen müssen; ein konsistenter Ansatz erleichtert die Entwicklung
  • Monitoring/Observability

    • Das ist nötig, sofern es sich nicht um die kleinsten und unwichtigsten Systeme handelt
    • In dem Moment, in dem man es wirklich dringend braucht, ist es eine große Hilfe
  • Caching

    • Es gibt viele Implementierungsweisen, alle erhöhen die Komplexität, und ob es schneller wird, hängt von der Situation ab
    • Eine Framework-seitige Geschichte dazu wäre gut, Nutzer können es aber auch selbst handhaben
  • E-Mail und Benachrichtigungen

    • Wenn es Login-Funktionalität gibt, kann E-Mail wegen Passwort-Resets praktisch notwendig sein
    • Andere Benachrichtigungsfunktionen können bei Bedarf ohne große Probleme ergänzt werden
  • Deployment-Werkzeuge

    • Ein konsistenter Weg, an einen bestimmten Ort zu deployen, wäre gut
    • Schon ein automatisch generiertes Dockerfile, das beim gewählten Hoster funktioniert, wäre nützlich
  • CSS/JS-Bundling

    • Es wäre gut, wenn Web-Werkzeuge CSS und JS erkennen und natürlich einbinden könnten
    • Ob das zwingend integriert sein muss, ist unklar

Die Lücken, die das bestehende Rust-Web-Ökosystem lässt

  • Rust hat bereits viele Werkzeuge für Webentwicklung, aber keines zielt auf die gewünschte integrierte Erfahrung ab
  • Minimalistische Web-Frameworks

    • actix-web und axum ähneln kleinen Frameworks wie Flask oder Sinatra
    • Sie nutzen Rusts Typsystem, um eine gute Webentwicklungserfahrung zu bieten, stellen über Handler hinaus aber kaum zusätzliche Funktionen bereit
    • Die meisten Projekte lassen sich zwar mit solchen minimalistischen Frameworks bauen, doch die benötigten Funktionen jedes Mal selbst zu verbinden, ist mühsam
  • SPA-Frameworks

    • Dioxus, Leptos und Yew besetzen den Bereich, in dem Rust gemeinsam für Backend und Frontend verwendet wird und WebAssembly fürs Frontend-Rendering zum Einsatz kommt
    • Die Erfahrung, digital vigil mit Yew zu bauen, war erfreulich, aber ob man es in einer echten Produktionsumgebung einsetzen möchte, ist nicht sicher
    • Auch diese Frameworks sind für ihren jeweiligen Zweck hervorragend, erfordern aber weiterhin viel Verknüpfungsarbeit
  • Bündel einzelner Bibliotheken

    • Es gibt viele Bibliotheken für Templates, Login, Berechtigungen und WebSockets
    • Einige Projekte und Beispiele integrieren mehrere Komponenten, aber es ist schwer, etwas zu finden, das alle verwendeten Teile integriert
    • In einem schnelllebigen Ökosystem können manche Beispiele veraltet sein
    • „Einfach verbinden“ bedeutet letztlich, die Funktionsweise jeder Bibliothek zu recherchieren und ausreichend zu verstehen

Die Wartung, die Starter-Templates nicht lösen

  • Der bestehende Weg besteht meist darin, ein Basis-Framework wie actix-web oder axum zu wählen, die benötigten Teile zu finden, daraufzusetzen und sie selbst zu verbinden
  • Starter-Templates können den anfänglichen Schmerz reduzieren, aber der Wartungsaufwand bleibt
    • Bibliotheken müssen aktuell gehalten werden
    • Auch auf Breaking Changes muss reagiert werden
    • Sobald sich ein Projekt vom Template entfernt hat, wird es schwierig, Template-Änderungen wieder zusammenzuführen
  • Wenn man mehrere Projekte betreibt, muss man statt eines Frameworks n maßgeschneiderte Frameworks jeweils einzeln aktualisieren
  • Besser wäre ein Web-Framework, das das Ganze übernimmt und Upgrade-Anleitungen zwischen Versionen bereitstellt
    • Breaking Changes können auftreten, lassen sich aber dokumentieren
    • Es kann reduziert werden, dass Probleme durch Änderungen im Zusammenspiel zweier Komponenten entstehen, die nicht wissen, dass sie miteinander integriert werden sollen

Das Web-Toolkit, auf das newt abzielt

  • Das ideale Rust-Web-Framework sollte neben den oben genannten Funktionen gute Dokumentation, ein Changelog, sorgfältiges Versionsmanagement, Umgang mit Breaking Changes und eine Community haben
  • Derzeit existiert kein solches Werkzeug, und es ist auch nicht sicher, ob jemand anderes daran arbeitet
  • Das Werkzeug in Arbeit ist eher ein Web-Toolkit, das bestehende Bausteine auf meinungsstarke Weise verbindet, als ein Framework
  • Dieses Toolkit heißt nicole's web toolkit, kurz newt
    • Es ist in einem public repository veröffentlicht
    • Es ist noch nicht nutzbar, und die neuesten Änderungen sind noch nicht gepusht
    • Es ist auch noch nicht bereit, Beiträge entgegenzunehmen
  • Ziel von newt ist, beim Erstellen einer neuen kleinen Web-App nicht tagelang Verknüpfungsarbeit leisten zu müssen, sondern innerhalb weniger Minuten mit der eigentlichen Projektarbeit beginnen zu können
  • Einige Komponenten sollen bei Bedarf auch von Grund auf neu gebaut werden
    • Das kann einfacher sein oder kohärenter zusammenpassen
  • Das Rust-Ökosystem braucht einen gesunden Zustand, in dem es mehrere solcher Toolkits gibt, und es wird gehofft, dass auch andere Werkzeuge entstehen

1 Kommentare

 
GN⁺ 2024-10-07
Hacker-News-Meinungen
  • Ich war überrascht, dass Rocket (https://rocket.rs/) nicht unter den Frameworks ist, die der Autor auflistet.
    Ich habe es selbst nicht benutzt und bevorzuge das weniger meinungsstarke axum/actix-web, aber meinem Verständnis nach kommt Rockets Ziel dem vom Autor gewünschten Batteries-included-Framework deutlich näher, und es ist bereits ein ziemlich altes Projekt.

    • Rocket war eines der frühen Rust-Frameworks, das mit prozeduralen Makros eine gute Developer Experience durchgesetzt hat, scheint aber in vielen Teilen der Community deutlich an Popularität verloren zu haben.
      Sehr lange brauchte es für den Build nightly Rust, und für Leute, die ein Framework in Produktionsumgebungen einsetzen wollten, war das ein großes Ausschlusskriterium.
      Außerdem hing es etwa zwei Jahre lang im Release-Candidate-Status von 0.5.0 fest, und das jüngste stabile Release lag weit hinter anderen Rust-Webframeworks zurück. Es brauchte nightly und hatte noch keine Async-Unterstützung.
      Jetzt, wo die 0.5-Hürde genommen ist, mag es besser geworden sein, aber Rockets Entwicklungsgeschichte lässt einen im Vergleich zu Alternativen wie Axum zögern.
  • Eins gibt es: Poem[1]
    Der Autor erwähnt Flask, aber wenn man sich den Abschnitt „Was benötigt wird“ anschaut, ist schwer zu sagen, dass Flask diese Anforderungen erfüllt. Ich hasse Django wirklich, aber bei solchen Anforderungen ist Django meiner Ansicht nach dem, was der Autor beschreibt, am nächsten.
    In dieser Hinsicht ist auch Poem kein guter Kandidat. Insgesamt ist Poem FastAPI ziemlich ähnlich, und das ist eher als Lob gemeint. Ich habe fünf oder sechs Rust-Webframeworks ausprobiert, und bei den meisten muss man beim initialen Setup viel Boilerplate anfassen. Wenn man schnell Ergebnisse liefern will, ist das ein Problem, und in diesem Punkt passt Poem gut.
    actix hat eine ziemlich gute Performance, aber wenn man nicht auf Antwortzeiten unter 30 ms abzielt, gibt es von vornherein wenig Grund, sich actix anzuschauen. Wenn man etwas wie Pydantic braucht, gibt es auch Crates, die das in gewissem Umfang übernehmen: https://crates.io/crates/poem-openapi
    [1] https://github.com/poem-web/poem

    • Nicht nur Django, sondern auch Rails, ASP .NET Core und viele andere voll ausgestattete Batteries-included-Webframeworks fallen darunter.
      Der Kernpunkt ist, dass es ein „Framework“ ist.
  • F# ist ebenfalls einen Versuch wert.
    Es hat fast alle Typ-System-Spielereien, die man sich wünschen kann, und bringt die nötigen Werkzeuge und Komfortfunktionen mit. Der große Nachteil ist vielleicht, dass Async-Verarbeitung und Speicherverwaltung nicht so viel Zeit verschlingen wie bei Rust, sodass die Gefahr besteht, tatsächlich die geschäftlichen Anforderungen zu lösen.
    Trotzdem dürfte irgendein Teil des Umgangs mit Microsoft diese Lücke schon füllen.

    • Braucht F# nicht die .NET Virtual Machine? Die meisten Rust-Wähler, die ich kenne, mögen, dass es immer zu nativem Code kompiliert wird, die Vorhersagbarkeit und das Fehlen zufälliger Pausen durch Garbage Collection.
    • Ich überlege schon länger, ob ich F# ausprobieren soll.
      Wie ist es im Vergleich zu OCaml oder Haskell?
  • Möglicherweise unpopulärer Gedanke: Rust ist eine Systemsprache, und Webarbeit mit Rust zu machen ist verschwendete Mühe.
    Für diesen Zweck gibt es deutlich bessere Sprachen und Ökosysteme.

    • Gegenrede: Webservices mit Rust zu entwickeln ist so einfach wie mit Go oder Java, und dazu bekommt man ein hervorragendes Typsystem (Sum Types!), einen hervorragenden Paketmanager und sehr gute Performance.
      Wie in Java kann man auch in Rust Dependency Injection für das Teilen von Connection Pools verwenden, und threadbasierte Hintergrundjobs lassen sich ebenfalls sehr einfach schreiben.
      Google hat in einer aktuellen Präsentation gesagt, gemessen zu haben, dass Rust-Entwickler nicht weniger effizient oder weniger produktiv sind als Go-Entwickler [1].
      Rust ist eine großartige Sprache und muss keineswegs auf Systemprogrammierung beschränkt werden. Man kann damit viel mehr machen.
      [1] https://www.ardanlabs.com/news/2024/rust-at-google/
    • Ich benutze für Webserver immer C/C++.
      Es ist leichtgewichtig, man kann C/C++ und Low-Level-Code einfach und schnell aufrufen, und es gibt einem viel Kontrolle über das Networking. Ohne eine anwendungsspezifische Sprache wie PHP oder nginx/apache-Konfigurationsdateien lernen zu müssen, kann man fast alles auf eine allgemeine und intuitive Weise tun.
      Eine Rust-Alternative zu etwas wie libmicrohttpd wäre schön, und wenn es sie gäbe, würde ich sie wohl verwenden.
    • Ich stimme fast vollständig zu, möchte aber darauf hinweisen, dass die Schnittmenge von Systemprogrammierung und Webprogrammierung nicht leer ist.
      Dasselbe gilt für die Schnittmenge von Embedded-Programmierung und Webprogrammierung.
      Wenn Optionen wie Django, .Net oder Go möglich sind, ist Rust aber meist wahrscheinlich eine schlechte Wahl.
    • Es ist eine Investition in Energieeffizienz.
    • In Systemen, in denen Speicher oder CPU stärker eingeschränkt sind als üblich, ergibt es Sinn.
      Ein statisch kompiliertes Webframework kann leicht nur 1/10 bis 1/100 des Speichers/der CPU von etwas wie Rails, Django oder Flask verbrauchen.
  • Python hat Django, C# hat ASP .NET Core, Ruby hat Rails.
    Wenn man Rust in der Webentwicklung wirklich groß machen will, muss man eine voll ausgestattete Lösung bauen.
    Rocket kommt dem vielleicht am nächsten, ist aber nicht so batteries-included wie die oben genannten Frameworks.

  • Was der Autor sucht, ist die Rust-Version von ASP.NET Core, und daran ist nichts falsch.
    Manche Leute mögen Auswahl und Zusammenstecken, aber in vielen Umgebungen ist es viel produktiver, wenn einem die Auswahl bereits kuratiert wird.
    Reaktionen wie „Was, wenn ich ein anderes X will? Y könnte doch um Z % besser sein!“ sind häufig, übersehen aber, dass Integration an sich enormen Wert hat. Einzelne Bibliotheken mögen für sich genommen die besten sein, aber wenn sie nicht nahtlos zusammenspielen, können sie zu einem Müllhaufen werden.
    Der Grund, warum ich gern mit ASP.NET 8 programmiere, ist auch, dass ich mir überhaupt keine Gedanken machen muss, ob das Template-System gut mit Authentifizierung, Injection, Routing usw. zusammenspielt.

  • Keine Erwähnung von loco-rs, poem, rocket? Es gibt schon ziemlich viele Projekte, die auf eine Batteries-included-Erfahrung abzielen.
    Was solche Projekte von Frameworks wie leptos unterscheidet, ist eine anleitende CLI. Genau das mag ich auch an Symfony, und darin liegt für mich der „faule“ Teil.

  • Es gibt https://shuttle.rs
    Es ist nicht nur ein Framework, sondern auch ein Tool, das das Web-Boilerplate drumherum erzeugt; nach meinem Maßstab ist das also ausreichend lazy.

  • Dieser Artikel behandelt mehrere verschiedene Punkte auf einmal; idealerweise müsste man sie jeweils getrennt diskutieren.
    Wenn man Pattern Matching hat, braucht man nicht zwingend einen Router. Man kann die URL aufteilen und statische/dynamische Variablen nach Bedarf matchen.
    Authentifizierung baut man in jeder Sprache normalerweise entweder selbst oder nutzt SaaS wie Firebase/Auth0; es ist also nicht unbedingt ein Problem der Sprache oder des Frameworks.
    CSS/JS-Tools passen zu vielen Rust-Frontend-Frameworks wie Dominator nicht gut. Dominator ist nicht in JS, sondern in Rust geschrieben und hat einen eigenen Styling-Ansatz, etwa indem Styles an Signale gebunden werden und sich in Echtzeit ändern.
    Ich verstehe, was der Autor meint. Tatsächlich bin ich mehrfach herumgelaufen, um verschiedene Punkte aus dem Artikel zu lösen, und es war auch schmerzhaft. Zum Beispiel erledigt https://github.com/dakom/dominator-workers-fluent-auth viele der hier genannten Aufgaben auf einem Cloudflare-Workers-Framework und fügt zusätzlich die gewünschte Fluent-basierte Lokalisierung hinzu.
    Ein Batteries-included Full-Framework, das alles übernimmt, wäre schön, aber viele reale Projekte werden solche normativen Entscheidungen ändern und lieber selbst implementieren wollen. Rust ist auch im Frontend-Web ausreichend ausgereift, und wenn man nur weiß, wo man hinschauen muss, kann man mit wasm-bindgen usw. alles abdecken.

    • „Mit Pattern Matching braucht man keinen Router“ greift zu kurz.
      Ein Web-Framework bietet viel mehr, etwa URL-Weiterleitungen, Behandlung von abschließenden Slashes, Verwaltung von URLs mit Groß-/Kleinschreibung und komplexes Regex-Matching.
      „Authentifizierung baut man in jeder Sprache normalerweise selbst oder nutzt SaaS“ ist falsch. Django, Laravel, Rails und Sprachen mit Batteries included haben eine sehr gute Authentifizierungsverwaltung. Persönlich halte ich es für einen enormen Fehler, wenn 90 % der Organisationen Authentifizierung an externe Anbieter auslagern.
      Dass ein erfahrener Webentwickler ohne unnötige Komplexität an einem Tag direkt zehn grundlegende CRUDs hochziehen kann, ist für kleine Unternehmen ein wirklich großer Vorteil.
  • Würde im Großen und Ganzen dasselbe gelten, wenn sich dieser Artikel nicht auf Rust, sondern auf C++ konzentriert hätte?
    Es ist eine Systemsprache mit hoher Einstiegshürde und Compile-Zeiten, und von einer Sprache, die noch keine zehn Jahre breit genutzt wird, zu erwarten, bei der Zugänglichkeit mit etwas wie Rails zu konkurrieren, ist unrealistisch.