👨‍💻

Railsをやめても解決しない問題

2021/02/01に公開

序文

昨年末くらいからRailsとフルスタックJavascriptの論争の記事がよくバズってましたね。主にORMとパフォーマンスやSPAが論点として多かった気がします。
Rails側のSPA作りづらい問題に対し、hotwireが一つの解として今後どういう受け入れ方をされて行くのか、どう発展していくのかは気になるところです。

未来のフルスタックフレームワークの代表争い

さてこの論争、僕は「未来のフルスタックフレームワークの代表争い」だと思っているのですが、結構難しくって視点次第でどうとでもなっちゃうような気がしてます。
というのもこの手の技術選定の問題ってアプリケーション規模やチームの思考、求められるサイト特性などによって合う合わないがあるので、一概に正解がわからないんですよね。

例えば今勉強がてらブログを作ってみたい、という人には迷わず僕はblitzNext/Gatsby+外部サービスのCMSを進めます。
が、リッチなUI要件はなく、よくデータ更新が行われるような場合においてはSSG(Static site generator)やISR(Incremental static regeneration )みたいな戦略でレスポンスのパフォーマンスチューニングはできないので、Critical CSSや Core web vitals対応などのやるべきことをやってれば別にRailsでもパフォーマンスチューニングは成り立つと思ってます。

型がないのは個人的には辛いですが、Rails得意な人からTypescriptを取り巻く複雑なエコシステム周りの話を持ち出されると反論しがたい部分だなとも思います。
つまるところ、この論争はしばらく続くと思ってます。
お互いに強みと弱みがあって、今はその弱みをお互いがどう克服するか試行錯誤している時期かなと。

残り続けるフルスタックフレームワークの問題

この論争とは別に今後、JSでAPIを実装することに長けたフレームワークが欲しかったりもします。
というのもフルスタックフレームワークの採用ってミニマムアーキテクチャの採用とほぼ同義だと思ってて、機能的に中規模〜大規模なアプリケーションの場合そもそもマイクロサービス化してあげた方がいいよねというのが現代のアーキテクチャパターンなので、フルスタックではなくAPI特化なフレームワークの方が嬉しいこともあると思ってます。

そういう面でいうとフルスタックフレームワークを採用すべきアプリケーション規模というものが存在する、という前提でこの議論はされている認識だったりするんですが、意外とこの辺の話題はあまり見かけなかったので「Railsをやめてもやめなくても、フルスタックフレームワークでは大規模アプリケーションは実装しづらい」ということについて、僕の思うところを書いてみようかと思います。

先に結論

  • 小規模〜中規模アプリケーションではフルスタックフレームワークで開発することが最適な場合は多そう
  • 小規模〜中規模で最適だからと言って、中規模〜大規模でも最適とは限らない(100万行に膨れたものは言語やフレームワーク問わずアジリティの大幅な低下は避けられない)
  • フルスタックフレームワーク=スケーラブルなフレームワークではないことを意識しなければいけない

フルスタックフレームワークでの大規模開発

フルスタックフレームワークとは

まずフルスタックの定義を考えてみましょう。
Wikipedia には

これは、複数のWeb開発に有用なライブラリを一つに結合した Web開発者向けのソフトウェアスタックとして集約したものである

とありました。これがフルスタックフレームワーク、要はWeb開発に必要なもの全部入りセットのことです。

フルスタックフレームワーク+大規模アプリケーションでよく出る問題点

まずアップデートがしづらくなります。
経験ある人や同意してくださる方も多いと思いますが、工数というのは規模に応じて指数関数的に増えていきます。ここでいう規模とはアプリケーションの規模(ソースコード量や機能仕様の数)のことです。
規模が小さい場合、網羅テストすることはそこまで難しくないですが、規模が大きいと網羅テストすることは困難になっていきます。

また、多くの場合アップデート以外も修正がしづらくなり、保守工数やテスト工数、予期せぬバグに当たったりします。
この辺は自動テストやSOLID原則にのっとることである程度の秩序をもたらすことができると思いますが、大規模になり修正する人の人数が増えれば増えるほどこの手の設計原則を守り続けること自体が難しくなったりもします。

