状態・イベント・境界は「同じ話」をしている

状態設計、イベント設計、境界設計。 これらは、多くの場合、 別々の設計トピック として語られます。

しかし実装を重ねていくと、 こんな違和感を覚えたことはないでしょうか。

  • 状態をきれいに設計したはずなのに、 if が消えない
  • イベントを分けたはずなのに、どこで判断しているのか分からない
  • 境界を引いたはずなのに、責務がにじみ出てくる

それは、あなたの設計力が足りないからではありません。

実はこれらはすべて、 同じ問いを、違う名前で考えているだけ なのです。

本書で扱ってきた

  • 状態
  • イベント
  • 境界

は、どれも本質的には、

「判断をどこで終わらせるか」

という、ひとつの設計問題を別の角度から見たものです。

この章では、それらを一度すべて並べ、 「同じ話をしている」ことを明確にします。

そうすることで、 これまでバラバラに見えていた設計判断が、 一本の軸としてつながるはずです。


判断とは何か —— 設計で最初に決めるべきもの

この章の軸になる定義

  • 判断とは
    • 分岐
    • 検証
    • 条件評価
    • 正常/異常の決定
  • つまり 「複数の可能性の中から、1つに確定させる行為」

ここで強調するポイント:

  • 判断は「いつまでも続いてはいけない」
  • 判断が終わらない世界は
    • 状態が不安定
    • テストできない
    • 責務が混ざる

状態とは「判断が終わった世界のスナップショット」である

本書における 状態の再定義

  • 状態 = 判断がすでに完了した結果を、嘘なく表現しているもの

ここでこれまでの章と接続:

  • UI State に if が多い
  • nullable が意味を持ちすぎている
  • 「この状態でこの画面、あり得る?」という違和感

→ それは 状態が、判断途中の世界を含んでしまっているから


イベントとは「判断が完了したこと」を表す構造である

本書における イベントの再定義

  • 一般的な onClick / onTextChanged ではない
  • 本書でのイベントは:

判断が完了し、その結果が境界を越えて伝えられる瞬間

ここで重要なのは:

  • イベントは「判断はこれから考えてね」ではない
  • イベントは「判断はもう考え終わったよ」の合図

境界とは「判断をこれ以上持ち越さない」ための線である

ここで境界の定義を統合する。

  • 境界の例を挙げると

    • View と ViewModel
    • UI と Domain
    • Flow の各種関数の前後
  • 本質は共通:

この線を越えたら、もう判断させない

境界の役割を明確化:

  • 境界の手前
    • 判断してよい
  • 境界の向こう
    • 判断してはいけない
    • 事実(確定情報)だけが流れる

Tips:Flow の各関数は「判断を閉じるための境界」である

Kotlin の Flow における mapfilteronEach といった 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 なのか」が言語化できる

設計の一貫性が生まれる


この章のまとめ:名前は違うが、問いは一つである

状態を考えているときも イベントを設計しているときも 境界を引いているときも

私たちはずっと 「判断をどこで終わらせるか」 という同じ問いに答えている。