コンテンツにスキップ

UI Boundary Architecture

UI Boundary Architecture は、UIを見た目の大きさではなく、責務と状態所有の境界によって分割する設計手法です。

宣言的UIフレームワークで画面を作っていると、次のような状況になりがちです。

分割の基準が「大きさ」になる。 「これは大きいから親コンポーネント」「これは小さいから子コンポーネント」という判断を続けると、名前は増えるのに、それぞれが何に責任を持つのかは決まりません。結果として、すべての要素を「コンポーネント」という同じ言葉で呼ぶことになり、設計の議論ができなくなります。

状態の置き場所が、分割の基準と別々に決まる。 「この値は2箇所で使うから親へ上げる」という判断を繰り返すと、状態は自然と画面の最上位へ集まります。最上位に集まった状態は、そこから下へ props として順に渡され、途中のコンポーネントは自分では使わない値を中継するだけになります。

どこを直すと何が壊れるか分からない。 状態が最上位にあると、その値を読んでいる場所は画面のどこにでもありえます。1つ変えるたびに、確認すべき範囲が画面全体へ広がります。スパゲッティコードとして感じられるのは、多くの場合この部分です。

どこまでが再描画されるのかも分からない。 確認すべき範囲が広いことと、再描画が及ぶ範囲が広いことは、同じ原因から起きています。投稿欄に1文字入力しただけで、無関係なタイムラインの全投稿まで描き直される、という状態です。

Atomic Design を当てはめようとしたが、決められない。 部品が重複してきたので調べてみたものの、目の前の要素が Atoms・Molecules・Organisms のどれに当たるか決められない。ページ固有のUIをどこへ置くかも書かれていない。理論と実装が離れているように感じる。

はじめの4つは、どれも個々の判断としては正しく見えます。問題は、判断の基準が「大きさ」しかないことです。

こうなったページを、この文書では God Page と呼びます。状態が絡み合い、どの状態が誰に使われているのかを追えなくなったページのことです。スパゲッティコードと呼ばれる状態のうち、UIの状態が原因になっているものだと考えてください。手元にそういうページがあるなら、ほぐす手順が 第6章 適用のしかた にあります(用語は 第1章 が前提です)。

最後の1つ、Atomic Design が当てはまらないように見える理由は 第5章 既存の設計手法との比較 で扱います。先に結論を書くと、Atomic Design は悩みの半分にしか答えていません。 部品をどう分類し、どう揃えるかには答えます。答えていないのは、ページ固有のUIをどこに置くかと、状態をどこに置くかです。

UI Boundary Architecture は、大きさの代わりに「何を分けているのか」を基準に置きます。

基本となる単位は次の5つです。

Scaffold
└─ Bridge
└─ Island
└─ Component
└─ Part
単位 境界 主な責務
Scaffold Screen Boundary 画面構造と画面状態
Bridge Coordination Boundary 複数の Island の協調
Island Feature Boundary 機能とその状態
Component Interaction Boundary 操作と振る舞い
Part Presentation Boundary 表現

この分類が答えようとしているのは、次の2つの問いです。

  • この責務はどこまでか。
  • この状態を誰が所有するか。

いちばん迷いやすい ComponentPart の見分け方だけ、先に触れておきます。自分で状態を持つなら Component、持たないなら Part です。Button は押されているかどうかを持つので ComponentCard は何も持たないので Part です。詳しくは 第1章 で扱います。

5つという数は、先に決めて当てはめたものではありません。UIが引き受けている責務が、次の5種類に分かれるからです。

責務の種類 対応する単位
この画面をどう成立させるか Scaffold
機能同士がどう連動するか Bridge
ひとつの機能が何を管理するか Island
ユーザーの操作をどう解釈するか Component
受け取った情報をどう見せるか Part

このうち Bridge だけは、他の設計手法にほとんど対応するものがありません。含む・含まれるの関係では表せない「機能同士の連動」を、独立した単位として扱っているためです(→ 第5章 既存の設計手法との比較)。

この並びは、UIのサイズや複雑さを表すものではありません。

上の図で Scaffold が最上位にあるのは、含む・含まれるの典型的な関係を示すためです。Scaffold が常に大きく Part が常に小さい、という意味ではありません。

軸と凡例と目盛りを含む大きなグラフが Part であることも、画面の隅に収まる小さな通知センターが Island であることもあります。

入れ子の図は、5つすべてを必ず配置するという意味ではありません。必要な境界だけを引きます。

たとえば設定画面のように、Island 同士が何も共有していない画面では Bridge を作りません。

SettingsScaffold
├─ AccountIsland
└─ AppearanceIsland

