最近、コンサルの方と話すのが少ししんどくなってきました。
「え?FEでクリーンアーキテクチャかけないの?」
これ。
正直、ムカつくというよりも、前提の“クリーンアーキテクチャ”という言葉の意味が様々なアーキテクチャ特性を持つのに単一の自由だけでそう呼んでね?伝わるでしょ?っていうのに呆れます。
さらにタチが悪いのは、察しているはずの前提や文脈を無視して話を進めてくる姿勢です。
Architectureの話は根幹にかかわるので、曖昧に話を合わせるとあとで地獄を見ます。正直、察していても合わせたくない気持ちになるのも自然です
そもそも何をもってクリーンアーキテクチャとするか
ReactやVueなどはcomponentがあり、componentのふるまいとしてUIとアプリケーションロジックを両方同時に満たしていると考えられるのです。
したがって一般的な会話型で用いられる下記の図には……
あれれーおかしいぞぉUIなのにUseCaseが一つのファイルに同居しちゃったぞー
となるわけですね。

クリーンアーキテクチャ(The Clean Architecture翻訳)より引用
ボブおじの本では、この円は「原則の説明用の図」であって「実装図」ではない。
特に「外側の層」というのはあくまで一例であり、言語やフレームワークの特性によっては「外側の層がUseCaseを持つこともある」すなわち
「UIコンポーネントが内側の層を抱え込む」
ことも起こると述べられています。
つまり、クリーンアーキテクチャは構造的に固定されたものではないのです
正直なところ言うと、クリーンアーキテクチャの原著には確かこの円はあくまでも例ですとなっています。
使うものに合わせて柔軟に組み替えてね?とここらへん著名な企業のマネージャーでさえ間違えていることがあるんで、何とも言えないんですが。
だからこそ正しく相手に伝えようとするとクリーンアーキテクチャという万人が理解しやすいのではなく、正確にはFE向けに再定義した責務分けアーキテクチャ/ドメイン駆動アプローチが正しい言い方なんではないかと考えています。
FEのアーキテクチャを開拓してみようよ
「FE向けに再定義した責務分けアーキテクチャ/ドメイン駆動アプローチ」がどういうものになり得るのか?
アーキテクチャ特性を考えてみましょう
基本的にフロントエンドはバックエンドほど潤沢な環境にはいません。SPAではユーザー体験を損なわないよう、ブラウザのリソースやレンダリング速度を考慮する必要があります。そのため、単純にバックエンドでよく言われるクリーンアーキテクチャやDIコンテナをそのまま持ち込むのは現実的ではありません。
可用性、保守性、速度性など、様々なアーキテクチャ特性をどのように実現するかは、SPAで構築するのか、SSRで構築するのかによっても変わってきます。
1.SPA
-
クライアント側でほぼ全てのレンダリングを行うため、ブラウザのリソース制約がボトルネックになりやすい
-
高速なUI更新やリッチなインタラクションには向く
-
可読性・保守性は層を分けて責務を明確にすることで担保可能
2.SSR(Server-Side Rendering)
-
初期レンダリングはサーバーで行うため、ユーザー体験の速度感やSEOに有利
-
状態管理やビジネスロジックの配置を慎重に設計しないと、サーバーとクライアント間の状態同期が複雑になる
-
高頻度更新には不向きで、ダッシュボードやリアルタイムUIにはSPAとの組み合わせが望ましい
そのため、どの特性を優先するかによってアーキテクチャの選択や層の責務範囲を決める必要があります。
例えば、可読性や保守性を重視するなら、SPAでも「Component → UseCase → Domain/Repository → State管理層」という責務分けを徹底するのが有効です。一方、速度性や高頻度更新が重要な部分では、State管理層へのdispatch頻度を最小化する工夫や、ローカルstateを併用するなどの設計判断が求められます。
私がアーキテクチャ設計面倒な時によく使うものがあり、それを見てみましょう
State Driven Architecture
ステート駆動型アーキテクチャでは、アプリケーションの状態(State)を中心に設計を行います。
Reduxなどの既存の状態管理ライブラリでは、しばしばStateがドメインやユースケースのような責務を兼ね始め、結果として肥大化・汚れが生じがちです。
そこで、状態管理自体を独立した層として隔離することを当時は提案していました。
最近では画面とAPIの挙動で状態管理が完結することが多くなってきたのでゴリゴリReduxやらJotaiを使うかは考える余地はありますが、いったんこういう動きになりますよというところだけでも
Component --(イベント)--> UseCase --(dispatch)--> State管理層
│
├──> Domain(エンティティ/値オブジェクト/ドメインサービス)
│
└──> Repository (API/DB)
特徴
1.状態管理の独立
-
グローバルStateは純粋に「アプリケーションの現在値」を保持
-
UIは読み取りのみで、書き込みは必ずUseCase経由
2.責務の明確化
-
UseCase: 状態更新やドメイン処理の統括
-
Domain: ビジネスルールの純粋な表現
-
Repository: 外部データアクセスの抽象化
3.高速更新対応
-
ダッシュボードやリアルタイムUIでは、更新頻度の高い部分はローカルStateで処理
-
必要に応じてState管理層に同期
ただし、これはあくまで一例に過ぎません。
-
状態管理にUseCaseの動きを持たせるパターンや、Stateを直接更新する「直叩きパターン」など、現場では様々な考え方が混在します。
-
認可情報のような特殊なケースでは、Componentより上位で動くものもあります。
つまり「すべての画面・すべてのケースに一律でこのパターンを適用すべき」というわけではありません。
そもそも、状態管理が必要なければ、UseCaseに直接Repositoryからデータを返してやれば十分です。
つまり、フローはシンプルにこうなります:
Component --(イベント)--> UseCase
│
├──> Domain(エンティティ/値オブジェクト/ドメインサービス)
│
└──> Repository (API/DB)
この場合、State管理層を挟まないため、更新頻度が低い画面や一度読み込んだらほぼ固定のデータに対しては余計な複雑さを避けられます。
がステート駆動型アーキテクチャとは呼べなくなってしまいました。
なるほどじゃぁ……ユビキタスだし、クリーンアーキテクチャと呼びましょう。
みんな伝わるでしょ??
いやいやちょっと待てよ、ドーナツからも外れていていろいろアーキテクチャ特性考えて弄り倒したアーキテクチャがクリーンアーキテクチャだけで通じるとでも?
むしろここまでくると、「クリーンアーキテクチャ」と言い張ることは、
コンビニでおじいさんがタバコを番号ではなく「マルボロメンソール」と言ってレジを詰まらせるような暴挙を見ている感覚になります。
あれ?クリーンアーキテクチャ理解してないの?
黙れ小僧、貴様に日本のモダン開発が救えるか!!
実際、クリーンアーキテクチャのようにドメインを中心に展開していくアーキテクチャでは、ユビキタス言語の共有が不可欠です。
しかしそれを無視して「クリーンアーキテクチャがどうたら」と語り始めると、いよいよもって終わり感が漂ってきますよね。
日本がシステム開発に失敗し続ける理由って、わからないこと説明が不足していることを聞くとKYや無能のレッテルを張るからなんじゃ……
あと一部開発者がドメイン駆動とかクリーンアーキテクチャとか書かれ始めると拒絶反応して、アマゾンのレビューで「クリーンアーキテクチャ等モダンなことが書かれていて参考にならなかった」 星1とかやり始める原因にもなっているんじゃ……実際見たぞ割と愛読してる書籍のレビューで
参考
State Driven Architecture例
クリーンアーキテクチャ(The Clean Architecture翻訳)