お仕事をしていて、たまにRFCを読みたくなることってよくあると思うのですが、読む対象のRFCがたくさんあると、どれから読めばいいのかな? 読み落としたのはないのか? みたいなところが脳のワーキングメモリーから溢れて収集がつかなくなりがちなので、Graphvizで出力してRFCの関連を簡単に確認できるツールを作ってみました。
ソースコードは以下のところにあります。
https://github.com/shibukawa/rfc-viewer/
こちらのGitHub Pagesで触れるようになっています。
https://shibukawa.github.io/rfc-viewer/
使っている技術セットはこんな感じです。
- React + TypeScript
- Vite.js
- Tailwind CSS + DaisyUI
- Recoil.js
- d3-graphviz
RFCを読むのも大事ですが、ちょっとRecoil.jsの素振りというか練習もする必要があって、それを兼ねて作ってみました。
RFC-Viewerの使い方
まず、RFCをリストアップしたい範囲があればfrom/toに数値を入れます。例えばHTTPを調べる場合、 1945よりも古いものはないはずなので、そういう場合に使います。
起点となる用語をincludes(2段目)に入れます。それが含まれるRFCが選ばれます。3段目はexcludeで、この用語が含まれているRFCは除外されます。
最後にチェックボックスで、祖先や子孫を辿るか? というチェックボックスがあります。RFCには、updates/obsoletesという項目があり、既存のRFCに機能追加を加えたり、既存のRFCを廃止して新しいバージョンのRFCを出す、ということができます。この情報を元にグラフ構造を作ります。
ただし、祖先と子孫の両方を辿るオプションを入れると、たまに関連が爆発して1000ぐらいのRFCが引っかかることがあります。DNSとかTLSみたいな、他のRFCから参照されまくっているものが見つかると、すごい数になってしまいます。
最後に生成ボタンを押すと、graphvizのソースを出力したり、ブラウザ上でレンダリングして見られます。いろいろいじってRFCライフにお役立ていただければと思います。
リアクティブプログラミング
React/Vue/Angularが三国志のように競っていた時代は、どれも同じようなモデルでした。コンポーネントという塊に対して、「状態」という色々な情報の塊が1つあり、それに対するデータの読み書きという世界観でした。ライフサイクルメソッドというものがあり、ステートの初期化を行い、イベントがあればステートを書き換え、最終的にそれが仮想DOMやら何やらの仕組みを使って画面に表示されます。
欠点としては、ステート管理のコードがコンポーネントと蜜結合されてしまうので、コンポーネントを分割しようとか、リファクタリングをするのは結構大変です。
コンポーネントは基本的に自分の親子としか会話できません。深い階層があるとバケツリレーが必要になり、コードが多くなってしまうのでそれを解決するための手法としてFluxという考え方がReactにより導入されました。このようなものはVueにもAngularにも導入されたりしました。Reduxが人気になりましたし、VueだとVuexとか人気ですよね。ただ、このようなグローバルな状態のストアも、基本的にでかい1つの箱(あるいはちょっとした階層)があり、そこへの読み書き、というところはコンポーネント側の思想と同様です。
Reactは16.8になってhooksを導入しました。関数コンポーネントになってライフサイクルメソッドという考え方を完全に無くした世界を作ろうとしてます。新しくなったReactのドキュメントでも、すべては副作用、という考え方を徹底しようとしています。ライフサイクルという縛りから離れて将来の最適化のためにStrictModeの場合はマウントとアンマウントを繰り返して、ライフサイクルメソッドの考え方で壊れやすいコードを実装しないようにさせよう、という挙動が18で導入されました。
Reactの関数コンポーネントで実装すると、コンポーネントの中は「大きな1つの状態」ではなくて、小さい状態がたくさんある状態になります。イベント、他の状態の変更(propsの変更も含む)で副作用が発生し、またそれが状態を変更する・・・という構造になります。状態と副作用のセットをカスタムフックとして切り出して再利用もできるようになりました。
ReduxもTypeScript対応やこのhooksの副作用と繋ぎやすいような拡張がされたり、それに合わせた進化はしていましたが、一方でmetaは新しい考え方の状態管理のライブラリであるRecoilをリリースしています。
Recoilは、React Hooksの世界観をコンポーネントを跨いで使えるようにしたものに思います。atom, selectorという2つの要素でグラフ構造を作っていきます。Recoilドキュメント入門というエントリーを前に書きましたが、コンポーネント間の情報伝達で、属性やイベントで行わずに、単に状態を定義しておき、exportしておくだけでコンポーネントを跨いだ状態の共有が行えます。
RFC-Viewerでは、サイドバーで検索の情報を入力させます。これはRecoilの状態管理の要素であるselectorにしています。この情報を使ってリアルタイムに検索を行わせることも可能です。実際、ソース生成までは直接は行っていませんが、検索ロジックを起動してヒット件数をボタン上に表示しています。
クリーンアーキテクチャは情報の流れを一方通行にするためにレイヤーを作って・・・という感じですが、すべての情報を依存グラフ上に表現し切っている感じですね。UI上のインタラクションも、UIが生成したデータをロジックが処理するのも、その結果を画面に表示するのも、すべてこの依存グラフ上でリアクティブに解決されていく、というのはなかなかおもしろ体験です。他のコンポーネントに伝達するためにpropsやイベントなどの外部I/Fを作り込むこともなく、状態管理の副作用のコードで頑張る量も体感で1/3ぐらいになりました。令和の時代になってようやく、亡霊のように生き続ける20年前のJ2EEとかのMVCやらレイヤーやらの考え方から、新しいアーキテクチャに一新されるチャンスなのでは、というのを感じました。
もっとも、Recoilのみがこの思想で作り切っており、他のフレームワークではまだまだコンポーネントの外までリアクティブを活用はできません。そのため、今すぐ、ウェブ開発全体がこの方向性になっていくか、というとならないとは思いますが、未来の(だと自分が信じる)アーキテクチャについて考えるのは頭の体操になりますね。いちおう、Angularが統合しているrxjsはリアクティブなフレームワークですが、Suspense対応なども含めて、Recoilの方が圧倒的に使いやすいです。
まとめ
RFCを読むための補助ツールを作りつつ、次世代のアーキテクチャをRecoilで体験しました。長くなったのでRecoilのTIPSはまた今度書こうと思います。
なお、Reactive Programmingという項目は日本語にはないですが英語のWikipediaにはあります。