Gun Safety Is a Design Problem: What State Management Teaches About Preventing Human Error
Hatched by John Smith
Jun 03, 2026
1 min read
1 views
92%
問題は人間ではなく、システムにある
コードが壊れるたびに、つい「またやってしまった」と思ってしまう。だが本当に問うべきなのは、なぜ人は何度も同じミスをするのか、ではない。なぜそのミスが、そんなに簡単に起きてしまう設計になっているのかだ。
この視点を持つと、プログラミングの失敗も、状態管理の選択も、まったく違って見えてくる。エラーを減らすとは、気をつけることではない。そもそも間違えにくい構造を作ることである。
人はいつでもミスをする。だから優れた設計とは、ミスを想定し、それでも破綻しないように作られた設計だ。
この考え方は、日常の開発にも、ライブラリの設計にも、そのまま当てはまる。状態が増えるほど、私たちは「どこかで辻褄を合わせる」役目を自分に背負わせがちだ。だが、その辻褄合わせこそが、バグの温床になる。
何度もつまずくのは、腕前の問題ではなく、摩擦の設計が悪いから
チームで同じようなバグが繰り返されるとき、よくある反応は「レビューを厳しくしよう」「テストを増やそう」「注意喚起を強めよう」だ。どれも間違いではない。しかし、これらはすべて人間の注意力を増幅させる対症療法にすぎない。
たとえば、フォームの入力値を複数箇所で持ち回っていて、更新漏れが頻発する状況を考えてみよう。ある画面では文字列のまま保持し、別の画面では数値に変換し、さらに集計用のロジックでは独自に派生値を計算している。ここで必要なのは、開発者がもっと慎重になることではない。入力値の正体をひとつに固定することだ。
人は記憶より文脈に弱い。だから、同じ意味を持つ状態が複数の場所に散らばるほど、認知負荷は指数的に増える。どの値が真実なのか、どこを直すべきなのか、何を派生にすべきなのかを毎回判断しなければならない。そのたびに小さな判断ミスが積み重なり、最終的に「また壊れた」になる。
ここで重要なのは、ミスをゼロにしようとしないことだ。ミスは必ず起きる。だからこそ、ミスが起きても被害が局所化される設計にする必要がある。
状態は持つものではなく、分割するもの
状態管理の難しさは、単にデータを持つことではない。どの状態を一次情報として持ち、どの状態を計算結果として扱うかを見極めることにある。ここを誤ると、コードは一見動いていても、内部では常に整合性が崩れかけている。
このとき効くのが、状態を「原子」と「派生」に分ける発想だ。原子は変更の起点になる最小単位、派生はそれらから導かれる結果だ。たとえば、ショッピングカートで「商品一覧」と「合計金額」を別々に手で更新していると、どちらかがズレる。だが、合計を派生状態として扱えば、真実は商品一覧だけに集約される。
これは単なる実装テクニックではない。真実の所在を減らす設計哲学である。真実が一箇所に集まるほど、認知負荷は下がり、バグの入口も減る。
たとえば、ユーザーの名前を表示するコンポーネントが複数あるとき、各所で整形した文字列を持つより、元の名前から表示用の派生値を都度作るほうが安全だ。全員が同じ変換ルールを共有できるからだ。逆に、表示文字列を各所でコピーしてしまうと、ある画面だけ敬称が抜け、別の画面だけ大文字化が古いまま残る、という不整合が生まれる。
派生状態は、面倒な同期作業を不要にする。 それは便利だからではない。同期作業こそが、失敗の本丸だからだ。
「銃を直せ」は、責めるなという意味ではない
「自分たちが何度も足を撃っているなら、銃を直せ」という比喩は、やさしいメッセージに見えるかもしれない。だが実際には、かなり厳しい指摘でもある。なぜならそれは、失敗の原因を個人の不注意に還元するな、というだけでなく、失敗を許す構造を放置するなと言っているからだ。
ここで言う「銃」とは、壊れやすいAPI、曖昧な命名、責務の重複、散らばった状態、そして人間が間違いやすいUI設計のすべてを含む。つまり、問題はミスをした人ではなく、ミスを自然に誘発する道具立てにある。
状態管理で言えば、危険なのは「どこからでも値を書き換えられる」ことだ。自由度が高いように見えて、実際には責務の境界が曖昧になり、更新経路が増え、何がいつ変わるかを追跡しづらくなる。自由度は設計の甘さを覆い隠しやすい。だが、自由度が高いほど設計が良いわけではない。
良い設計とは、何でもできることではない。大事なことが自然にでき、危険なことがやりにくいことだ。
これはプロダクト設計にもそのまま通じる。ユーザーが迷うのは、その人の能力が低いからではない。選択肢の構造が悪いからだ。開発者が状態を取り違えるのも、慎重さが足りないからではない。状態の構造が人間の認知に合っていないからだ。
派生状態は、コードのためではなく、思考のためにある
派生状態の本質は、再計算の効率化ではない。もちろんパフォーマンス面の利点はある。だが本当の価値は、考えるべきことを減らすことにある。
人は、画面に出ている値が「どこから来たのか」を常に意識できるわけではない。しかも、状態が増えるほど、脳内でのシミュレーションは破綻しやすくなる。だから、派生状態を正しく使うと、開発者は「これを更新したら、あれも直さなければならないのか」という面倒な連鎖から解放される。
たとえば、Todoアプリに「未完了数」と「完了率」があるとする。これらを別々の状態として保持すると、チェックボックスをひとつ押すたびに、複数の値を同期しなければならない。だが、タスク一覧だけを持ち、未完了数と完了率を派生として計算すれば、更新ポイントはひとつになる。すると、コードだけでなく、設計の説明も簡潔になる。
これは重要だ。良い設計は、実装を短くするだけでなく、説明を短くする。説明が短い設計は、理解されやすく、変更されやすく、壊れにくい。
さらに言えば、派生状態は「なぜ今この値なのか」を明確にする。状態が手計算で維持されていると、その値には経緯が入り込む。だが派生であれば、値の意味は常にソースに戻れる。真実の出所がはっきりしているコードは、修正の勇気をくれる。どこを直せばいいかが明確だからだ。
バグを減らす最短ルートは、判断回数を減らすこと
優れた開発者ほど、細部まで気を配る。だが本当にスケールする設計は、個人の注意力に依存しない。なぜなら、注意力は有限だからだ。レビュー、テスト、運用、障害対応が積み重なると、人は必ず疲れる。疲れた状態で守れるルールは少ない。
だから、設計のゴールは「正しく考え続けること」ではない。正しく考えなくても、自然に正しい方向へ流れることだ。
この観点で見ると、状態管理の良し悪しは、APIの美しさ以上に、意思決定の数で測れる。ある設計が優れているかどうかは、次の質問で見極められる。
- この値は本当に保存すべきか、それとも計算すべきか。
- 更新ポイントはひとつに収まっているか。
- 同じ意味の状態が複数の場所に存在していないか。
- もしミスが起きても、どこで検出されるか。
- 変更時に人間が毎回判断しないといけない部分はどこか。
この5つに対して、明確に答えられる設計は強い。逆に、答えが曖昧なほど、その設計は人間の注意力を食い潰す。
Key Takeaways
- ミスを減らす前に、ミスが起きる構造を減らす。 注意力に頼るより、更新経路や責務の重複をなくすほうが効果的。
- 真実の所在はできるだけ少なくする。 保存すべき状態と、派生で十分な状態を分けると、同期バグが激減する。
- 派生状態は説明コストを下げる。 「なぜこの値なのか」を毎回考えなくて済む設計は、変更に強い。
- 自由度の高さを善としない。 どこからでも書き換えられる設計は、短期的には便利でも、長期的には事故を増やす。
- 良い設計は、人間の不注意を前提にする。 正しさを祈るのではなく、間違えにくさを組み込む。
直すべきなのは人ではなく、判断の多さだ
開発で本当に厄介なのは、難しい処理そのものではない。毎回その場で考えなければならない設計だ。状態が散らばり、派生が手作業で維持され、変更のたびに整合性を頭の中で再構築しなければならないなら、どんな優秀な開発者でもいつかミスをする。
だから、設計の問いはこう言い換えるべきだ。どうすれば人が頑張らなくても壊れにくくなるか。どうすれば更新の責任を最小化できるか。どうすれば真実を一箇所に閉じ込められるか。
ここまで考えると、状態管理は単なる実装の話ではなく、人間の限界を前提にした認知設計だとわかる。銃を直すとは、責めることでも、甘やかすことでもない。人は必ず撃ち間違えるという前提に立ち、その手元の道具を、撃ち間違いにくい形へ変えることだ。
そしてその原則は、コードにも、チームにも、プロダクトにも共通している。優れたシステムは、賢い人を必要としない。むしろ、賢い人がつい見落とすようなところを、最初から見落としにくくしている。そこにこそ、設計の本当の強さがある。
Sources
Hatch New Ideas with Glasp AI 🐣
Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)
Start Hatching 🐣