アカウント設定と外観設定は、それぞれ独立して自分の状態を持ちます。共有する状態がないので、協調させる境界も要りません。値を1つも持たない Bridge を挟むと、追う層が1つ増えるだけです。

同じように、Island が1つしかない画面もあります。新しく作る画面は、たいてい Island 1つから始まります(→ 第6章 適用のしかた)。

たとえば、よくあるSNSのタイムライン画面は、次のように分割できます。

TimelineScaffold
├─ ComposerIsland
├─ PostSelectionBridge
│ ├─ TimelineIsland
│ │ ├─ FeedTabs
│ │ └─ PostCard
│ │
│ └─ ThreadIsland
│ ├─ PostCard
│ └─ ReplyList
└─ TrendsIsland

TimelineScaffold は画面全体を成立させます。ナビゲーション、中央のタイムライン、右側の欄を画面上のどこに置くかを決めます。

4つの Island は、それぞれ独立した機能と状態を持ちます。

Island 役割 持つ状態の例
ComposerIsland 投稿を書く 下書きの本文、添付画像
TimelineIsland 投稿を並べる スクロール位置、未読の新着件数
ThreadIsland 1件の投稿とその返信を見せる 返信を全件表示しているか
TrendsIsland いま話題になっているものを出す

これらの状態は、互いの Island からは見えません。

一方、「いま開いている投稿はどれか」は、タイムラインとスレッドの両方が必要とします。タイムラインはその投稿を強調するために、スレッドはどの投稿を展開するかを決めるために使います。

この値をどちらか一方の Island が持つと、もう一方はその Island に依存します。そこで PostSelectionBridge が所有します。

PostSelectionBridge は画面には現れません。持っているのは「この2つの Island は、開いている投稿を共有している」という関係だけです。

PostCard が2箇所に現れているのは、同じ Component をタイムラインとスレッドの両方が使っているからです。分類は要素そのものの性質で決まり、どこに置かれるかは問いません。

この手法が効果を出すのは、1つの画面に独立した機能が複数あるときです。

次のような画面には持ち込まなくて構いません。

  • 機能が1つしかない画面 — ログインフォーム、確認ダイアログのようなページ。Island が1つあるだけなので、Bridge も、Scaffold による配置の判断も発生しません
  • 状態を持たない画面 — 静的な紹介ページ、規約の表示。所有する状態がないため、状態所有の判断そのものが不要です

これらの画面に5つの単位を当てはめると、Island を1つだけ抱えた Scaffold という、名前だけの構造ができます。分割の判断が要らないところに分割の語彙を持ち込んでも、覚える名前が増えるだけです。

内容
第1章 5つの境界 5つの単位それぞれの定義、判定基準、よくある誤判定
第2章 状態所有 状態をどの単位が所有するかの決め方、所有者を移す手順
第3章 論理構造と描画構造 責務の構造と、画面上の見え方が一致しないということ
第4章 レスポンシブ設計 画面サイズによる変化を、どの単位が引き受けるか
第5章 既存の設計手法との比較 Atomic Design、Islands Architecture との違いと併用
第6章 適用のしかた 既存コードへの適用と、新規設計の進め方
第7章 ディレクトリ構成と共有 ページ固有のUIをどこに置くか、いつ共有へ移すか
第8章 分類に迷ったとき 迷ったときの判断手順

第1章は以降すべての前提です。第2章から第4章は互いに独立しているので、必要なものから読めます。

実装時に手元へ置く規則だけを抜き出した RULES.md があります。判定手順、状態の置き場所、命名、ディレクトリ、禁止事項だけを収めた版で、背景と根拠は含みません。

AI エージェントに UI を実装させる場合は、この圧縮版をプロジェクトの CLAUDE.mdAGENTS.md へ貼り付けてください。

目的 順序
ひととおり理解したい 第1章から順に
Atomic Design がうまく当てはまらなかった 第5章 → 第1章 → 第7章
ページ固有のUIの置き場所と、再利用の線引きを決めたい 第1章 → 第7章
手元のコードをほぐしたい 第1章 → 第6章
判断基準だけ確認したい 第8章のみ

この文書では、次のように書き分けます。

  • Scaffold Bridge Island Component Part — この手法における5つの単位。日本語の文中でも英字で書きます。
  • 「コンポーネント」 — フレームワークにおける一般的な構成要素。カタカナで書きます。

Component(第4の単位)と「コンポーネント」(一般語)は別のものです。すべての IslandPart も、実装上はフレームワークのコンポーネントとして書かれます。

また、画面ページも区別します。

  • 画面Scaffold が成立させる表示単位
  • ページ — ルーティングとディレクトリ配置の単位

原則として、1つのページに1つの Scaffold が対応します。