Jetpack Compose が設計を強制するもの

Jetpack Compose の登場によって、Android の設計は大きく変わりました。特に影響が大きいのが、「状態を中心に UI を組み立てる」という考え方です。

Compose では、

  • UI は状態の結果として描画される
  • 状態が変われば UI が再描画される
  • 状態を正しく持てないと UI が破綻する

という前提が、半ば強制されます。

これは単なる UI フレームワークの違いではなく、設計の中心が状態管理に移った ことを意味します。


UI State は「ドメインの投影」である

UI State は、しばしば「画面表示のためのデータ」として扱われます。しかし、本書では UI State を次のように捉えます。

UI State は、ドメイン上の判断結果を UI 用に投影したもの

つまり、UI State 自体が判断を持つべきではありません。

  • 表示してよいかどうか
  • 操作を許可するかどうか
  • 次にどの状態へ遷移するか

これらはドメイン側で決まり、その結果が UI State として表現されます。この関係を意識すると、状態管理の責務が明確になります。


非同期状態をドメインに持ち込まない

Loading / Error / Success といった非同期状態を、ドメインモデルに含めてしまう設計を見かけることがあります。しかし、これはドメインの関心事を曖昧にします。

非同期状態は、

  • 通信や I/O の都合
  • UI 表示のための必要情報

であり、ドメインそのもののルールではありません。

ドメインは「成功した結果」や「失敗の意味」を扱い、Loading かどうかは UI 側で管理する方が、責務が分離されます。


StateHolder / Reducer パターンの現実的な使い方

状態管理の手法として、StateHolder や Reducer パターンが紹介されることがあります。しかし、これらを厳密に適用しようとすると、コード量が一気に増えがちです。

本書では、次のような使い方を推奨します。

  • 状態遷移が複雑な画面に限定して使う
  • すべての画面に強制しない
  • Reducer は「状態遷移のルール」を閉じ込める場所として使う

あくまで 必要なところにだけ導入する道具 として扱うことで、設計と実装のバランスを保てます。

Reducer パターンの具体的な実装例は、別紙「参考:Reducer を使う場合・使わない場合のサンプル」を参考にしてください。


ViewModel は「状態の翻訳者」

Compose 時代の ViewModel は、単なるデータ保持クラスではありません。本書では、ViewModel を次のように位置づけます。

ドメインの判断を UI State に翻訳する存在

  • Domain → UI State への変換
  • 非同期処理の調停 (ドメイン側に非同期処理を実装しない)
  • UI からのイベントをドメインに渡す

ViewModel がこの役割に集中できていれば、UI は状態を表示することに専念できます。


状態を持ちすぎないという選択

Compose では、すべてを State として持ちたくなりがちです。しかし、状態が増えすぎると、逆に全体像が見えなくなります。

  • 一時的な UI 状態は remember で閉じる
  • 画面をまたがない状態は ViewModel に上げない
  • 永続化が必要なものだけを状態として持つ

「どこに状態を持つか」は、設計判断そのものです。State を減らすことも、立派な設計です。


この章のまとめ

Jetpack Compose 時代の Android 設計では、

  • 状態管理が設計の中心になる
  • UI State はドメイン判断の結果である
  • 非同期や表示都合をドメインに混ぜない

という整理が重要になります。

次章では、Repository の責務を Android 文脈で再定義し、どこまでを Repository に任せるべきかを見ていきます。