🪄

Ruby on Railsにはない一般攻撃魔法

2024/10/01に公開

他言語のフレームワークとRailsを比べてみる

Railsにはたくさんゾルトラークがある

葬送のフリーレンという作品にはゾルトラークという魔法が出てきます。当初はその強力性から稀有な魔法と認識されていたものの、解析や研究が進んだ結果誰もが使える魔法となり一般攻撃魔法と認識されるようになりました。

Ruby on Railsというフレームワークも同様にファイルアップロードのActive Storage、複数データベース接続など従来はgemで実現していたものの一部が組み込み化され一般攻撃魔法になっています。

コアが大きくなったのでとあるバージョンから別ライブラリーに切り出しますというライブラリー、フレームワークもあるので組み込み機能が肥大化していくことは必ずしも善ではないのですが、メンテされる範囲で機能が増えていくのはいいことでしょう。

一方で他言語のフレームワークにはあるけれどRailsにはない機能もあり、他言語の一般攻撃魔法をまとめることでどうよりRailsが進化できるかを論じてみたいと思います。

Djangoの機械学習との親和性

DjangoはPythonのフレームワークでMVCフレームワークでなくMVT(Model, View, Template)フレームワークを標榜しています。

DjangoにはDjango ORMもあるのですが、PythonのDevelopers Surveyの結果で言うとPython全体ではSQLAlchemyに少し負けています。ここはActiveRecordほぼ一強のRuby界隈と違う部分。

Python界隈にRubyが負けている部分があるとすれば機械学習ライブラリーとの親和性でしょう。Red Data Toolsというデータ処理をRubyで行うライブラリー群もありますが、機械学習ライブラリーはC++またはPythonのみをサポートという場合もままあります。AIブームの中、Web系と機械学習系両方のサーバーを両方Pythonで書こうは一つの合理性ですかね。

一方でDjango Channelsがメンテナ1人で開発停止を訴えた時もあり、Pythonは用途がWebに特化していないので一番人気のDjangoでもフレームワークを維持するのは大変な印象。

Django特有なところで言うと、ディレクトリ構造がRailsより少しモジュール性を持っている点やDjango Adminという組み込み管理画面がある点、Railsでもbasic sessions generatorは足されましたがdjango.contrib.auth.modelsというユーザーモデルがあるのは特徴です。

個人的には部分インデックスはActiveRecordにあっても良さそうに思っています。

LaravelのObject Document Mapper

LaravelはPHPのフレームワークでSymfonyという別のフレームワークの上にのっています。Laravel9は元々LTSだったのですがSymfony側がリリースされたのでLTSでなくなるなどこの依存のせいでリリースコントロールが難しくなっている部分はあります。

一方でElixirのPhoenix LiveViewに影響されたHotwireがRubyにあるようにLivewireというものもあり、技術トレンドのキャッチアップは比較的速い印象。Rails 7.1のDockerfile自動生成よりLaravel Sailが出たのは前ですね。

RailsはAPIモードはあるもののRails自体の分解はそれほどできないですが、Laravelは各機能が割合独立しています。PHPのカンファレンスの発表を見てもそれによってLaravel風の書き方に統一されないという人もいればつまみ食いできていいという人もおりここは諸説ある部分。

ActiveRecordはORMとしては強力ですが、RailsはベクターDB、ドキュメントDBのMapperについては提供していません。LaravelにはLaravel Scoutという全文検索をラッパーした機能がありそこは優れている部分でしょうか。

LaravelにはFormRequestというControllerとは別に認可と検証をする機構があり、PORO(Plain Old Ruby Object)やActive ModelによるFormObjectでも書ける部分ですが、レールがひかれているのは魅力的です。

NestJSのDTO

NestJSはTypeScriptのフレームワークでORMと密結合していないばかりかベースのフレームワークがExpressかFastifyか選べるようになっています。一方でExpress、Fastifyで書き方が変わる部分もあり、組み合わせが多いので検索した時に自分と同じパターンが出てこない時はあるかもしれない。

