― ウェブの「純化」と「ねじれ」の10年
10月5日、Ahmad El-Alfy氏が「How Functional Programming Shaped (and Twisted) Frontend Development」と題したブログ記事を公開し、話題を呼んでいる。
この記事では、20年以上のフロントエンド開発経験を持つ著者が、関数型プログラミング(FP)の理念が現代のフロントエンド開発をいかに形成し、 また一部ではプラットフォーム本来の力をねじ曲げてきたか という経緯と影響について述べている。
以下に、その内容をポイントを絞って紹介する。詳しくは原文を参照していただきたい。
秩序が複雑さを生んだ
React、Redux、TypeScript。これらのツールは、いずれも「予測可能で安全なコード」を目指して進化してきた。特にFP の純度を追求する潮流が「UI = f(state)」「不変データ」「副作用の隔離」といった強力な抽象化をもたらした。
しかし筆者によれば、関数型プログラミングの理念──副作用を排除し、不変性を保ち、状態を明示的に扱うという発想──をウェブ全体に適用したことで、本来シンプルだった仕組みを、かえって複雑にしてしまったという。
ブラウザはもともと「副作用的」である。
CSS はグローバルに波及し、DOM は直接操作でき、フォームやイベントは標準で動作する。
それらを「制御すべき対象」とみなした結果、フロントエンド開発は多層化し、ブラウザが得意とする機能まで JavaScript 側で再実装されるようになった。
秩序を求めた背景
2010年代初頭、JavaScript 開発は混乱していた。
jQuery スパゲッティコード、双方向バインディングのバグ、ブラウザごとの挙動差などが積み重なり、開発規模が拡大するほど破綻しやすかった。
この状況に秩序をもたらしたのが React である。
React の「UI = f(state)」という考え方は、状態を明示的に扱い、ビューの変化を関数的に表すモデルを提示した。
続く Redux は Elm の「Model-View-Update」思想を継承し、状態遷移を一方向に制御する仕組みを提供した。
こうして FP の考え方がフロントエンドに広がり、「不変性」「純粋関数」「副作用の隔離」が業界標準の設計思想として定着していった。
CSS-in-JS と「カスケードからの離脱」
CSS は本来、スタイルを全体的に波及させる「カスケード」によって成り立っている。
だが FP の視点では、これは制御不能な副作用とみなされた。
その結果、CSS-in-JS という新たな手法が登場する。
styled-components や Emotion は、スタイルをコンポーネント単位で閉じ込め、グローバル作用を排除した。
確かにこれにより予測可能性は増したが、代償も大きかった。
スタイルがランタイムで生成されるため、SSR(サーバーサイドレンダリング)の処理が複雑化し、パフォーマンスにも影響した。
また、クラス名がランダムに生成されるため、デバッグが困難になった。
Tailwind CSS はこの反動として登場し、実行時生成をやめてコンパイル時にスタイルを決定する方式を取った。
しかし Tailwind もまた、HTML に大量のユーティリティクラスを埋め込む構造を採用し、CSS の「継承」という利点を失った。
「カスケードを避ける」という思想は、そのまま新しい複雑さを生んでいる。
イベント・ルーティング・フォームの再実装
React の合成イベント(Synthetic Events)は、ブラウザ間の差異を吸収するための仕組みだった。
だが同時に、開発者がブラウザのネイティブイベント API に触れる機会を減らした。
結果として、addEventListener
の挙動を知らない開発者が増えた。
同様のことはルーティングやフォームにも起きている。
ブラウザには本来、<a>
や <form>
で実現できるナビゲーションと送信の仕組みがある。
しかし、React Router や Formik のようなライブラリがそれらを置き換え、すべてを JavaScript の状態管理に閉じ込める構造を作った。
その結果、Ctrl+クリックや右クリックといった標準操作が正しく動かないケースも増えた。
ハイドレーションと「ブラウザの再構築」
「UI は状態の関数である」という思想を徹底した結果、クライアントサイドレンダリング(CSR)が一般化した。
しかし、サーバーが HTML を生成しても、クライアントは再び同じ DOM を再構築してハイドレーションを行う。
つまり、ブラウザがすでに描画したものをもう一度 JavaScript で描画し直している。
その過程で API が二重に呼ばれ、キャッシュやデータフェッチも重複する。
ブラウザの持つストリーミング描画やプログレッシブレンダリングといった特性は活かされず、初期表示が遅くなる。
筆者はこれを「 ウェブを真っ白なキャンバスとして扱いすぎた結果 」と評している。
ネイティブ要素の軽視
この問題はコンポーネント設計にも及ぶ。
例えば、ブラウザ標準の <dialog>
要素はフォーカス制御、Escキー対応、アクセシビリティなどを備えるが、React 教材の多くは <div>
と状態変数で同等機能を再実装している。
フレームワークの設計思想が「ネイティブの機能よりも統一的な抽象化」を優先しているためである。
結果として、開発者がプラットフォーム機能を使わないまま、独自の複雑な実装を重ねる構造が生まれている。
回帰の兆し
こうした状況に対し、近年は「プラットフォームを尊重する」流れが戻りつつある。
HTMX、Qwik、Astro、Remix、SvelteKit などの新しいフレームワークは、HTML を第一級の成果物として扱い、フォーム送信やキャッシュをブラウザの機能として活かす設計を採用している。
それらは、「UI = f(state)」の考え方を内部に保ちながらも、JS に全てを委ねないアプローチである。
まとめ
筆者が伝えたいのは、関数型プログラミングの思想そのものを否定することではない。
問題は、それをウェブ全体に当てはめようとした点にある。
ウェブは、グローバルスコープや可変状態、非同期イベントといった「不完全さ」を前提に発展してきた。
その仕組みを“より純粋に”しようとした結果、私たちはブラウザの力を活かしきれなくなってしまった。
これからのフロントエンド開発に必要なのは、「ウェブを制御すること」ではなく、「ウェブと協調すること」だと筆者は締めくくっている。
詳細はHow Functional Programming Shaped (and Twisted) Frontend Developmentを参照していただきたい。