3 points par GN⁺ 2024-10-23 | 1 commentaires | Partager sur WhatsApp
  • Rwf est un framework complet pour créer des applications web en Rust, basé sur le modèle classique MVC, et fournit par défaut les fonctionnalités nécessaires pour construire des apps web rapides et sûres
  • Les fonctionnalités de base incluent un serveur HTTP, un ORM pour les requêtes PostgreSQL, des templates dynamiques, l’authentification et les sessions utilisateur, les middlewares, les tâches en arrière-plan et planifiées, ainsi que les migrations de base de données
  • Il propose aussi un framework REST intégré avec prise en charge de la sérialisation JSON, WebSockets, l’hébergement de fichiers statiques, la configuration par environnement, la journalisation et les métriques, ainsi qu’une CLI
  • Il s’intègre étroitement à Hotwired Turbo pour créer des SPA pilotées par le backend, et fournit un serveur WSGI pour migrer depuis Django/Flask ainsi qu’un serveur Rack pour migrer depuis Rails
  • Actuellement en bêta, le projet recherche des early adopters ; il indique que la plupart des fonctionnalités sont en bon état et que la documentation est utilisable

Framework web MVC pour Rust

  • Rwf est un framework complet pour construire des applications web en Rust
  • Il est écrit selon le modèle classique MVC(model-view-controller)
  • Son objectif est d’inclure par défaut les fonctionnalités nécessaires pour créer facilement des apps web rapides et sûres
  • La documentation est disponible dans la documentation officielle

Fonctionnalités proposées

  • Serveur et traitement des requêtes
  • Données et structure applicative
    • Fournit un ORM convivial pour créer facilement des requêtes PostgreSQL
    • Prend en charge les migrations de base de données
    • Fournit des Dynamic templates
    • Inclut l’Authentication et des sessions utilisateur intégrées
  • API et traitement des tâches
  • Outils d’exploitation et de développement
    • Prend en charge la configuration par environnement
    • Fournit la journalisation et les métriques
    • Inclut une CLI

Prise en charge de Hotwired Turbo et des migrations

Démarrage rapide

  • Créez une application binaire Rust et ajoutez rwf comme dépendance pour l’utiliser
cargo add rwf
  • Une app de base utilise rwf::prelude::* et rwf::http::Server pour définir les contrôleurs et les routes
use rwf::prelude::*;
use rwf::http::Server;