ORMはTypeORMかPrismaの採用が多い印象。TypeORMの型安全性が低いパフォーマンスが低いという人もいればPrismaは破壊的変更が多すぎる、厳密にはORMより低レベルという人もおり一長一短。ただしどちらも進化が速いので検索して出てきた問題はもう解決しているかもしれない。

TypeORMは木構造をサポートしている、Prismaは組み込みのSQL Clientがついてくるのが推しポイント。

Sails.jsなどの既存のJavaScriptフレームワークがイマイチTypeScript化できないボトルネックにSQLの型推定があると思っており、AndroidのRoomなどでもそうだが、SQLの処理をある程度プロシージャ化して定義する必要がある(あった)。Prismaの新機能でTypedSQLというものがあり期待しています。

DTOというController前のvalidation層を置くのが一つのパターンになっており、この点はLaravelのFormRequestにも似ている。ActiveRecordのvalidationのうち、DBの値を見ないといけないものと、見なくてもわかるバリデーションを分けて後者についてはControllerに到達する前に見ると見通しがよくなることもあるかもしれないし強制されると複雑になるだけかもしれない。

RailsでもJSON Schemaでバリデーションかけている会社はありますね。

Pythonのバリデーション定義から フロントエンドTypeScriptのコード生成という取り組みもある。言語によって"型"ができることには違いがあるが"型"ができることはモデルのバリデーションから切り出しcontroller前のバリデーションとフロントエンドのバリデーションをwrite onceで書けるようにしたいというのは人類皆一度は考える部分。

Next.jsのCDN親和性

Next.jsはTypeScriptのフレームワークで、他のフルスタックのフレームワークと違いBFF(backend for frontend)の前段に特化しているというかReactにルーティングを足したような軽いフレームワーク。

PaaSがVercelしかできない機能もあると言われがちだが、Client-Side Rendering (CSR)、Server-Side Rendering (SSR)、Static-Site Generation (SSG)、Incremental Static Regeneration (ISR)などビルドやデリバリーのストラテジーが選べるのは魅力的。

Incremental Static Regenerationは普段は静的に返し特定の期間が経つとAPIからフェッチして更新を行う機構で便利です。一方で複数サーバーが同時にキャッシュの再取得を行うことで急リクエストが来て捌けきれなくなるdog pile effectという現象もあり、フロントエンドにとって夢の機構はバックエンドにとっては悪夢かもしれません。

DevOpsという言葉も一般化して開発と運用は一体化したが、意外とCDNの設定はインフラが担当だったり開発と分かれていることはまだある印象。

例えばconfig/routes.rbに

get 'pages/:id', :to => 'pages#show', :rendering => :isr

と書くとvarnish(キャッシュサーバー)の設定がエクスポートできるようになると面白いと思う時はあります。

Goのマイクロサービス親和性

Goのおすすめのフレームワークはnet/httpという程度にはフレームワークがあんまりないのがGo界隈。主にマイクロサービスでgRPC通信構成で使われることが多い。

後方互換性の確保に心血注いでおり、壊れにくいようになっているのは魅力的。methodが実際のレスポンスとerrorオブジェクトの2値返しが慣例となっており、例外を吐くこともあるRailsの開発とは思想が違います。

Googleが出したService Weaverというモノリスとマイクロサービス両対応のフレームワークがあり、それもヒントになるかもしれません。

Railsでのマイクロサービスは複数プロセスでRailsを立ち上げるとメモリの消費量がえぐかったりするので、例えば3つのRailsをmonorepoで管理して、本番にはないダミーのRailsに3つのRailsをRailsエンジンとしてマウントすると一つのRailsとして認識して、内部通信のHTTP callはGET https://service2.example.com/books/1get_service_2_example_com_books(1)に開発中だけ自動変換してくれるようなgemがあるとモジュラーモノリスからマイクロサービスへの移行が捗りそうと思う時はあります。

Play FrameworkのActor Model / Springのパフォーマンス

Play FrameworkはJava/Scalaのために作られたフレームワークです。Actor Modelというパラダイムに準じたフレームワークです。

