Goodbye Gatsby, Hello Remix

本ブログを Gatsby から Remix に切り替えた。徐々に Gatsby 依存のコードを排除してきたために最後の移行自体はそこまで難しく無かったが、それでも二日掛かった。

Hello Remix

差分ファイル数や差分行数が多いが、ブログ記事本体による見せかけ。実質必要だった変更はそこまで多くない。Cloudflare Pages にデプロイしてる。公式でアダプターを提供してくれているので、何も困ることはなかった。

Why Remix?

なぜ Remix に移行したのか。理由はシンプルだ。Gatsby を中心とした今の技術スタックに飽きてしまったからだ。

Gatsby との出会いは、GraphQL Asia 2019 に遡る。GraphQL に関してアジア圏初の大型カンファレンスに参加した私は、そこで Gatsby や Netlify の開発者たちと出会い、GraphQL をインターフェースとした斬新なデザイン思想やエコシステムの加速度的な発展、カンファレンスで感じた現地の熱狂に惚れた。帰国後に早速 Gatsby を利用したサイトを幾つか実装し、その自然な帰結として個人ブログも Gatsby に切り替えた。

当時から五年が経過した。その間に、Gatsby Plugin を実装したり、複数の Toolchain を利用したり、Gatsby 本体のソースコードを読んだりしてきて、日常の開発にはそこまで困らない程度には習熟した。SSG (Static Site Generation) でブログを書くワークフローも手に染みついた。Gatsby を取り巻く開発陣の様相も大きく変わった。Gatsby Cloud が、まさに GraphQL Asia 2019 から帰国した半年後に登場し、2023 年に Netlify に統合された Gatsby は、他社競合との差別化をするためにも、数々の機能を実装していった。

その一方で、Remix といった全く別の思想を持つフレームワークも進化し、Vite のようなツールチェーンも強化され、Next.js はもちろん継続的にアップデートされ続けてきている。そのような中で、Gatsby 離れ散見されるようになってきた。この現象はある程度習熟した技術全般に言えることで、逆にこのような議論が出てきたことが Gatsby が枯れて来たと言えるのかもしれないが、五年前に比べて Gatsby を敢えて利用することへのワクワク感、期待感、楽しみ、というのが個人的に薄くなってしまった。

そんな悶々とした気持ちを抱える中で、Shopify が Remix を買収し、周囲でも Remix の本番適用が見られることになり、そのパフォーマンスの向上やUnidirectoinal なデータフロー設計思想や内部実装に興味が出てきた。その結果、Remix にいっちょ乗り換えてみるか、というシンプルな好奇心で切り替えた、というのが本音だ。所属上、ポジショントークと捉えられるかもしれないが、そうではない点は明記しておく。本業は Site Reliability Engineer (SRE) であり、Remix の機能開発自体には携わっていない。

Goodbye SSG, Hello SSR

Gatsby の思想の根本にあるのは SSG (Static Site Generation) だと理解している。CPU Intensive でアセットの増加に応じて伸びるビルドプロセスと引き換えに、必要なデータをランタイムではなくビルド時に読み込み HTML に埋め込む。そうして生成された静的アセットを CDN に置くだけで、それなりのパフォーマンスを達成できる。アーキテクチャの観点から考慮してもバックエンドを必要としない非常にシンプルな設計であり、運用も容易である。ビルドツールの保守コストやビルド時間をトレードオフに、シンプルなデプロイメントとエッジへの展開を可能としている。

正直、SRE として評価すれば SSG はメンテナンスコストが少ない理想的な運用だ。実際に、リタイアしたサービスを最低限のコストで運用する場合に、それまで動的なアプリケーションだった構成をシンプルに静的アセットに切り替える手法は実際にある。

一方で SSR (Server-Side Rendering) は、クライアントであるブラウザーでの描画をサーバーサイドに持ってくるという思想だが、サーバーの運用を前提とする。データをビルド時に埋め込まないということは、ランタイム時にどこかから取得する必要があるが、データベースやキャッシュストアを必要とする場合、それらの保守コストも生まれる。

