選定理由が失われたアーキテクチャの罠
事業の売買で、買い手のエンジニアがコードを読み始めて数日経った頃に、ぽつりと出てくる質問があります。「ここ、なんでキューを挟んでるんですか」。悪気はまったくありません。純粋に知りたいだけです。そして売り手が、しばらく黙ってから「……なんでだったかな」と答える。この一往復が、その後の交渉の温度を静かに変えていきます。
コードは残ります。動きます。ドキュメントが1行もなくても、サーバーは今日も注文を捌いて、売上を立てている。事業として、何ひとつ嘘はついていません。それでも引き継ぎの場面で決定的に足りないものがあって、それは「なぜこの構成なのか」という判断の記録です。実装は残るのに、その実装を選んだ理由だけが、どこにも残っていない。
この記事では、なぜ理由の記録だけが失われるのか、それが買い手にとって何を意味するのか、そして「立派な設計書を書く」以外の現実的な処方箋を、順番に整理していきます。
コードは「何をしているか」しか語らない

まず、当たり前すぎて見落とされる前提から始めます。
ソースコードは、驚くほど正直で、驚くほど雄弁です。何をしているかについては、一切の誤魔化しがありません。日本語のドキュメントは古びますが、コードは古びない。動いている以上、そこに書かれていることが、そのまま今の事実です。「何を」を知りたいなら、コードを読むのが最短であり、最も確実です。この点で、コードはドキュメントより信頼できます。
ただし、コードが答えられるのは、そこまでです。
なぜMySQLではなくPostgreSQLなのか。なぜここでキューを挟んでいるのか。なぜこのライブラリを選んで、当時もっと人気があったあちらを選ばなかったのか。なぜこの処理だけ同期で、隣は非同期なのか。コードに、これらの答えは書かれていません。選ばれた結果だけが書いてあって、選ばれなかった選択肢は、そもそも存在した痕跡すら残らないのです。検討して却下した、という営みは、コードの上では「何もしなかった」と完全に同じ姿をしています。
Gitがあるじゃないか、と思われるかもしれません。ところがコミット履歴も、この点ではあまり助けになりません。fix: リトライ処理を追加。これは「何を」の記録です。「なぜ」ではありません。リトライを足したことは差分を見れば分かるので、コミットメッセージは実質、差分の日本語訳をもう一度書いているだけになっている。
そして、これを責めるのは筋が違います。深夜3時に本番が燃えている最中に、判断の背景を落ち着いて文章化できる人間はいません。事業を止めないことが最優先で、それは完全に正しい優先順位です。ただ、朝が来て、火が消えて、次のタスクが積まれる。「あのリトライ回数の理由、どこかに書いておかないと」というメモは、誰の手元にも残らない。
つまり、こういう非対称性があります。実装は自動的に記録されるが、判断は意識して書かない限り、記録されない。この差が、事業の売買で牙を剥きます。
買い手が止まるのは、「変だ」と思った瞬間

買い手のエンジニアがコードを読んでいて、手が止まる場所があります。それは、汚いコードの前ではありません。意図が読めないコードの前です。
ここはよく誤解されるので、はっきり書いておきます。変数名が雑でも、関数が300行あっても、買い手はそれほど困りません。読めば分かるからです。時間はかかりますが、それは工数の問題であって、見積もれます。見積もれる問題は、価格に織り込んで終わりです。
本当に困るのは、こういう場面です。ある処理だけ、明らかに周りと違う作りになっている。他は全部フレームワークの流儀に沿っているのに、そこだけ生SQLで書かれている。キャッシュを持つ理由がなさそうな場所に、やたら複雑なキャッシュ層が挟まっている。あるいは、同じ計算が2箇所に書かれていて、微妙に結果が違う。
ここで買い手の頭の中に立ち上がる問いは、2つに1つです。
- 当時の制約の下では、これが正解だった。何かを避けるために、意図してこう書いた
- 単に、知らなかった。あるいは何かの事故でこうなったまま、放置された
そして、この2つを区別する材料が、どこにもありません。合理的な判断の結果として書かれた奇妙なコードと、無知の結果として書かれた奇妙なコードは、外形上まったく同じ姿をしているからです。前者を後者だと決めつけるのは失礼ですし、後者を前者だと信じるのは危険です。判断がつかない。
区別がつかないと、買い手はどうするか。触りません。
これも、日々の意思決定としては完全に正しい。理由が分からないコードに手を入れて、それが実は必要だった場合、壊れるのは本番です。触らなければ、少なくとも今の状態は維持されます。リスクとリターンを天秤にかけたら、触らないほうが合理的に決まっています。
ここに、この論点の本質があります。触られないコードは、改善されません。そして改善されないまま、次のOSアップデートや、次のライブラリのサポート終了や、次の法改正のときに、また同じ場所で手が止まる。1回の「触らない」は判断ですが、それが積み重なると、その領域は永久凍土になります。
買収の動機だったはずの機能追加は、凍土を避けて、その周りに増築する形で進むことになります。そして、その増築こそが、次の世代にとっての新しい謎になる。「なんでここだけ迂回してるんですか」と、また誰かが尋ねる日が来ます。理由の欠落は、こうやって複利で増えていきます。
買収前の技術的DDで本当に測られているのは、コードの美しさではありません。買った後に、そこへ手を入れられるかどうかです。そして手を入れられるかどうかを決めているのは、コードの品質ではなく、理由が読めるかどうかのほうです。
一見無駄なコードは、たいてい墓標である

