なぜシステムは『壊れにくい更新手順』より『壊れたときに戻せる記録』を必要とするのか
Hatched by John Smith
Jul 18, 2026
1 min read
2 views
57%
変更を怖がる組織は、実は変更そのものではなく「戻れなさ」を怖がっている
ソフトウェア開発で本当に厄介なのは、新しいものを入れることではない。入れたあとに、何が起きたのかを正確に説明できないことだ。データベースの変更でも、プロトコルの変更でも、つまずく瞬間はだいたい同じである。手順が複雑だからではなく、変化の痕跡が曖昧だから、安心して次の一手を打てなくなる。
この視点で見ると、マイグレーションを生のSQLで管理したいという発想と、最小限のMCP Host, Client, Serverを自分で実装するという発想は、まったく別の話には見えない。どちらも実は、抽象化された便利さの裏で失われるものを、自分の手で取り戻そうとする試みだからだ。便利な道具が悪いわけではない。しかし、便利さが増すほど、システムの内部状態は見えにくくなり、責任の境界もぼやける。
本当に必要なのは、変更を自動化することではなく、変更が起きたときに「何が、どの順番で、なぜそうなったか」を再構成できることだ。
この記事では、データベースのマイグレーションとプロトコルの最小実装を手がかりに、システム設計における記録性、可逆性、境界の明確さという共通の問題を掘り下げる。結論を先に言えば、優れたシステムとは、最も賢いシステムではない。壊れても理解できるシステムである。
抽象化は速くするが、責任の所在を曖昧にする
フレームワークや仕様は、複雑さを隠すためにある。Rails のマイグレーション機構は、まさにその代表例だ。テーブル定義の変更、カラム追加、インデックス作成といった操作を、開発者は高級な記述で扱える。MCP のようなプロトコルも同じで、クライアント、サーバー、ホストという役割分担を定義することで、個別の実装はずっと扱いやすくなる。
だが、抽象化には必ず副作用がある。見通しが良くなる代わりに、実際に何が行われているかは遠くなる。たとえば、マイグレーションファイルをフレームワーク任せで積み上げていくと、最終的には「どういうSQLが流れたのか」を正確に把握しづらくなる。プロトコル実装でも、ライブラリが多くを肩代わりすると、メッセージの境界や責務の流れを体感しにくい。
ここで重要なのは、抽象化を捨てることではない。むしろ逆で、抽象化の下にある現実を忘れないことだ。データベースは結局 SQL を解釈する。通信は結局メッセージの順序と意味に依存する。どれほど洗練された API でも、その下には必ず「実際に起きる変化」がある。そこを見失った瞬間、障害対応は祈りに近づく。
具体例を挙げよう。カラム追加を ORM 経由で行うと、コードは短くなる。しかし本番でロックが長引いたとき、あるいは特定の DB バージョンで挙動が異なるとき、問題の核心は ORM の外側にある。生 SQL で記述しておけば、少なくとも自分がどの機能を使い、どの制約に触れているかが明確になる。これは「低レベルが正しい」という話ではない。責任の輪郭がはっきりするという話だ。
最小実装の価値は、機能を増やすことではなく境界を見える化すること
MCP の最小実装をスクラッチで行う意義も、同じ場所にある。最小限で実装することの本当の価値は、システムを小さくすることではない。どこが接続点で、どこが契約なのかを露出させることにある。
たとえば、Host が Client に指示を出し、Client が Server に問い合わせ、Server が応答する。これを完全な製品の中ではライブラリや SDK が綺麗に隠してくれるかもしれない。しかし最小実装で一度自分の手で書くと、次のようなことがはっきり見える。
- どのタイミングで状態が変わるのか
- どの情報が同期的に必要で、どの情報は後から補えるのか
- エラーはどこで発生し、誰が責任を持って扱うのか
- 仕様の「中心」がどこにあるのか
これは、マイグレーションを生 SQL で書くときの感覚と驚くほど似ている。高級なツールは「変更を適用する」ことに最適化されているが、スクラッチ実装は「変更がどう流れるか」を学ぶのに最適化されている。前者は業務に強い。後者は理解に強い。
小さな実装は、性能のためにあるのではない。複雑な世界の中で、責任の境界を一本の線として引き直すためにある。
この境界の可視化は、保守性の問題だけではない。チームの認知負荷にも関わる。抽象化が積み重なりすぎると、人は「この変更はどこまで影響するのか」を推測するしかなくなる。すると、変更は技術的な作業ではなく、心理的な賭けになる。逆に、生の SQL や最小実装のように明示的な構造を持つと、推測ではなく確認で進められる。ここに、システム設計の本質的な安心感がある。
真の設計問題は、正しさではなく可逆性にある
多くの開発者は、良い設計とは「失敗しないこと」だと考えがちだ。しかし現実のシステムは、失敗しないことを前提に運用できない。ネットワークは落ちる。DB は詰まる。仕様は変わる。人間はミスをする。だから重要なのは、失敗をゼロにすることではなく、失敗から戻れることだ。
ここでマイグレーションとプロトコル実装は、同じ問いに答えている。変更そのものよりも、変更後に「元に戻せるか」「どの状態まで遡れるか」「影響を切り分けられるか」が重要なのだ。生 SQL で管理するマイグレーションは、少なくとも自分が書いた文の集合として履歴を残す。最小実装は、余計な魔法を介さず、通信の全体像を追跡可能にする。どちらも、可逆性のための透明性を確保している。
この考え方を、日常の比喩で言い換えるならこうだ。優れた引っ越し業者は、荷物を速く運ぶだけではない。何がどこに入っていて、壊れたときにどの箱を先に開けるべきかが分かるようにする。システムも同じで、速さだけでは足りない。トラブル時に復元できる記録が必要だ。
この観点から見ると、フレームワークが提供する「自動化」は、しばしば一方向の便利さに偏る。適用は簡単でも、取消しは難しい。実装は楽でも、何が起きたかの説明は難しい。だから設計者は問いを変えるべきだ。
「どうやって楽に進めるか」ではなく、「どうやって安全に戻れるか」。
3つのレイヤーで考えると、抽象化の価値と危険が整理できる
ここで実践的なフレームワークを提案したい。変更を扱うあらゆるシステムは、次の3層で考えると理解しやすい。
1. 意図の層
何を変えたいのか。テーブルを分割したいのか、メッセージの流れを整理したいのか。ここでは高級な表現が役に立つ。人間は機械ではないので、意図を短く明快に記述できることは価値が高い。
2. 実行の層
実際に何が起きるのか。SQL は何を発行するのか。どのメッセージが誰に送られるのか。ここでは曖昧さを残してはいけない。抽象化は便利でも、最終的に作用するのは実行の層だからだ。
3. 逆転の層
問題が起きたとき、どう戻すのか。どこまで巻き戻せるのか。何をログに残すのか。ここが最も軽視されやすいが、最も重要である。成功は一度きりで済むが、失敗は何度も訪れる。
この3層で見ると、生 SQL のマイグレーションは 2 と 3 を重視する実装だと言える。最小 MCP 実装は、1 と 2 の境界を露出させる訓練になる。どちらも、ただの「原始的なやり方」ではない。抽象化された便利さを、現実に耐える形で再配線する方法なのだ。
便利なツールは、変更を速くする。だが設計者の仕事は、変更を速くすることだけではなく、変更の意味を失わないことにある。
Key Takeaways
- 変更は自動化するだけでなく、再構成可能にする。 何が起きたかを後から説明できるログや履歴を残す。
- 高級な抽象化を使うほど、下層の実体を定期的に確認する。 生成される SQL やメッセージフローを一度は目で追う。
- 最小実装は学習用ではなく境界確認の装置として使う。 役割分担、責務、エラー伝播を見える化する。
- 設計の評価軸を「失敗しない」から「戻れる」に移す。 取消し、ロールバック、再実行のしやすさを重視する。
- 意図, 実行, 逆転の3層で設計を点検する。 どの層に曖昧さが残っているかを明確にする。
結論, システムは完成度ではなく、可読な変化で評価すべきだ
私たちはしばしば、良いシステムを「よく隠れているシステム」だと勘違いする。複雑さが内部に飲み込まれ、表面だけが整っていると、たしかに気持ちはよい。しかし本当に長生きするシステムは、隠すのが上手いのではない。変化が起きたときに、その変化を読めるのである。
生 SQL でのマイグレーション管理も、最小実装のプロトコル構築も、そのための手段に過ぎない。そこに共通するのは、道具への反抗ではなく、道具に依存しすぎたことで失われる認識を取り戻す姿勢だ。私たちが守るべきなのは、抽象化された見た目の美しさではない。壊れたときに理解できること、戻れること、説明できることだ。
だから次に「もっと簡単に済ませられないか」と考えたとき、別の問いを立ててみてほしい。
この変更は、あとで読めるか。
この境界は、あとで責任を引けるか。
この失敗は、あとで戻れるか。
その問いに答えられるなら、システムはまだ生きている。
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 🐣