はじめに
前回は、エラーが連鎖する理由を
「状態更新と UI の境界」という構造の観点 で整理しました。
今回はその続きですが、視点を一段下げています。
構造の話ではなく、自分の実装上の“手癖" に焦点を当てます。
具体的には、
自分が一番やってしまっていた state.copy の使い方についての振り返りです。
Jetpack Compose で状態管理を書いていると、
state.copy() を使う場面はかなり多くなります。
自分も最初は「これが Compose の普通の書き方だろう」と、特に疑っていませんでした。
ただ、開発を進めるうちに、
-
直したはずのエラーが、別の画面でまた壊れる
-
状態更新を少し触っただけで、関係なさそうな UI が崩れる
という状況に、何度も遭遇するようになりました。
起きていたこと
当時のコードを振り返ると、
UI 側から直接 state.copy() を呼んでいる
画面ごとに状態更新の書き方が微妙に違う
という状態になっていました。
一つひとつを見ると問題なさそうで、
実際に build も通ります。
ただ、修正を入れるたびに
影響範囲がどこまで広がるのか分からなくなる感覚 がありました。
起きていた問題
具体的には、次のような状態です。
エラーを修正すると、別の画面で別のエラーが出る
state の構造を少し変えただけで、多数の Composable が壊れる
「どこで状態が更新されているのか」が把握しづらい
結果として、
「直したはずなのに、また壊れた」
という状況を何度も繰り返していました。
原因
結論から言うと、
state.copy() 自体が悪いわけではなく、
状態更新の責務が“手癖として”散らばっていたこと が原因でした。
UI が状態更新の方法を知ってしまっている
更新ルールが画面単位で存在している
この構造では、
一箇所の修正が別の場所に波及しやすくなります。
落ち着いた形
最終的に、次の形に整理しました。
状態更新は専用の関数に集約する
state.copy() では必要な差分だけを更新する
UI は 「値を渡すだけ」 にする
この形にしてから、
-
エラーの再発頻度
-
修正時の影響範囲
-
状態更新に対する不安感
が明らかに減りました。
なぜハマったのか(後出し)
今振り返ると、
1. state.copy() が便利すぎた
2. 動いてしまうので問題に気づきにくかった
3. 小さな修正を積み重ねやすい“手癖”になっていた
この3点が重なって、
構造的な問題に気づくのが遅れたのだと思います。
やらなくなったこと
この一件以降、次のことをやらなくなりました。
UI 側で直接 state.copy() を書く
画面ごとに更新ルールを持たせる
「とりあえずここで直す」修正
おわりに
state.copy() が悪いわけではありません。
ただ、Compose では
「どこで状態を更新させるか」 が安定性に直結します。
今回は構造の話ではなく、
自分の“手癖”を一段下げて見直した話でした。
もし、
・直したはずのエラーが何度も再発する
・修正するたびに別の場所が壊れる
という状況に心当たりがある場合は、
一度、state.copy を 『どこ』 で、『どう』 使っているかを
振り返ってみると、状況が改善するかもしれません。