3 ポイント 投稿者 GN⁺ 2024-10-23 | 1件のコメント | WhatsAppで共有
  • Rwfは、RustでWebアプリケーションを構築するための総合フレームワークであり、古典的なMVCパターンをベースに、高速で安全なWebアプリを作るために必要な機能を標準搭載している
  • 基本機能には、HTTPサーバー、PostgreSQLクエリ用ORM、動的テンプレート、認証とユーザーセッション、ミドルウェア、バックグラウンドジョブとスケジュールジョブ、データベースマイグレーションが含まれる
  • JSONシリアライズをサポートする組み込みRESTフレームワーク、WebSockets、静的ファイルホスティング、環境別設定、ロギングとメトリクス、CLIも提供する
  • Hotwired Turboと緊密に統合されており、バックエンド主導のSPAを構築できるほか、Django/Flask移行用のWSGIサーバーとRails移行用のRackサーバーを提供する
  • 現在はベータ状態で初期導入ユーザーを募っており、ほとんどの機能は良好な状態で、ドキュメントも利用可能な水準だとしている

Rust向けMVC Webフレームワーク

  • Rwfは、RustでWebアプリケーションを構築するための総合フレームワーク
  • 古典的な**MVC(model-view-controller)**パターンで書かれている
  • 高速で安全なWebアプリを簡単に作るために必要な機能を標準で含めることを目標としている
  • ドキュメントは公式ドキュメントで提供されている

提供機能

  • サーバーとリクエスト処理
  • データとアプリケーション構造
    • PostgreSQLクエリを簡単に作成するための使いやすいORMを提供する
    • データベースマイグレーションをサポートする
    • Dynamic templatesを提供する
    • Authenticationと組み込みユーザーセッションを含む
  • APIとジョブ処理
  • 運用と開発ツール
    • 環境別設定をサポートする
    • ロギングとメトリクスを提供する
    • CLIを含む

Hotwired Turboと移行支援

  • Hotwired Turboと緊密に統合されており、backend-driven SPAsを構築できる
  • Django/Flaskアプリから移行するためのWSGI serverを提供する
  • Railsから移行するためのRack serverを提供する

クイックスタート

  • Rustバイナリアプリケーションを作成し、rwfを依存関係に追加して利用する
cargo add rwf
  • 基本アプリはrwf::prelude::*rwf::http::Serverを使ってコントローラーとルートを定義する
use rwf::prelude::*;
use rwf::http::Server;

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

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

例とプロジェクトの状況

  • 一般的なユースケースはexamplesで確認できる
  • Rwfは現在ベータ状態で、初期導入ユーザーを募っている
  • ほとんどの機能は良好な状態で、ドキュメントも利用可能な水準だとしている
  • コントリビューションは歓迎されており、ガイドはCONTRIBUTING、コード構造の案内はARCHITECTURE、希望機能の一覧はROADMAPにある