ここで、実務でいちばん罪深い誤解に触れておきます。意味が分からないコードを、無駄なコードだと判断してしまうことです。
典型的なのは、こういう形跡です。
- 外部APIの、奇妙なリトライ。3回ではなく7回。教科書どおりの指数バックオフではなく、なぜか固定間隔の2秒
- 謎のsleep。処理と処理の間に、説明のつかない待ち時間が挟まっている
- 使われていないように見えるフラグ。どこからも参照されていないように見えるのに、なぜか消されずに残っている
- 特定の1社だけを分岐している条件文。ドメイン名やIDが、コードに直書きされている
- 二重に書かれた保存処理。同じデータを、わざわざ2箇所に書いている
これらは、新しく入ってきたエンジニアの目には、ほぼ確実に「掃除すべきゴミ」に見えます。実際、リファクタリングの第一候補として真っ先に挙がる。手が早い人ほど、その日のうちに消してしまいます。
ところが、こうしたコードの大半は過去の障害の墓標です。
7回のリトライは、そのAPIが月末になると必ず不安定になることを、深夜に叩き起こされて学んだ結果です。固定間隔の2秒は、指数バックオフだと相手のレート制限に引っかかることを、3回失敗して突き止めた結果です。謎のsleepは、外部サービス側の反映が非同期で、待たずに参照すると空が返るという仕様を、問い合わせても教えてもらえないまま実測で割り出した結果です。特定の1社だけの分岐は、その取引先のシステムだけが仕様外の値を返してくることへの、現場としての妥協です。二重の保存は、片方が過去に一度だけデータを落としたことがあるからです。
どれも、コードとしては美しくありません。そして、事業としては完全に正しい。
ここで思い出す価値があるのが、チェスタトンの柵という考え方です。野原の真ん中に、意味の分からない柵が立っている。「役に立っていないから」と撤去する前に、まずなぜそれが立てられたのかを説明できるようになれ、という原則です。理由を説明できないうちは、その柵を撤去する資格がない。100年前に書かれた話ですが、これほど現代のコードレビューの話をしている文章も珍しいと思います。
問題は、買い手には、その柵が立てられた理由を知る手段がないことです。理由はコードに書かれていない。障害の記憶は売り手の頭の中にある。そして引き継ぎ期間には終わりがある。だから買い手は、良かれと思って柵を抜き、半年後に、売り手が5年前に踏んだのと寸分違わぬ地雷を、まったく同じ手順で踏むことになります。
しかも、そのとき原因の特定に時間がかかります。売り手には「あのAPIは月末に落ちる」という知識がありましたが、買い手にはありません。ゼロから調査が始まる。1行のコメントがあれば起きなかった障害に、数日を溶かすことになります。
外部サービスに寄りかかった事業では、APIの利用停止のような、分かりやすくて派手なリスクばかりが議論されがちです。ただ実務でより高い頻度で効いてくるのは、こうした相手の癖に合わせて歪んだコードのほうです。派手なリスクは資料に書かれますが、歪みは誰も書きません。書くほどのことではないと、その場では思うからです。
理由は、書かなければ消える

