- 状態・イベント・境界は「同じ話」をしている
- 判断とは何か —— 設計で最初に決めるべきもの
- 状態とは「判断が終わった世界のスナップショット」である
- イベントとは「判断が完了したこと」を表す構造である
- 境界とは「判断をこれ以上持ち越さない」ための線である
- Tips:Flow の各関数は「判断を閉じるための境界」である
- ViewModel は「判断済みの世界」を作る場所である
- 「状態・イベント・境界」が噛み合ったときに起きること
- この章のまとめ:名前は違うが、問いは一つである
状態・イベント・境界は「同じ話」をしている
状態設計、イベント設計、境界設計。 これらは、多くの場合、 別々の設計トピック として語られます。
しかし実装を重ねていくと、 こんな違和感を覚えたことはないでしょうか。
- 状態をきれいに設計したはずなのに、 if が消えない
- イベントを分けたはずなのに、どこで判断しているのか分からない
- 境界を引いたはずなのに、責務がにじみ出てくる
それは、あなたの設計力が足りないからではありません。
実はこれらはすべて、 同じ問いを、違う名前で考えているだけ なのです。
本書で扱ってきた
- 状態
- イベント
- 境界
は、どれも本質的には、
「判断をどこで終わらせるか」
という、ひとつの設計問題を別の角度から見たものです。
この章では、それらを一度すべて並べ、 「同じ話をしている」ことを明確にします。
そうすることで、 これまでバラバラに見えていた設計判断が、 一本の軸としてつながるはずです。
判断とは何か —— 設計で最初に決めるべきもの
この章の軸になる定義
- 判断とは
- 分岐
- 検証
- 条件評価
- 正常/異常の決定
- つまり 「複数の可能性の中から、1つに確定させる行為」
ここで強調するポイント:
- 判断は「いつまでも続いてはいけない」
- 判断が終わらない世界は
- 状態が不安定
- テストできない
- 責務が混ざる
状態とは「判断が終わった世界のスナップショット」である
本書における 状態の再定義
- 状態 = 判断がすでに完了した結果を、嘘なく表現しているもの
ここでこれまでの章と接続:
- UI State に if が多い
- nullable が意味を持ちすぎている
- 「この状態でこの画面、あり得る?」という違和感
→ それは 状態が、判断途中の世界を含んでしまっているから
イベントとは「判断が完了したこと」を表す構造である
本書における イベントの再定義
- 一般的な onClick / onTextChanged ではない
- 本書でのイベントは:
判断が完了し、その結果が境界を越えて伝えられる瞬間
ここで重要なのは:
- イベントは「判断はこれから考えてね」ではない
- イベントは「判断はもう考え終わったよ」の合図
境界とは「判断をこれ以上持ち越さない」ための線である
ここで境界の定義を統合する。
境界の例を挙げると
- View と ViewModel
- UI と Domain
- Flow の各種関数の前後
本質は共通:
この線を越えたら、もう判断させない
境界の役割を明確化:
- 境界の手前
- 判断してよい
- 境界の向こう
- 判断してはいけない
- 事実(確定情報)だけが流れる
Tips:Flow の各関数は「判断を閉じるための境界」である
Kotlin の Flow における
map や filter、onEach といった operator は、
単なる処理の連結ではありません。
本書の文脈では、 それぞれが「判断をこれ以上持ち越さないための境界」 です。
Flow は「値が流れていく仕組み」ではなく、 判断が段階的に完了していく構造 として読むことができます。
operator を一つ挟むごとに、
- それ以前の判断は、すでに終わっている
- それ以降の処理は、判断済みの結果だけを扱う
- 上流の事情を、下流が知る必要はない
という前提が成立します。
たとえば、
filter- 通すか、捨てるか、という判断を完了させる境界
map- どの形に変換するか、という判断を完了させる境界
catch- 失敗をどう扱うか、という判断を完了させる境界
です。
重要なのは、 operator を越えて判断をやり直そうとした瞬間に、設計が崩れる という点です。
下流で 「やはり別の条件で分岐したい」 「ここでもう一度 null を見たい」 と感じたなら、
それは判断の位置、 つまり 境界の引き方が間違っている というサインです。
Jetpack Compose においては、
- ViewModel 内の Flow
- 判断を完了させていく場所
- UI に届く Flow
- 判断が終わった世界の表現
であるべきです。
Flow の operator は、処理のための道具ではありません。
判断を閉じ、責任を分けるための線 それが、Flow における境界です。
ViewModel は「判断済みの世界」を作る場所である
- 一般的に想定される ViewModel の責務は:
- UI イベントを受け取ること
- onClick を処理すること
しかし、その本質は、
判断を完了させ、 状態とイベントを「判断済みの形」で外に出すこと
判断の観点で UI と ViewModel の責務を明確にすると
- UI
- ユーザー操作を通知するだけ
- ViewModel
- 判断を完了させる
- UI が受け取るのは:
- 判断済みの State
- 判断済みの Event
「状態・イベント・境界」が噛み合ったときに起きること
- if が消える
- sealed class が自然に増える
- 「この分岐どこでやる?」で迷わなくなる
- Flow の各関数の境界が説明できる
- 「なぜここで map / transform なのか」が言語化できる
→ 設計の一貫性が生まれる
この章のまとめ:名前は違うが、問いは一つである
状態を考えているときも イベントを設計しているときも 境界を引いているときも
私たちはずっと 「判断をどこで終わらせるか」 という同じ問いに答えている。