※後述しますがこれはRailsだけの問題ではなくアプリケーションのスケーリングの問題はよくある問題で、フロントエンド界隈ではVueがプログレッシブフレームワークという「スケーリング可能なフレームワーク」という位置付けで売り出してたのが僕にはとても魅力的だったりしました。

Webアプリケーション規模分類

ではアプリケーション規模を4段解で考えて、それぞれ規模ごとに工数や変更容易性的に最適だと思う形で分類していくことでフルスタックフレームワークにはどういった規模が最適で、大規模開発にはどういった形が最適なのか考えていきましょう。

※必ずしもこの4分類にあてはまるわけではないと思いますがよくあるパターンを独断と偏見で分類したものです。

Level1: No Codeや少量の実装で実現可能なアプリケーション

作りたいものがあまり予算のないコーポレートサイトだとか自分用のブログ(テックブログみたいに作ることが半分目的なものを除く)とかの場合、RailsとかNextとか使うまでもなくNo Codeのサービスで作った方が安く済むことの方が多いと思います。
僕はいつもstudio をおすすめしてますが、wordpressとかも当てはまると思います。

自分で作らないなんてエンジニアとしてイケてないと思われるかもしれませんが、実際エンジニアの稼働ってコスト高いんで稼働せずほぼ同じようなものが作れるなら顧客的にはそれに越したことはないと僕は思います。

Level2: 永続化を外部ASPにしたWebアプリケーション

リッチなUI操作や独自のログインなどは必要だけど利用者数が少なく機能的にもシンプルな場合、外部ASPで実装しちゃうのが最適なことが多いかと思います。

規模にもよりますがcontentful とか microCMS とかはGatsbyやNextでの実装は楽だし、firebase とかNetlify form もそうですね。
結局ありもののAPI使えてそれのサブスクリプションが実装コストより安いならこれらを使う方が良いだろうという考えです。

Level3: 単純なCRUDを中心としたWebアプリケーション

単純と表現しましたがテーブル数やルーティングが数えるくらいしかないアプリケーションのことを指してて、この場合においてはフルスタックフレームワークが有用だと考えます。

数えるくらいってどのくらいかってところが個人の感覚によりそうですが、結局閉鎖性共通の原則に沿って分割可能なら分割した方がアプリケーションとしては望ましいんじゃないかと思います。

https://qiita.com/NagaokaKenichi/items/65c149ba92580fce5be2#閉鎖性共通の原則ccpthe-common-closure-principle

これ極論するとフルスタックフレームワークは採用せず必ず分割しろって聞こえるかもしれませんが、変更頻度が多いことが明らかな場合は基本的に分割した方がいいと僕は思ってます。
とはいえマイクロサービス分割しておくことによるコストがメンテコストの最適化メリットを上回る場合はあると思うので、その際はフルスタックフレームワークの出番なのだろうと僕は思ってます。

Level4: 中規模〜大規模Webアプリケーション

またちょっと曖昧な表現ですが中規模以上の場合は前述の閉鎖性共通の原則にのっとり、基本的に可能な単位でマイクロサービス化しておくべきだと思います。もちろん必要以上に分割するとサーバーコストなども発生するのでその辺はトレードオフですが、アプリケーションは大規模になる程指数関数的に保守工数と障害リスクが伸びていくので基本方針としては分割しておくべきだと思っています。

今日時点で僕の知る限り、大規模アプリケーションを容易に運用しアップデートをノーリスクで行えるフレームワークは存在しない認識です。
デプロイ時に障害を検知しても、調査範囲が膨大な場合と小規模の場合でどちらが復旧を安全に高速に行えるかはいうまでもないかと思います。

規模分類を超える瞬間

上記の分類でも述べましたが、僕はフルスタックフレームワークが必要になるのはLevel3規模のアプリケーションのみだと思っていますが、実際アプリケーションの初期開発ってLevel3の開発をすることが多いんじゃないでしょうか?