LightbendのAkkaがオープンスースでなくなったため2でAkkaだったものを3でフォークしたApache Pekkoに移行したなど少しゴタゴタはあります。

.NETでもAkka.NETなどがあり、エンタープライズだとこういった機構が必要になることはありますが、RailsのOne Person Frameworkとは思想上真反対にいるユースケースだとも思います。

JavaだとSpring (Boot)が人気ですが、Ruby製のMastodonをJavaで置き換えたら100倍速になったという主張もあり、通常のWebサービスでボトルネックが本当に言語になるかは議論ポイントですが、Rubyが年々高速化しているとはいえパフォーマンスが必要なケースではJavaには負けると思います。

アーキテクチャの本はJavaベースのものが多いのですが、packwerkと似たようなライブラリーにArchUnitがあります。Spring Modulithというモジュラーモノリスのライブラリーもあり、アーキテクチャ関係のライブラリーはJavaは豊富です。

Ktorのinternal

KtorはKotlinのフレームワークです。Kotlin MultiplatformによりiOSでもKotlinとの共通コードが増えるケースがあり、その場合サーバーサイドもKotlinにすれば言語が割合揃うという合理性があります。

同様にFlutterを採用している企業でDartバックエンドのRiverpod、ゲームクライアントをC#で開発している企業でバックエンドをASP.NET MVC、ReactNative(Expo)の会社でTypeScriptバックエンドにするのは一つの合理性です。

現状Rubyでモバイルアプリ開発やゲーム開発は残念ながら人気で負けるのでその点は不利です。

Kotlinにはinternalというモジュール外非公開の構文があり、モジュラーモノリスを実現する上ではRubyよりというかオートローダーがほぼ強制で効いてるRailsより優位性があります。

Railsのメリットやデメリットについて語られるときにActiveRecordが槍玉に上がることが多いんですが、意外とORMは他言語でもありユニーク製はそこまで高くありません。同じスクリプト言語のPHPやPythonのフレームワークでもインポート文は頻繁に出てくるのでRailsをRailsたらしめているのは意外とオートローダー(Zeitwerk)の部分であり、インポート文を書かなくてもいいフレームワークがRailsの特徴だったりします。

例えばJavaScriptならdependency-cruiserなど依存を可視化するライブラリーがあると思うのですが、このオートローダー頼りの部分はVim/Emacsでも開発できるという利点はあるのですが、大規模化しモジュラーモノリスなどを考える上で静的解析がしづらい部分はあります。

rbsなど型定義を外部ファイルにするのが今のRubyの方向性ですが、本来あるはずだったrequire文はある程度定数などからわかるはずで、インポート文相当を静的解析用に外部ファイルに切り出す枠組みがあると静的解析上便利と感じる時はあります。

RustのWebAssemblyとの親和性

Rustは安全性の高い言語ですが、Web開発での採用例はまだ少なく成長中といった感じで、実際人気のフレームワークactix-webの作者がプロジェクト終了を宣言したこともありました。

RustはFigmaでも採用され、リアルタイム編集機能でパフォーマンスが改善したそうでそういった性能を要求されるケースでは光りますね。

mviyなんかでも採用されている点、WebAssemblyとの親和性が高い点からブラウザで動かすCADだったりネイティブ並みのことをやろうとしている場合にフロントとバックエンド両方Rustを取れるのは一つの利点かもしれません。

最後に: Railsを議論する際は他のフレームワークの挙動も把握しよう

以上です。解像度低い言語/フレームワークもあるので間違いあればフィードバックウェルカムです。

英語について研究している人は影響を受けたフランス語とドイツ語についてもある程度理解する必要があるそうで、何かを極めるためにはT型人材になる必要があります。

Ruby on Railsは人気のフレームワークのため批判されることはしばしばありますが、批判者の理解が浅い場合もあります。Ruby on Railsのいいところ、悪いところを論じるためには当然ながらある程度いくつかのバックエンドのフレームワークの挙動を把握する必要があり、そのスタート地点となるのではと思いまとめてみました。

Discussion