1件のコメント

 
GN⁺ 2024-10-23
Hacker Newsのコメント
  • リリースはかなり非現実的に感じられそうで、とにかくおめでとう。Railsで長くWeb MVCをやって学んだ最大のことは、フレームワークはモデル層のビジネスロジックを強く抑制すべきだということ。
    データモデルには、Active Recordが言うコールバック、たとえば afterCreate のようなフックは入れないほうがよいと思う。まだORMにはないがロードマップにあるなら、ないままのほうがよいと思う。
    ただしこれは、サービス、つまりビジネスロジック層を強く推奨する場合にだけうまく機能する。自分のRailsアプリの多くは、Interactorのようなgemでコマンド/サービスオブジェクトを構成している。
    MVCだけで、したがってRailsの基本構成だけでは、サービス層の不在のせいで運用可能なアプリを書くのに理想的ではないと思う。それと、コミュニティ既存のORMやクエリビルダーを使わなかった理由も気になる。Rustはまだ1行も書いたことがないが、だんだん興味が湧いてきている。

    • この見方がどこから来るのか気になる。自分の考えはまったく逆で、できるだけ多くのビジネスロジックはモデルにあるべきだと思う。
      サービスは、ほとんどがモデルからトリガーされる、より複雑で特定のコード片であるべきだと思う。薄いコントローラー、厚いモデルが、デバッグ・整理・発見可能性の面で最も良かったし、サービスを多用すると経験上スパゲティコードがたくさん生まれる。
      純粋なオブジェクト指向の観点でも、モデルはエンティティを定義する基本オブジェクト。User は自分自身について知るべきことをすべて知っていて、他のエンティティとはメッセージでやり取りすべきだ。
      ただしコールバックについては同意する。コールバックは奇妙な副作用をたくさん生み、デバッグを本当に難しくする。
    • ビジネスロジックがなければ、そもそもモデルとは何なのかわからない。構造体をモデルと呼び、手続きをサービスと呼ぶ構成を望んでいるように聞こえる。
      そうすることはできるが、どんな方法でエンティティが更新されうるのかを推論するのがかなり難しくなる。任意の数の手続きが更新でき、それぞれが別々のビジネスルールを持ちうるからだ。そこまで行くなら、手続きが直接データベースに書き込んで、モデルをなくしてしまってもよい。
    • モデルにビジネスロジックがあってはならないという点には同意する。Martin FowlerとRobert C. Martinはこうしたものを貧血ドメインモデルと呼び、昔のオブジェクト指向とパターン重視のエンタープライズ開発のやり方とは反対だ。
      ただ、20年以上開発してきて、カプセル化は利点ではなく負担だという結論に至ったし、データはそのデータに対して行われる操作と分離されるべきだと思う。これはデータ指向設計またはデータ指向プログラミングと呼ばれ、同じ結論に達したのは自分だけではない。
    • MVCだけでは本番レベルのアプリに不十分だというのは、かなり大きな主張だ。個人的にはサービスオブジェクトが嫌いで、あちこちに散らばって発見可能性を損なう。
      うまくスケールする別のモデリング手法もあり、関連記事もいくつかある。Basecampの人が書いた https://dev.37signals.com/vanilla-rails-is-plenty/ がある。
      もちろんこれはかなりオブジェクト指向的なので、自分もそこまで好みではない。たとえばElixirのPhoenixフレームワークは、関連機能をまとめるためにコンテキストを使っていて、単純に言えばファサードと見なせる。
      サービスが好きなら使えばよいが、MVCが本番運用に十分でないというのは少し的外れだと思う。重いビジネスプロセスをモデルコールバックで処理するのはよくないが、データを正しい形に整える小さな作業にはかなり向いている。
    • 興味深い。会社でPHP ORMを自作したのだが、Laravelのようなオープンソースライブラリの使用が禁じられていて、フックがとても有用だと感じた。
      とくに、自分のプログラミング経験がフックを広範に使うWordPress向けPHPから始まったので、そのバイアスがあるのかもしれない。
      自分が作ったものには、SQL定義に変換したり、見栄えよく整形したHTMLフォームを吐き出せたりするテーブル仕様がある。別個のコントローラーがすべてのDB接続とCRUD処理を担当し、必要なら他のテーブルとの制約を簡単に相互参照できる前後フックもある。
      かなりうまく動いているが、可能ならすぐにでもLaravelに乗り換えると思う。
  • RESTフレームワークなら、基本的にSwagger/OpenAPI定義の生成ができることを期待する。FastAPIのキラー機能の一つはそれだと思う。
    また、diesel.rsのような既存ORMと統合せずに自前でORMを作った理由や、人気のある既存テンプレートエンジンを選ばずに独自のテンプレート言語を作った理由もよくわからない。
    それ以外は、プロジェクトは本当に面白そうで、今後も追いかけたい。
    [0] https://diesel.rs/
    [1] https://crates.io/categories/template-engine

    • 数年前にDieselを使ってみたが、自分にはあまりにもRustっぽく感じられた。スキーマを二重に定義しなければならず、挿入と取得で同じ構造体を使えなかったので、実質的には三重に定義するようなものだった。
      全体として、データベースの型をRustの型に合わせる良い最初の試みではあったが、ORMはもっと柔軟で使いやすいべきだ。クエリを難しくするのではなく、もっと簡単に書けるようにすべきだから :)
      テンプレートのほうは、自分だけの言語を作るのは30代以上のナードクラブへの通過儀礼に近い。ドラゴンブックは読んでいないが、学校でその授業はぜひ受けてみたかった。こういうものには常に複数の実装があるし、RailsのERBがやっていることをかなり近く再現するこの実装を使うのが正しいと感じた。
    • https://github.com/poem-web/poem は、Swagger定義を標準提供するRustフレームワークだ。
    • 逆向きに動く似たフレームワークを知っている人がいるか気になる。つまり、OpenAPI定義を単一の信頼できる情報源として維持し、サーバーがそれに従っているか検証する方式のこと。
    • サーバー側でOpenAPIを生成するのは100%キラー機能だと思う。自分たちはDropshotでうまくやっている。
    • 自分もRESTフレームワークならSwagger/OpenAPI定義を標準で生成することを期待する。ただ、自分の理解では、これはWeb API構築用のフレームワークではなく、HTMLを返すMVCフレームワークだ。
  • SREの観点からは、https://levkk.github.io/rwf/migrating-from-python/に関心を引かれた。一方では、これをやり遂げたのは本当にすごいが、安定性を見るSREの視点では心の中で悲鳴を上げることになる。
    規模が大きくなると、これはCaddy、Nginx、Traefikのようなリバースプロキシが処理すべきだ。

    • 私も同じことを考えたが、この方式ならアプリケーションエンジニアがあちこち行き来せずに変更をローカルでテストできる。結局は昔からあるモノリス対マイクロサービス論争に戻ってくる。
      安定したWSGIサーバーを書くことは可能で、スレッド数やvacuum、昔のphp-fpmのようにn回のリクエストごとに再起動するといった細部に少し注意すれば、それほど難しくない。基本的にはuwsgiが持つオプションの大半を実装すれば、正しい道にいると言える。RwfをGunicornの実行と比較可能にすることがロードマップに入っている。
    • 筆者は、技術に明るい読者であればWSGIサーバーの前にあるリバースプロキシの必要性をわざわざ説明しなくても分かる、と考えたのだと思う。
  • 名前の選び方が実に見事だ。検索結果の一番上に来る方法のひとつではある :P
    真面目な話、よくできている。良いフレームワークを作るのは驚くほど大きな仕事で、人々が設計空間を探りながら新しいアイデアを試すのを見るのはいつでも良いものだ。

    • Rustプロジェクトはこういう広すぎて一般的で、自己顕示的な名前を選ぶ傾向があるが、正直大きな失敗だと思う。Crates.ioは、もっともらしい名前を先取りしたまま放置されたプロジェクトの墓場になるだろう。
    • 「Row」も良い名前だし、rwfより発音しやすそうだ。
      RustOnWeb.comも10ドルで買える :) ちょっと言ってみただけ。
  • 「Railsを思い浮かべてほしい。Flaskではなく」という表現が気に入った。静的型付け言語にも、Rails/Djangoのような意見の強いフレームワークがもっと増えるか、もっと良くなる必要がある。

  • よくできている。https://www.arewewebyet.org/で紹介されるよう試してみる価値がありそうだ。

    • このページにloco.rsがないのはかなり意外だ。Rustフレームワークの中では最も「Rails」に近く見えるのに載っていない。
  • いいね! 最高の言語で作られたDjango/Railsだ。
    提案すると、async-traitはもう安定化されているはずなので、マクロはもはや不要かもしれないし、デフォルトでメトリクスとトレーシングを得られるようOpenTelemetry統合を追加すると良さそうだ。Linux向けにはjemallocも使うといい。

    • ありがとう。標準の非同期トレイトを使おうとしたが、Rwfが広範に使っている動的ディスパッチをサポートしていない。
      tracingクレートの関数にOpenTelemetryタグを追加する予定だ。jemallocはRwfを使うバイナリアプリに追加できるので、ライブラリ依存関係として入れる必要はない。
      [1] https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-trait...
    • Linux向けにjemallocを使うべき理由が気になる。あるいは、なぜ他の対象では必要ないのかも気になる。
  • Rustを学ぼうとしたが、最初のうちに諦めた。C#、C/C++、Java、Pythonから来たので、Rustは奇妙に感じられた。
    私を挫折させたのは奇妙さそのものではなく、C#、Java、Pythonのような言語に比べてひとつの作業を終える速さが遅いことだった。
    最近は主にWeb開発をしているので、使いやすさと生産性が最優先だ。Rustはスループットや速度で少し優れているかもしれないが、最近のWebフレームワークのベンチマークを見ると、C#やJavaもこの点ではかなり健闘している。
    これをRust批判や、MVCフレームワークをゼロから作り上げた大きな成果を貶める発言として受け取らないでほしい。どちらかといえば「仕事に合った適切な道具」という話だ。

    • 言いたいことは完全に分かる。私を含め、多くの人が最初は似たような経験をしている。
      学習曲線を乗り越えるには強い動機が必要だ。その言語を使わなければならないとか、型システムと安全性の利点に惹かれるとか、自分なりの具体的な理由が必要になる。
      そうした動機がないなら、それでまったく問題ない。私も最初はなかったので、初期の学習の試みは長く続かなかった。多くの人が感じるように、RustはJavaやPythonより仕事を終えるのに時間がかかり、前もってより多く考える必要がある。特定の状況ではその価値があるが、そのトレードオフをなぜ受け入れるのかが明確でないなら、続ける強い理由はない。
  • 最近、webpackのJSローダーを捨てて50倍速いRustローダーを使うようになって、私もRustに夢中になった。Rustは性能向上の効果が大きく、今ではC++とRustがいちばん好きな言語だ。

    • おお、webpackをやめて何を使うようになったのか共有してもらえる?
  • バックエンドのRust作業のために、よく名前が挙がる候補をすべて評価し、小さなプロトタイプも作ってみた。今のところ、望むよりは低レベルではあるものの、全体としてはAxumが最善だという集団的な結論にしぶしぶ同意することになった。
    他の候補はLocoとRocketだった。LocoはRailsに似すぎていたし、RocketはRustをもっと使うようになってからマクロが気になり始めた。
    このフレームワークは、「バッテリー同梱だが過度に規定的ではない」という私の基準に完璧に合っているように見える。エコシステムにとって良い追加だ。

    • Actixはどうだろう? 記憶では、以前HNでActixとAxumに関する議論があった。