では、なぜ理由が書かれないのか。ここも怠慢ではありません。書く動機が、その瞬間には存在しないからです。
1人で開発しているとき、判断の理由を書く相手は自分しかいません。そして自分は、たった今その判断をしたばかりなので、当然、理由を知っています。知っていることを、自分に向かって説明する文章を書く。これほど動機の湧かない作業もありません。合理的に考えて、書かないのが正解です。
問題は、この「知っている」に賞味期限があることです。
半年経つと、細部から順に薄れていきます。1年経つと、リトライを7回にしたことは覚えていても、なぜ7回だったのかは出てこなくなります。3年経つと、そのコードを自分が書いたことすら、少し疑わしくなってくる。自分が3ヶ月前に書いたコードを他人のものだと感じた経験は、たいていのエンジニアにあるはずです。
ここに、判断の理由の残酷な性質があります。「何を」はコードに書いてあるので、忘れても読み返せます。「なぜ」は頭の中にしかないので、忘れたら終わりです。バックアップの取られていない唯一のデータが、人間の記憶の中で毎日少しずつ減衰していく、という構図になっている。しかも、減っていることに本人が気づけません。
そして売却は、この減衰に締切を設定する行為です。引き継ぎ期間が1ヶ月なら、その1ヶ月で買い手が聞けた質問の分だけが引き継がれ、聞かれなかった分は永久に失われます。リポジトリの形跡から質問を組み立てられる買い手は優秀ですが、それでも聞けるのは「気づいた分」だけです。買い手が気づかなかった柵は、そのまま野原に立ち続け、いつか誰かが抜きます。
この構造は、コードに限った話ではありません。マイグレーション履歴が失われた事業で、そのカラムがなぜ足されたのかを誰も説明できなくなるのも、まったく同じ形をしています。本番に残るのは「今の姿」だけで、そうなった理由は、書かれていない限り、最初から存在しなかったことになる。
そして厄介なのは、理由が失われたことに、誰も気づけないという点です。コードが1行消えれば、テストが落ちて、誰かが気づきます。理由が1つ消えても、何も起きません。今日も明日も、システムは同じように動く。失われたことが判明するのは、数年後、他人がそのコードの前で手を止めた瞬間だけです。
処方箋は、立派な設計書ではなく1行のコメント

ここまで読んで「設計書を書かないといけないのか」と身構えた方に、先に結論をお伝えします。要りません。
この領域には、ADR(Architecture Decision Record/アーキテクチャ決定記録)という考え方があります。1つの判断につき1ファイル、短いテキストで「どういう状況で」「何を決めて」「その結果どうなるか」を書き残し、リポジトリの中でコードと一緒にバージョン管理する、という運用です。数十人、数百人の組織では、これは本当に効きます。人が入れ替わっても、判断だけが残るからです。
ただ、1人で事業を回してきた売り手に、これを今から遡ってやれというのは、控えめに言って非現実的です。5年分の判断を発掘して、フォーマットに沿って書き起こす。終わりません。そして、やる意味もそこまでありません。
買い手が知りたいのは、全部ではないからです。
フレームワークの流儀どおりに書かれた画面について、理由を聞かれることはありません。教科書と同じ形をしているものは、教科書が理由を説明してくれます。買い手が理由を知りたいのは、周りと違う場所だけです。コード全体の数パーセント、多くても十数箇所といったところでしょう。
そして、その数パーセントがどこかは、売り手が誰よりも正確に知っています。「あそこは説明しないと分からないだろうな」と思う箇所が、必ずいくつかあるはずです。その直感は、ほぼ当たります。買い手が手を止めるのは、まさにそこだからです。
やることは、その箇所に1行のコメントを置くこと。それだけです。
「何を」ではなく「なぜ普通にしなかったか」を書く
書き方のコツが1つあります。「何をしているか」は書かないでください。それはコードに書いてあります。
効かないコメントは、こうなります。
// 2秒待つ
効くコメントは、こうです。
// 外部側の反映が非同期で、即座に参照すると空が返る。1秒では足りなかったため2秒。(2023-04の障害対応)
この差は、文字数ではありません。前者はコードの繰り返しで、後者はコードに絶対に書けない情報です。前者は読んでも何も増えませんが、後者を読んだ買い手は、その場所を触りません。
ここが肝心なところで、「怖いから触らない」と「触ってはいけないと分かったから触らない」は、まったく別のことです。前者は不安で、後者は情報です。同じ「触らない」でも、価格への効き方が正反対になります。前者は謎として減点され、後者は仕様として引き継がれます。
選ばなかった選択肢を、1行だけ書く
もう1つ、強烈に効く型があります。選ばなかった選択肢を書くことです。
// 本来はマネージドのサービスを使うべきだが、当時この構成では対応リージョンが無く断念。移行するなら最初の候補。
これが書いてあると、買い手の評価は一段変わります。「知らなかったのではなく、知ったうえで選べなかった」ことが、その場で証明されるからです。しかも、買い手にとっての改善プランまで、ついでに書いてある。
レガシースタックだから一律で減点、という単純な話にならなくなるのは、まさにこの一行があるときです。同じ構成でも、「そうするしかなかった」と書かれているのと、何も書かれていないのとでは、買い手が読み取る事業の解像度がまるで違います。
買い手の側にも、聞き方の作法がある