#[controller]
async fn index() -> Response {
    Response::new().html("Welcome to Rwf!

")
}

#[tokio::main]
async fn main() {
    Server::new(vec![
        route!("/" => index),
    ])
    .launch()
    .await
    .unwrap();
}

Exemples et état du projet

  • Les cas d’usage courants sont disponibles dans les examples
  • Rwf est actuellement en bêta et recherche des early adopters
  • Le projet indique que la plupart des fonctionnalités sont en bon état et que la documentation est utilisable
  • Les contributions sont les bienvenues ; le guide se trouve dans CONTRIBUTING, la présentation de la structure du code dans ARCHITECTURE, et la liste des fonctionnalités souhaitées dans ROADMAP

1 commentaires

 
GN⁺ 2024-10-23
Commentaires sur Hacker News
  • Le lancement semble assez irréel, félicitations. La plus grande leçon que j’ai apprise en faisant du MVC web avec Rails pendant longtemps, c’est qu’un framework doit fortement décourager la logique métier dans la couche modèle
    Je pense qu’il vaut mieux éviter de mettre dans le modèle de données des callbacks Active Record, par exemple des hooks comme afterCreate. Même si ce n’est pas encore dans l’ORM mais que c’est sur la feuille de route, je pense qu’il vaudrait mieux ne pas l’ajouter
    Cela dit, ça ne fonctionne vraiment que si l’on encourage fortement une couche service, c’est-à-dire une couche de logique métier. Dans la plupart de mes apps Rails, j’utilise des gems comme Interactor pour construire des objets commande/service
    À mon avis, avec le seul MVC, et donc avec la configuration par défaut de Rails, on n’est pas dans une situation idéale pour écrire une application exploitable en production, à cause de l’absence de couche service. Et je me demande aussi pourquoi ne pas avoir utilisé les ORM ou query builders existants de la communauté. Je n’ai pas encore écrit une seule ligne de Rust, mais ça m’intrigue de plus en plus

    • Je me demande d’où vient ce point de vue. Pour moi, c’est exactement l’inverse : autant que possible, la logique métier doit vivre dans le modèle
      Les services devraient presque tous être des fragments de code plus complexes et plus spécifiques déclenchés depuis les modèles. Des contrôleurs fins et des modèles épais ont été ce qu’il y avait de mieux pour le débogage, l’organisation et la découvrabilité, alors que l’usage intensif de services a souvent produit, dans mon expérience, beaucoup de code spaghetti
      Même d’un point de vue purement orienté objet, le modèle est l’objet de base qui définit l’entité. User doit tout savoir de ce qu’il doit savoir sur lui-même, et communiquer avec les autres entités par messages
      En revanche, je suis d’accord au sujet des callbacks. Les callbacks créent beaucoup d’effets de bord bizarres et rendent vraiment le débogage difficile
    • Je ne vois pas bien ce qu’est un modèle s’il n’y a pas de logique métier dedans. On dirait que vous voulez une structure où l’on appelle les structs des modèles et les procédures des services
      C’est possible, mais cela rend assez difficile de raisonner sur les manières dont une entité peut être mise à jour. N’importe quel nombre de procédures peut la modifier, chacune avec ses propres règles métier. À ce compte-là, autant laisser les procédures écrire directement en base de données et supprimer les modèles
    • Je suis d’accord sur le fait qu’il ne devrait pas y avoir de logique métier dans les modèles. Martin Fowler et Robert C. Martin appellent cela un modèle de domaine anémique, et c’est l’inverse de l’ancienne approche de développement d’entreprise lourde en objet et en patterns
      Mais après plus de 20 ans de développement, j’en suis arrivé à la conclusion que l’encapsulation est une charge, pas une fonctionnalité, et que les données doivent être séparées des opérations effectuées sur elles. On appelle cela la conception orientée données ou la programmation orientée données, et je ne suis clairement pas le seul à être arrivé à cette conclusion
    • Dire que le MVC seul ne suffit pas pour des applications de niveau production, c’est une affirmation assez forte. Personnellement, je n’aime pas les objets service, parce qu’ils sont dispersés partout et nuisent à la découvrabilité
      Il existe d’autres approches de modélisation qui passent bien à l’échelle, et il y a quelques articles à ce sujet. Il y en a un écrit par quelqu’un de chez Basecamp : https://dev.37signals.com/vanilla-rails-is-plenty/
      Bien sûr, c’est très orienté objet, donc je n’en suis pas non plus un grand fan. Par exemple, le framework Phoenix d’Elixir utilise des contexts pour regrouper les fonctionnalités liées, ce qu’on peut voir, en simplifiant, comme des façades
      Si vous aimez les services, vous pouvez en utiliser, mais dire que le MVC ne suffit pas pour de la production me semble un peu à côté de la plaque. Traiter de lourds processus métier dans des callbacks de modèles n’est pas une bonne idée, mais pour de petites opérations qui remettent les données dans la bonne forme, c’est tout à fait correct
    • Intéressant. J’ai créé un ORM PHP en interne dans mon entreprise, parce que l’usage de bibliothèques open source comme Laravel y était interdit, et j’ai trouvé les hooks très utiles
      Il est possible que je sois biaisé, surtout parce que mon expérience en programmation a commencé avec du PHP pour WordPress, où les hooks sont omniprésents
      Ce que j’ai construit dispose de spécifications de tables capables de se convertir en définitions SQL ou de produire des formulaires HTML joliment formatés. Un contrôleur séparé gère toutes les connexions à la base et les opérations CRUD, et il y a des hooks avant/après qui permettent, si nécessaire, de référencer facilement les contraintes d’autres tables
      Ça fonctionne plutôt bien, mais si je le pouvais, je passerais immédiatement à Laravel
  • Pour un framework REST, je m’attendrais par défaut à la génération de définitions Swagger/OpenAPI. Pour moi, c’est l’une des fonctionnalités décisives de FastAPI
    Je comprends aussi mal pourquoi ils ont créé leur propre ORM au lieu de s’intégrer à un ORM existant comme diesel.rs, et pourquoi ils ont créé leur propre langage de templates au lieu de choisir un moteur de templates populaire existant
    À part ça, le projet a l’air vraiment intéressant et je vais continuer à le suivre
    [0] https://diesel.rs/
    [1] https://crates.io/categories/template-engine

    • J’ai essayé Diesel il y a quelques années, et pour moi c’était trop rustique au sens Rust. Il fallait définir le schéma deux fois, et on ne pouvait pas utiliser la même struct pour l’insertion et la lecture, donc en pratique on la définissait presque trois fois
      Globalement, c’était une bonne première tentative pour faire correspondre les types de base de données aux types Rust, mais un ORM doit être plus flexible et plus agréable à utiliser. Il doit rendre les requêtes plus faciles à écrire, pas plus difficiles :)
      Pour les templates, créer son propre langage tient presque du rite de passage dans le club des nerds de plus de 30 ans. Je n’ai pas lu le Dragon Book, mais j’ai toujours voulu suivre ce cours à l’école. Il existe toujours plusieurs implémentations pour une même idée, et j’ai eu le sentiment qu’il était juste d’utiliser une implémentation qui imite d’assez près ce que fait ERB dans Rails
    • https://github.com/poem-web/poem est un framework Rust qui fournit des définitions Swagger prêtes à l’emploi
    • Je me demande s’il existe un framework comparable qui fonctionne en sens inverse : garder la définition OpenAPI comme source de vérité et vérifier que le serveur s’y conforme
    • Pour moi, générer OpenAPI depuis le serveur est à 100 % une fonctionnalité décisive. Nous l’utilisons avec Dropshot et ça se passe très bien
    • Moi aussi, pour un framework REST, je m’attendrais à une génération native de définitions Swagger/OpenAPI. Mais si j’ai bien compris, ce n’est pas un framework pour construire des API web, c’est un framework MVC qui renvoie du HTML
  • Du point de vue d’un SRE, https://levkk.github.io/rwf/migrating-from-python/ a attiré mon attention. D’un côté, ce qu’ils ont réussi à faire est vraiment impressionnant, mais du point de vue SRE, centré sur la stabilité, ça donne envie de crier intérieurement
    À grande échelle, c’est le genre de chose qui devrait être géré par un reverse proxy comme Caddy, Nginx ou Traefik

    • J’ai eu la même réaction, mais avec cette approche, un ingénieur applicatif peut tester les changements en local sans faire des allers-retours. Au final, on retombe sur le vieux débat monolithe contre microservices
      Il est possible d’écrire un serveur WSGI stable, et ce n’est pas si difficile si on fait un minimum attention à des détails comme le nombre de threads, le vacuum, ou un redémarrage tous les n requêtes comme l’ancien php-fpm. En gros, si on implémente la plupart des options de uwsgi, on est sur la bonne voie. Rendre Rwf comparable à une exécution avec Gunicorn fait partie de la roadmap
    • Je pense que l’auteur a supposé qu’avec un lectorat technique, il n’était pas nécessaire d’expliquer en détail pourquoi il faut un reverse proxy devant le serveur WSGI
  • Le choix du nom est vraiment remarquable. C’est une façon d’arriver tout en haut des résultats de recherche :P
    Plus sérieusement, c’est du beau travail. Créer un bon framework représente une quantité de travail étonnamment importante, et c’est toujours agréable de voir des gens explorer l’espace de conception et essayer de nouvelles idées

    • Les projets Rust ont tendance à choisir ce genre de noms larges, génériques et un peu tape-à-l’œil, et honnêtement je pense que c’est une grosse erreur. Crates.io risque de devenir un cimetière de projets abandonnés ayant accaparé des noms plausibles
    • « Row » serait aussi un bon nom, et probablement plus facile à prononcer que rwf
      RustOnWeb.com est aussi disponible pour 10 $ :) je dis ça comme ça
  • J’aime bien la formule « pensez Rails, pas Flask ». Les langages à typage statique auraient besoin de plus de frameworks d’opinion à la Rails/Django, ou de meilleurs frameworks de ce type

  • C’est bien fait. Ça vaudrait le coup d’essayer de le faire référencer sur https://www.arewewebyet.org/

    • Je suis assez surpris que loco.rs n’apparaisse pas sur cette page. C’est pourtant probablement le framework Rust le plus proche de « Rails »
  • Sympa ! Un Django/Rails écrit dans le meilleur des langages
    À titre de suggestion, async-trait est maintenant peut-être stabilisé, donc le macro n’est peut-être plus nécessaire, et ce serait bien d’ajouter une intégration OpenTelemetry pour avoir par défaut des métriques et du tracing. jemalloc serait aussi une bonne idée pour Linux

    • Merci. J’ai essayé d’utiliser les traits async standard, mais ils ne prennent pas en charge le dispatch dynamique dont Rwf fait largement usage
      Je compte ajouter des tags OpenTelemetry aux fonctions du crate tracing. Pour jemalloc, il peut être ajouté aux applications binaires qui utilisent Rwf, sans qu’il soit nécessaire de l’inclure comme dépendance de la bibliothèque
      [1] https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-trait...
    • Je serais curieux de savoir pourquoi il faudrait utiliser jemalloc sur Linux, ou pourquoi ce ne serait pas nécessaire sur d’autres cibles
  • J’ai essayé d’apprendre Rust, mais j’ai abandonné assez tôt. En venant de C#, C/C++, Java et Python, Rust m’a paru étrange
    Ce n’est pas l’étrangeté en elle-même qui m’a fait renoncer, mais le fait que la vitesse d’exécution d’une tâche y soit plus lente que dans des langages comme C#, Java ou Python
    Ces temps-ci, je fais surtout du développement web, donc la facilité d’usage et la productivité passent avant tout. Rust est peut-être un peu meilleur en débit et en vitesse, mais quand on regarde les benchmarks récents de frameworks web, C# et Java s’en sortent eux aussi très bien sur ce point
    Je ne voudrais pas que cela soit lu comme une critique de Rust ou comme une manière de minimiser le grand accomplissement que représente la création d’un framework MVC from scratch. C’est plutôt dans l’esprit du « bon outil pour le bon travail »

    • Je comprends parfaitement ce que tu veux dire. Beaucoup de gens, moi y compris, ont eu une expérience similaire au début
      Il faut une forte motivation pour franchir la courbe d’apprentissage. Il faut avoir une raison précise : devoir utiliser le langage, être attiré par les avantages de son système de types et de sa sécurité, ou toute autre raison personnelle concrète
      Sans cette motivation, il n’y a vraiment aucun problème. Moi non plus, je ne l’avais pas au départ, et c’est pour ça que mes premières tentatives d’apprentissage ne sont pas allées bien loin. Comme beaucoup de gens l’ont constaté, Rust demande plus de temps que Java ou Python pour faire avancer les choses, et oblige à réfléchir davantage en amont. Dans certaines situations, cela en vaut la peine, mais si on n’a pas une idée claire de la raison pour laquelle on accepte ce compromis, il n’y a pas de raison forte de persévérer
  • J’ai moi aussi commencé à aimer Rust récemment après avoir abandonné le loader JS de webpack pour un loader Rust 50 fois plus rapide. Rust apporte des gains de performance très visibles, et aujourd’hui C++ et Rust sont mes langages préférés

    • Oh, tu pourrais partager par quoi tu as remplacé webpack ?
  • J’ai évalué tous les candidats généralement cités pour du backend Rust et j’ai même réalisé de petits prototypes. Jusqu’à présent, bien que ce soit plus bas niveau que ce que je souhaiterais, j’en suis venu à accepter à contrecœur la conclusion collective selon laquelle Axum est globalement le meilleur choix
    Les autres candidats étaient Loco et Rocket. Loco ressemblait trop à Rails, et Rocket a commencé à me gêner à cause de ses macros à mesure que j’utilisais davantage Rust
    Ce framework semble correspondre parfaitement à mon critère de « batteries incluses, sans être trop prescriptif ». C’est un bon ajout à l’écosystème

    • Et Actix ? Si je me souviens bien, il y a déjà eu des discussions sur HN à propos d’Actix et d’Axum