- 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アプリを簡単に作るために必要な機能を標準で含めることを目標としている
- ドキュメントは公式ドキュメントで提供されている
提供機能
- サーバーとリクエスト処理
- データとアプリケーション構造
- APIとジョブ処理
- 運用と開発ツール
- 環境別設定をサポートする
- ロギングとメトリクスを提供する
- CLIを含む
Hotwired Turboと移行支援
クイックスタート
- 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();
}
例とプロジェクトの状況
1件のコメント
Hacker Newsのコメント
リリースはかなり非現実的に感じられそうで、とにかくおめでとう。Railsで長くWeb MVCをやって学んだ最大のことは、フレームワークはモデル層のビジネスロジックを強く抑制すべきだということ。
データモデルには、Active Recordが言うコールバック、たとえば
afterCreateのようなフックは入れないほうがよいと思う。まだORMにはないがロードマップにあるなら、ないままのほうがよいと思う。ただしこれは、サービス、つまりビジネスロジック層を強く推奨する場合にだけうまく機能する。自分のRailsアプリの多くは、Interactorのようなgemでコマンド/サービスオブジェクトを構成している。
MVCだけで、したがってRailsの基本構成だけでは、サービス層の不在のせいで運用可能なアプリを書くのに理想的ではないと思う。それと、コミュニティ既存のORMやクエリビルダーを使わなかった理由も気になる。Rustはまだ1行も書いたことがないが、だんだん興味が湧いてきている。
サービスは、ほとんどがモデルからトリガーされる、より複雑で特定のコード片であるべきだと思う。薄いコントローラー、厚いモデルが、デバッグ・整理・発見可能性の面で最も良かったし、サービスを多用すると経験上スパゲティコードがたくさん生まれる。
純粋なオブジェクト指向の観点でも、モデルはエンティティを定義する基本オブジェクト。
Userは自分自身について知るべきことをすべて知っていて、他のエンティティとはメッセージでやり取りすべきだ。ただしコールバックについては同意する。コールバックは奇妙な副作用をたくさん生み、デバッグを本当に難しくする。
そうすることはできるが、どんな方法でエンティティが更新されうるのかを推論するのがかなり難しくなる。任意の数の手続きが更新でき、それぞれが別々のビジネスルールを持ちうるからだ。そこまで行くなら、手続きが直接データベースに書き込んで、モデルをなくしてしまってもよい。
ただ、20年以上開発してきて、カプセル化は利点ではなく負担だという結論に至ったし、データはそのデータに対して行われる操作と分離されるべきだと思う。これはデータ指向設計またはデータ指向プログラミングと呼ばれ、同じ結論に達したのは自分だけではない。
うまくスケールする別のモデリング手法もあり、関連記事もいくつかある。Basecampの人が書いた https://dev.37signals.com/vanilla-rails-is-plenty/ がある。
もちろんこれはかなりオブジェクト指向的なので、自分もそこまで好みではない。たとえばElixirのPhoenixフレームワークは、関連機能をまとめるためにコンテキストを使っていて、単純に言えばファサードと見なせる。
サービスが好きなら使えばよいが、MVCが本番運用に十分でないというのは少し的外れだと思う。重いビジネスプロセスをモデルコールバックで処理するのはよくないが、データを正しい形に整える小さな作業にはかなり向いている。
とくに、自分のプログラミング経験がフックを広範に使う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
全体として、データベースの型をRustの型に合わせる良い最初の試みではあったが、ORMはもっと柔軟で使いやすいべきだ。クエリを難しくするのではなく、もっと簡単に書けるようにすべきだから :)
テンプレートのほうは、自分だけの言語を作るのは30代以上のナードクラブへの通過儀礼に近い。ドラゴンブックは読んでいないが、学校でその授業はぜひ受けてみたかった。こういうものには常に複数の実装があるし、RailsのERBがやっていることをかなり近く再現するこの実装を使うのが正しいと感じた。
SREの観点からは、https://levkk.github.io/rwf/migrating-from-python/に関心を引かれた。一方では、これをやり遂げたのは本当にすごいが、安定性を見るSREの視点では心の中で悲鳴を上げることになる。
規模が大きくなると、これはCaddy、Nginx、Traefikのようなリバースプロキシが処理すべきだ。
安定したWSGIサーバーを書くことは可能で、スレッド数やvacuum、昔のphp-fpmのようにn回のリクエストごとに再起動するといった細部に少し注意すれば、それほど難しくない。基本的にはuwsgiが持つオプションの大半を実装すれば、正しい道にいると言える。RwfをGunicornの実行と比較可能にすることがロードマップに入っている。
名前の選び方が実に見事だ。検索結果の一番上に来る方法のひとつではある :P
真面目な話、よくできている。良いフレームワークを作るのは驚くほど大きな仕事で、人々が設計空間を探りながら新しいアイデアを試すのを見るのはいつでも良いものだ。
rwfより発音しやすそうだ。RustOnWeb.comも10ドルで買える :) ちょっと言ってみただけ。
「Railsを思い浮かべてほしい。Flaskではなく」という表現が気に入った。静的型付け言語にも、Rails/Djangoのような意見の強いフレームワークがもっと増えるか、もっと良くなる必要がある。
よくできている。https://www.arewewebyet.org/で紹介されるよう試してみる価値がありそうだ。
いいね! 最高の言語で作られたDjango/Railsだ。
提案すると、
async-traitはもう安定化されているはずなので、マクロはもはや不要かもしれないし、デフォルトでメトリクスとトレーシングを得られるようOpenTelemetry統合を追加すると良さそうだ。Linux向けにはjemallocも使うといい。tracingクレートの関数にOpenTelemetryタグを追加する予定だ。jemallocはRwfを使うバイナリアプリに追加できるので、ライブラリ依存関係として入れる必要はない。[1] https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-trait...
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がいちばん好きな言語だ。
バックエンドのRust作業のために、よく名前が挙がる候補をすべて評価し、小さなプロトタイプも作ってみた。今のところ、望むよりは低レベルではあるものの、全体としてはAxumが最善だという集団的な結論にしぶしぶ同意することになった。
他の候補はLocoとRocketだった。LocoはRailsに似すぎていたし、RocketはRustをもっと使うようになってからマクロが気になり始めた。
このフレームワークは、「バッテリー同梱だが過度に規定的ではない」という私の基準に完璧に合っているように見える。エコシステムにとって良い追加だ。