ここまで売り手の話を書いてきましたが、買い手にも責任があります。というより、理由を引き出せるかどうかは、質問の作り方でほぼ決まります。
最悪の質問は、これです。
「なんでこんな作りになってるんですか」
技術的には至極まっとうな質問です。ただ、日本語としては、ほぼ非難です。聞かれた売り手は身構えます。そして身構えた人間の口から出てくるのは、「まあ、当時はいろいろあって」という、情報量ゼロの防御だけです。質問の仕方ひとつで、聞けたはずの話が消えます。これは相手の性格の問題ではなく、人間として自然な反応です。
効く聞き方は、前提を変えることです。
- 「この構成にしたとき、何を避けようとしたんですか」
- 「このリトライ回数、何かあって増やした感じですか」
- 「これを普通のやり方に直すとしたら、どこで詰まりそうですか」
この3つに共通しているのは、「理由があったはずだ」を前提に置いていることです。前提が肯定的だと、売り手は思い出そうとしてくれます。そして思い出した話には、ほぼ必ず、資料に一行も書かれていない一次情報が含まれている。「ああ、あれは月末だけ相手のAPIが死ぬからで」という何気ない一言が、買収後の障害を1件、確実に消します。
3つ目の聞き方が特に優秀なのは、売り手が思い出せなくても情報が取れる点です。理由を忘れていても、「そこを直すと何が起きそうか」の勘は残っていることが多い。「あー、そこは触ると多分メールが止まりますね」という一言だけでも、買い手にとっては十分な収穫です。
そして査定への織り込み方ですが、ここでも順序を守る価値があります。理由が説明されなかった箇所を、いきなり減点表に転記しないでください。それは減点表ではなく、質問リストです。
そのうえで、最後まで理由が判明しなかった箇所については、正直に見積もりへ載せます。「この領域は、当面触れない前提で価格を出します」と伝える。これは売り手に対しても誠実です。謎の量は、そのまま買い手が引き受けるリスクの量なので、価格に反映されること自体は避けられません。ただ、それを「雑な作りだから」と説明するのか、「理由が確認できなかったから」と説明するのかで、交渉のその後がまったく変わります。前者は人格の話に聞こえ、後者は情報の話で終わります。
理由を残すことは、自分の判断を守ること

最後に、売り手にとってこの作業が持つ意味を書いておきます。
理由を書き残すことは、買い手への親切ではありません。自分の名誉の話です。
長く事業を続けてきた人のコードには、必ず変な場所があります。それは、その事業が現実と何度も衝突してきたということです。教科書どおりに書けたということは、教科書どおりの状況しか起きなかったということで、5年動いた事業に、そんな幸運は訪れません。相手のAPIが仕様書どおりに動かなかった。取引先のシステムだけが違う値を返してきた。深夜に落ちて、朝までに直さないといけなかった。その一つひとつに対して、その場で持っている材料だけで最善を選んできた痕跡が、今のコードの「変な部分」です。
それは無知の記録ではなく、判断の記録です。
ただ、判断だったという証拠が、どこにも書かれていない。
そして証拠がないとき、買い手は最悪を想定します。悪意ではありません。それが買い手として正しい姿勢だからです。理由が分からない以上、無知だった可能性を排除できない。排除できない以上、価格には保守的な数字を置く。5年かけて積み上げてきた判断の履歴が、書かれていないという一点だけで、無知として値付けされる。これほど理不尽なことはありませんが、買い手が意地悪なのではなく、証拠が無いという事実の帰結です。
だから、書いてください。設計書は要りません。1つの判断につき1行で十分です。「なぜ普通のやり方をしなかったか」だけを、その場所に置いておく。
売却を考え始めた日に、自分のコードを開いて、「ここは説明が要るな」と感じる箇所を探してみてください。おそらく5箇所か10箇所くらいで、半日あれば終わります。数字を1年かけて磨いてきた人が、この半日をやらないまま交渉に臨むのは、あまりにもったいない(そして、その半日で書ける内容を全部知っている人間は、この世にあなたしかいません)。
あなたが積み上げてきた判断は、コードの中に、確かに残っています。ただ、まだあなたにしか読めない形で残っている。それを他人にも読める形へ翻訳する作業だけが、まだ終わっていないだけです。