ただここで問題になるのが、最初はLevel3規模だったのに数年のうちに明らかにLevel4規模のアプリケーションに達してしまうパターンです。クックパッドの100万行Railsアプリケーションリファクタの話(すごい・・・!)なんかは有名だと思いますが、最初からそうだったわけではなく止まらない肥大化によって大規模アプリケーション化してしまったんだと思います。
こういった大規模化してしまったアプリケーションに最初のスキーマ(Level3のアプローチ:フルスタックフレームワーク)がどうやら通用しないというのもRailsで明るみに出た問題だったのかなと思っています。

そこで出てきたのがマイクロアーキテクチャというアーキテクチャ分割手法で、これが大規模アプリケーションに通用する唯一のアプローチだと僕は思っています。
他にも「肥大化してしまったRailsが辛い」という話は聞いたことがありますが、基本的にその手の話は大抵Railsの問題ではなくアーキテクチャパターンの問題だと思っています。なので今後JSでフルスタックフレームワークが登場しても、この原則は意識する必要があり、そこを怠る人が多いと「フルスタックJS辛い」という人が続出するんじゃないかと危惧しています。

では何を持ってLevel4への入り口と判断すべきなのでしょう?
これは個々人の感覚(何行から大きいと感じるのかなど)によるとしか言えないと僕は思っています。では大規模化を防ぐことはできないのでしょうか?

現時点で使えそうなアプリケーション規模の判断指標

感覚による、とはいっても要は決めの問題なのでSonarQubeで定量化できる指標に対し一定の基準を設けるというのも1つの手だと思います。
例えば100万行RailsなんかはいまだとSonarQubeで行数モニタリングするとかすれば、今後大規模化は避けられそうですね。

あとはアーキテクチャ構成判断の基準になりうる他の計測指標からアーキテクチャ最適化を怠らないことも大事なことに思えます。
具体的には

  • ビジネス寄与数(経由CV数、利用者数など)が少ない機能の数
  • パフォーマンス

らへんの計測です。
ビジネス的価値がほぼないのに存在する機能にメンテ工数を払いたくないものです。この辺はt-wadaさんのVoyage なんかが詳しいと思いますが、「いらないものを捨てる」というのもアーキテクチャにおいて重要な活動だと思います。
また、似たような話でパフォーマンスも昨今Web界隈において重要なビジネス指標の1つです。SEOにも絡むし、直接的にユーザーのCVRなどに影響しえます。
ところがパフォーマンスは一朝一夕では改善できないものです。パフォーマンス最適とアーキテクチャは切って離せない話で、これにも「不要な機能の削除」や「できればあって欲しいけどパフォーマンスのために削除」する機能などもでてくることもあると思います。

なので直接的に大規模化を検知できなくても、不要な大規模化を防ぐ活動にはなりうるかと思います。

まとめ

最初に書いた結論の繰り返しになりますが、僕が言いたかったのは↓です。

  • 小規模〜中規模アプリケーションではフルスタックフレームワークで開発することが最適な場合は多そう
  • 小規模〜中規模で最適だからと言って、中規模〜大規模でも最適とは限らない(100万行に膨れたものは言語やフレームワーク問わずアジリティの大幅な低下は避けられない)
  • フルスタックフレームワーク=スケーラブルなフレームワークではないことを意識しなければいけない

RailsもblitzなどのJavascriptフレームワークも今は特にスケーラビリティに対する何かしらの対応予定などは見受けられません(僕が知らないだけだったらすいません)。なぜならこのスケーリングや大規模アプリケーションへの適用の問題は、多くの場合アーキテクチャの問題だからです。

また、昨今のRails論争は「フルスタックフレームワークの論争である」と思ってみると、僕は「BFF:NextJS+API:Rails」みたいな構成は今後も残るんじゃないかと思うし、それは全然いいんじゃないかなって思ったりもします。
この構成はフルスタックフレームワークを採用したものではなく、大規模アプリケーションにも対応できる構成だからです。

拙い文章でしたが読んでいただき、ありがとうございました🙇‍♂️

Discussion