宣言的UIのデータアーキテクチャはコンポーネントを中心に考える
#宣言的UIの設計レシピ #状態管理(GUI)
フロントエンドのドメインはUIを構築すること。
UIの最小単位はコンポーネントだが、データ構造や振る舞いの分割はどのように行うとよいのだろうか。
関連
宣言的UIの振る舞いを分割する単位はページなのか機能なのか
宣言的UIのモジュラリティや堅牢性はコンポーネント設計で担保する
ドメインをデータのワークフローと捉えるのか、ユーザーが期待する振る舞いと捉えるか
koushisa.iconは宣言的UIで
ソフトウェア工学としてのオブジェクト指向
Domain Object, Value Objectっぽいもの
SPAでのレイヤードアーキテクチャの考察と不確実性へのマインドセット
複雑GUIにおけるRepositoryパターンの勘所
複雑GUIにおけるDomain Modelの勘所
などを実践した経験を持っているがうまくいったケースはほとんどない
なぜうまくいかなかったのか?
フロントエンドと時空から示唆を得た
---
オブジェクト指向やクラスは不要な時間的凝集を作る
状態がクラス階層の奥にあればあるほどリグレッション管理が難しくなる
状態を減らす関数型プログラミングが主流
データ構造と振る舞いを切り離す
クライアントサイドの実装におけるModelとは何か
フロントエンドでMV*フレームワークを使わない理由
---
宣言的UIにおけるステートやロジックのほとんどはServer Stateに集まる
@adwd118: サーバーでロジック>外部依存(DBなど)の関係にするのは理解できるけど、フロントエンドってクライアントっていうくらいなんだから外部依存を扱うことの関心のほうが主では?なのでReactのfetchと状態とViewが一度に現れるような書き方がポピュラーになった気がする
@adwd118: フロントエンドとバックエンドでクリーンアーキテクチャの同心円が2つあるんじゃなくて、あくまでもサーバーサイドがメインの同心円にフロントエンドがくっつくイメージ
https://pbs.twimg.com/media/FnxBA7FaAAQIhFr.jpghttps://pbs.twimg.com/media/FnxBDBzaQAEkAfu.jpg
GraphQLでいうと参照系でのdomain->usecase->viewあたりの変換はQueryの柔軟性でほぼ自動で、あとは更新系のドメインロジック(Usecase相当)をMutationに落とし込めばこの図での関係性はすごくしっくりくるのでやっぱりGraphQL最高🔥
@adwd118: あとそうだ、同心円以前の原則である依存性の逆転もフロントエンドでやらないほうが楽だと思う。サーバー・クライアントという関係からして明らかにサーバーに依存してるわけで、逆転で得たかったテスタビリティとかが別の手段で確保されてればいいんじゃないかな?
@adwd118: フロントでレイヤリングしてもいいけどああいうのが唯一の手段ではないし、別の生産性が高くてテスタビリティも同等なやり方があるのではという提案というか、最近のフロント見てると流れは明らかにそっちなはず
@adwd118: HTTPリクエストのロード状態なんか
const { loading } = useQuery(...);
で今どきは済むところをusecase->port->presenterとかやる意味ンゴ…😇
大体のWebアプリでは「ドメイン」と呼ばれるものはサーバーサイドで処理されていてフロントエンドはそのクライアントでしか無い
Server Stateを管理する現代のトレンドはRender As You Fetchパターン
末端のコンポーネントがデータフェッチして同じキャッシュを参照する
必然的にコンポーネントを中心に組み立てることとなる
@fumi_sagawa: propsを極力排してコンポーネントは閉じる。「jotaiで複数回使われる状態の共有/TanstackQueryでDB直通」させたいんだけど過激派かな?
最近SPAはめちゃくちゃちっちゃいMVCの集まりだと思ってる
#TanStack_Query
Atomic State Managementもこれ
Next.jsのApp RouterやReact Server Componentsもこれ
コンポーネントをアクターモデルのように捉えてる
@yuta0801_: 直接的にはあまり言及してるのを見ないが長い間Suspenseが事実上Relayで使うためにあったような状態だったのを感がるとReact側はGraphQL推してるはずで、それなのにNext.jsがfetchレベルで標準APIを拡張して制御させようとするのはよくわからないな
上述の「サーバーサイドがメインの同心円にフロントエンドがくっつく」という文脈を交えての仮設koushisa.icon
RSCやAppRouterはGraphQLの正統進化で、resolverがJSXを返すようなもの
@rickhanlonii: @Dan Abramov It’s like original React changed how we thought about separation of concerns from separating technologies to separating components, and now it’s doing the same for separating the stack. It’s just components all the way down.
Reactの登場によって、技術の分離からコンポーネントの分離へと、関心事の分離の考え方が変わりましたが、今度はスタックの分離も同じようになりました。スタックの分離も同様で、ずっとコンポーネントだけです。
宣言的UIのモジュラリティや堅牢性はコンポーネント設計で担保する
GUIでスケーラブルなアプリを書く秘訣は、良いコンポーネントを適切なタイミングで抽出することで、それ以上のことはない
---
これからどう考えるべきか
サーバーとクライアントは主従関係にある
クライアントはサーバーが所有しているリソースをコンポーネントツリーで表現している
リソースの構造や関係性に目を向けたコンポーネント設計が重要である
メッセージパッシングとしてのオブジェクト指向
状態管理ではなく関係と関連に着目した状態法則を考える
依存関係の意味を区別する
この哲学や構成方法はReact Docsに大体書いてある
単方向データフロー(unidirectional data flow)を徹底する
ステート/オブジェクトのライフサイクルを考えたときに状態遷移は一箇所にまとまっていると認知負荷が低く管理しやすい
データとロジックは近い位置にまとめる
UI/UXの仕様変更で複数のファイル or コンポーネントをまたがって変更するのは避けたい
MVVMのようにデータ構造と振る舞いが密結合な双方向バインディングのアーキテクチャを避ける
スコープは小さいに越したことはない
イベント発行からのレスポンスを期待しないことと、レスポンスからの状態更新をしないことが、物事をシンプルに保つ
依存を一方通行にするためにコンポーネントとイベントハンドラのインタフェースを整理する
安定依存の原則(SDP)
困難は分割せよ(サブドメイン分割)
細かく分けすぎるのではなく、一番外側の制御フローを意識的にシンプルにする
SLAP原則
Elmの哲学
外側に近いモジュールほど一方通行のストーリーを作る
コンポーネントをまたいだロジックやステートで依存関係が生じる場合
Lifting state up
Layoutコンポーネントを配置する
Atomic State Managementに寄せる
Async SelectorかRender As You Fetchパターンでコンポーネントから副作用を分離する
Async Selector: APIは「叩く」のではなく「叩かれる」もの
大事なことなのでもう一度、基礎はReact Docsに大体書いてある
---
UIに大層なアーキテクチャが必要となるケースは限られる
ペイするケースが少ない
Worse is Betterで、認知負荷が低い設計はスケールしやすい
フロントエンドはJSON色付け係に専念したい
生存期間の長い守りたいドメインロジックは少なく、あったとしてもUI/UXと密結合
あまり独自のXXX層とかを設けない
APIの構造とクライアント上のユースケースが合わない場合にはじめてドメインモデルを検討する
条件分岐ではなく、 パターンマッチングにするための代数的データ型(ADT), Presentation Model
必要に応じてテスティングトロフィーに乗っかる形でBDDのテストを書く
技術の変遷に対する考え方
SPAでのレイヤードアーキテクチャの考察と不確実性へのマインドセット#6469c81c8660300000b41a45