モジュラフロントエンドのメモ
このスクラップは?
SPA において(レイヤーではなく)表示領域ごとの分割統治方法をメモしていく。スパム的なものを以外、誰がコメントを付けても構わない。
(リンクが無いものも自分がふと見かけた別のエンジニアのアイデアがベースになっている)
分割統治することで、領域の関心がシンプルになり理解しやすくなるし UI の歪みも明らかになる。また、レイヤーを減らすことで、領域全体を一目で把握しやすく、また、実装しやすく破棄しやすくする。
ただし、サーバー等でのプラクティスであるモジュラモノリスレベルでの分割を SPA で実現するのは、相互作用の多さから不可能だろう。
別の目的で作られたとはいえ、こうしややり方に借用できるツールやライブラリが整ってきたことにより、現実的になりつつあると考えている。
フロントエンドにおけるモデルについて
サーバーと違い、フロントエンドには長く残すべきドメインモデルのようなモデル[1]はない。フロントエンドの関心は UI とそれにまつわる必要な処理だが、それらは頻繁に変わる。フロントエンドでの短命のモデルに変更を加え続けるよりも、レイヤーやモデルの存在を気にせず E2E でべた書きした方が将来の保守性・実装速度が上という状況はあり得る。
レイヤードアーキテクチャ[2]は良く知られた有効なプラクティスで、普通のサーバーのコードであればレイヤー毎に関心は整い良いコードが書きやすいだろう。一方で、「ブレークスルー」による再モデリングではない文脈で、他と同化したドメインモデル・ユースケースの一部分を取り除くのは影響範囲を確認しつつの作業となるため面倒だろう。サーバーではどういう状況でこうした要求が発生するのか私にはわからないが、ほぼ起きないならば問題にならないと思う。一方、フロントエンドでは UI デザインの変更でその処理が不要になることはある。
短命なモデルしかないフロントエンドに、レイヤードアーキテクチャはどの程度役に立つのだろうか。
ちなみに、フロントエンドでのバリデーションロジックはドメインモデルではないか?という意見はあると思う。これについては、サーバーのバリデーションがデータやビジネスの整合性を維持するためのものであるのに対し、フロントエンドのバリエーションはユーザビリティ向上のためにあることを考えると良い。
フロントエンドではユーザビリティのためにサーバーと違うチェック・表示も可能で、ビジネスロジックとは別に、それと無関係に UI デザインや UX ライティング上の要求として実装できる。
-
DDD でのモデル・ビジネスロジックはサーバーの更新系を意図している。一方の参照系のリードモデルは柔軟に書けたり変えられたりした方が良いという意見があったと記憶している(手前味噌だがまとめは https://blog.masuqat.net/2020/11/03/system-mode-border/ )。このくくりでは、フロントエンドは参照系にあたるので、フロントエンドのモデルはこうしたドメインモデルとは性質が異なる。 ↩︎
-
関心毎にレイヤーに分けることで、理解しやすく技術的変更に強いコードを目指す。ヘキサゴナルアーキテクチャのようにレイヤーの分け方をうまくとると、ドメインモデルやビジネスロジックを不要な技術的詳細の影響から守ることができる。 ↩︎
コンパイラは比較的キレイにレイヤリング可能なプログラムなので、コンパイラばかり書いている人たちにとってはそれこそが正しいデザインに思えたのだろう。
リンカと比較できるものではないが、私見ではフロントはきれいにレイヤリングできない、もしくは、効果が薄い。
把握しやすいミニマムなコード
領域全体を常にすぐに把握しやすい状態に保つことができれば追加実装しやすい。レイヤードアーキテクチャの欠点はボイラープレート的コードが必要になることと、E2E での把握がしにくくなる[1]ことだ。
フロントエンドではJSON色付け係という言葉があるようにサーバーから取得したデータをユーザーに見せる処理で完結する場合も多く、その中間のロジックもあまりないので技術的詳細を隠蔽してもあまりうれしくない。フォームをはじめユーザーに操作してもらうところも多いが、こちらも HTML の仕様と強く結びついているので隠蔽の旨味は少ないと思う[2]。
そうであれば、むしろレイヤーを取っ払って、データ取得と表示を近くに書いてみたらどうだろうか。ボイラープレートが減って E2E での把握もしやすい、把握しやすくミニマムなコードができるのではないか。
(ドメインモデルがあるような普通のサーバー的には失格かもしれないが)
これの "Worse is Betterという考え方" そのままだった。
捨てる障壁を低いということ
今の実装(の一部分)を捨てて作り直すすることに躊躇しなくなると何がうれしいか。フロントエンドで(一部分の)実装を捨てるという事態は、負債解消や機能追加等の実装上の理由だけでなく、UI デザインの変更や検証で部分的に作り変える、という理由でも起きる。
むしろ、現実の使い捨て製品のように、捨てるコストが低い方が運用の柔軟さに勝り、実装や UI デザインの試行錯誤や改善が行いやすい。
「犠牲的アーキテクチャ」なのかもしれない。
CSS の技術
TODO: Utility-First CSS, Container Query
デザイントークンの反映と必要最小限のセマンティクス
コンポーネント設計
TODO: Atomic Design の Organisms
API アクセス
TODO: GraphQL
-> render-as-you-fetch パターン、fetch の物理処理と論理処理をつなぐアジャスターとしての fetch ライブラリが必要
物理処理:実際に飛ぶリクエストのこと
論理処理:特定のデータを(利用者が感知しない何かしらの方法で)取得すること
demand 型
更新波及が宣言的
TODO: msw によるモック
- SoEの要件の変化の速さについていけない
- UIに正解がない ≒ APIのモデリングに正解がない
Atomic Design でいうところの Organisms レベルで API リクエストをする際に気を付けたいこと。
課題
- 意図しないリクエストを見つける
- 不要なリクエストを見つける
- 権限の分岐
- どこで分岐するか。親か当該コンポーネントの JSX か子孫か。
- この権限のユーザーではある API にリクエストしても 403 になるだけなので呼ぶべきでない。ただ、それをコードを見てチェックするのは面倒なので動かしてみて確認したい。
assert する方法のヒント
残し続けるべきものは何か?
デザインシステム
TODO
スピードを落とさないために指針が必要。
UI デザインを改善し続ける姿勢
TODO
既存実装を気にしない。捨てるのを躊躇しない。
実装能力
捨てられる構造だからと言って、書き捨て的な汚いコードを書いてよいわけではない。あくまで全体のコード量を抑え見やすくし、かつ、捨てる際のコストを低くすることが目的だ。
むしろ要求される能力は増える。機能追加の際に、コードが膨れないようにしたり、UI デザイン変更で一部を作り直すときに(ボイラープレートなコードを追加・削除する時間が不要になる分だけ)実装の質と速度がエンジニアの実装の質と速度により依存するだろう。
コンポーネントカタログ・テスト
TODO
内部ステート化による網羅の難しさ
-> storybook addon interaction
VRT
カタログのテスト転用
マイクロフロントエンド
モジュラモノリスの先にマイクロサービスアーキテクチャがあるのでここでも考察
Webpack の Module Federation を使うとすぐに(?)実現できそう。
Vite を使いたい場合。
Vue を使う人は Origin.js の Vite plugin が良いかもしれない。
そうでない人(React 派等)は @module-federation/vite を使うと良さそう。(2023/03/21 時点ではまだ 0.x だが…)
(違いがわからないという話もある https://github.com/module-federation/vite/issues/4 )