しかし、ユーザー体験で考えたときにパフォーマンスが常に最高点かというと、実はそういうわけでもない。SSG によってビルドしたアセットは CDN でキャッシュされて配信されるからこそ速いのであって、キャッシュできない動的なコンテンツ(検索結果)や Cache Miss のケースでは、必ずしも最適化されたレスポンスを返せるとは限らない。

何も SSR 自体は新しい技術でも Remix の特権ではない。運用に対するデメリットは至る所ですでに議論され尽くしている。Node.js の運用スキルを上げる方向に振り切るのも手だが、バックエンドのパフォーマンス最適化の手法は多岐にわたる。更に、Gatsby でも SSR は可能 であるし、Static Generation を遅延する DSG (Deferred Static Generation) という手法も提供されている。とはいえやはり、デフォルトでは SSG を推奨する Gatsby と、SSG の手法自体を現時点では提供していない Remix では、開発速度や機能提供の幅には大きな差異があるのではないだろうか。

SSR でサービスを運用する際の一番のマインドセットの変化は、ボトルネックが常にバックエンドにあるという前提だ。データベースの制約であったりスロークエリや N+1 クエリだったりの改善に投資することが求められる。シンプルなサイトであれば SSG で全く問題ないだろうか、中長期に運用するサービスにおいては、初期に綿密にデータモデリングやサービス間通信に投資した利益が複利で効いてくる。

Investing in your back end will yield the same performance results as SSG, but it scales to any kind of page. It will require more initial work than SSG, but we think it's worth it for your users and your code in the long run.

SSG はデプロイメントと運用をシンプルにする。一方で SSR は、複雑性をバックエンドと運用側に持ってくることを受容することによって、クライアントサイドでの処理をシンプルにする。トレードオフをどこにおくかと言う問題であり、どちらの技術が優れていると言う話ではない。

Unidirectional Dataflow

Remix を初めて触れた時におそらく困惑するのは、loader / action / component の仕様だろう。かなり Opinionated なフレームワークだという印象は拭えない。しかし、強力な制約を加えることによって、データ管理をシンプルにしている。

export async function loader() {
  // provides data to the component
}

export default function Component() {
  // renders the UI
}

export async function action() {
  // updates persistent data
}

loader がデータを読み込み、更新系のアクションは action が担当する。Component はその結果レンダリングされる。そしてそれらを一つのファイルに書いていく。MVC (Model-View-Controller) でいうところの View と Controller を loader / action / component の組み合わせで再定義している。

この制約によって、データの更新イベントが流れるデータフローが明確になる。どこで更新され、どこで読み込まれ、どこで表示されるかの関連が、一方通行で表現される。これは開発体験にとって大きなメリットだと考えている。

フロントエンド開発の肝の一つは、ユーザーの行動によって常時変化するステートの管理 (State Management) にある。Remix はサーバー側の状態とクライアント側の状態の同期を担うことによって、クライアント側での複雑な状態管理を可能な限り減らそうと試行している。プロのフロントエンドエンジニアではないので、これで全てのユースケースに対して状態管理が楽になるとは口が裂けてはいえないが、サーバーとクライアントの間で乖離する状態をフレームワークが管理してくれることほど嬉しいことはないだろう。

What's next?

と軽率に Remix について語ってみたが、また向こう五年は利用してみないと見えてこないデメリットや制約はあるだろう。引き続き Remix を利用しながら、限界点を探っていきたい。

もしすでに Remix を本番で利用していて、何かご存じだったり意見がある方がいれば、教えて欲しい。ぜひ話しましょう。また、Gatsby よりもおそらく有名で利用されているであろう Next.js と比較するほどには Next.js の経験がないので、有識者の意見が欲しいところである。SSR の本番運用経験はあるとはいえ、これはアプリケーションのワークロードの性質やデプロイ構成によって大きく異なる環境なので、SSR に関しても幅広いフィードバックを欲している。

また、個人ブログは限界点を探れるほどのリクエストは受けていないので、あくまで本番業務での知見が重要になってくるはずだ。個人ブログはあくまで実験場に過ぎないので、ここでの経験が遊びの領域を出ることはない。手を動かしながら考えていく。

2024-04-27