設計の話をしていると、 よくこんな言葉を耳にします。

とりあえず作って、あとで直せばいい 実装しながら設計を詰めればいい

一見すると、合理的に聞こえます。

しかし現実には、 設計は、後から直そうとするほど難しくなっていく という現象が、ほぼ必ず起こります。

この章では、その理由を 精神論ではなく 構造の問題 として説明します。


「後戻りできない」の正体は、構造の蓄積である

設計が後戻りできなくなる理由は、単純です。

判断が、コード全体に染み出していくから です。

判断を構造として表現せずに実装を進めると、 その判断は次のような形で現れ始めます。

  • if 文として
  • 呼び出し順の前提として
  • コメントの注意書きとして
  • テストの前提条件として

つまり、 ひとつの判断が あらゆる場所に複製 されていきます。

この状態になると、 もはや一箇所を直すだけでは済みません。


最初に置いた判断が、全体の前提になる

初期段階では、設計を深く考えずに とりあえず次のようなコードを書いてしまうことがあります。

fun submit(data: Data) {
    if (data.isValid()) {
        // 処理
    }
}

このコードは、一見すると何の問題もありません。 しかし、この一行には、すでに 重要な設計判断 が含まれています。

この時点で置かれている判断は、次の二つです。

  • Data は「不正な状態」で渡される可能性がある
  • その妥当性を判断する責任は submit が持つ

つまりこのコードは、

「呼び出し元は、Data の正しさを気にしなくてよい」

という前提を、 コードの構造として表現している のです。


暗黙の前提は、静かに複製される

この前提のまま実装が進むと、 同じ考え方が別の場所にも持ち込まれます。

fun submitDraft(data: Data) {
    if (data.isValid()) {
        // 別の処理
    }
}

あるいは、

if (data.isValid()) {
    submit(data)
}

といったコードが現れ始めます。

ここで起きているのは、

  • 妥当性チェックが複数箇所に現れる
  • 「どこで判断するのか」が揺れ始める
  • 判断の責任が、構造として整理されなくなる

という状態です。

この段階では、 まだ「少し重複している」程度にしか見えません。


設計を変えたいと思ったとき、すでに遅い

しばらく実装が進んだ後で、 次のように考え直すことがあります。

実は、Data は生成時点で必ず valid にしたい submit には、正しい Data しか渡らない設計にしたい

これは、より良い設計判断 です。

しかし、この判断を構造として表現し直そうとすると、 すぐに問題にぶつかります。

  • すでに submit の中でチェックしている
  • 呼び出し側にもチェックが存在する
  • テストが「invalid な Data を渡す前提」で書かれている

つまり、

「Data は invalid かもしれない」 という判断が、 コード全体の前提として表現されてしまっているのです。

この状態では、

  • if を消すだけでは済まない
  • 前提を洗い出す必要がある
  • 影響範囲が読めない

という状況になります。

これが、

設計は後から直せない

と感じる正体です。


境界を後から引き直すのが難しい理由

境界は、

  • 依存関係
  • 呼び出し順
  • ライフサイクル

と深く結びついています。

一度、判断を曖昧なままにして実装を進めると、

  • あちこちから直接触られ
  • 暗黙の前提が増え
  • 例外的な扱いが混ざり込む

結果として、 境界を引き直すだけで大量の修正が必要 になります。

これは、 境界が単なる「線」ではなく、 構造全体の形そのもの だからです。


「設計はあとからでも直せる」は、なぜ魅力的なのか

この考え方が魅力的に見えるのは、

  • 早く動くものが見える
  • 考える時間を減らせる
  • 手戻りしている感覚がない

からです。

しかし実際には、

  • 判断を表現しない
  • 境界を定めない
  • 構造を意識しない

という 設計上の借金 を、 静かに積み上げています。


技術的負債の正体は「判断の負債」である

技術的負債という言葉は、 しばしば曖昧に使われます。

本書では、次のように捉えます。

技術的負債とは、 構造で表現すべき判断を、 人と時間に押し付けた結果 です。

  • 「ここは気をつけて」
  • 「この順番だけ守って」
  • 「この条件は暗黙で」

これらが増えるほど、 設計を修正するコストは指数関数的に増えていきます。


小さな設計は、後戻りできる

ここで重要な補足があります。

すべての設計が、 後戻りできないわけではありません。

  • 小さな関数
  • 局所的なクラス
  • 閉じたモジュール

これらは、 判断の影響範囲が小さい ため、 後から直すことができます。

問題になるのは、

  • 境界
  • 依存関係の向き
  • 状態の持ち方

といった 構造の根幹 です。


良い設計は「決断を早くする」

設計とは、 可能性を狭める行為です。

  • できることを減らし
  • 書けるコードを制限し
  • 判断を構造として表現する

これは一見、 不自由に見えるかもしれません。

しかし、この制限こそが、

  • 後から迷わない
  • 変更時に悩まない
  • 壊れにくい

という自由を生みます。


設計とは、未来の選択肢を整理すること

設計は、 未来を縛る行為ではありません。

未来の選択肢を、 安全な形に整理する行為 です。

  • 危険な選択肢を消し
  • 正しい変更だけを残す

そのために、 判断を構造として表現します。


この章のまとめ

  • 設計が後戻りできなくなるのは、判断が広がるから
  • 判断は、構造で表現しないと複製される
  • 境界や依存関係は、後から直しにくい
  • 技術的負債の正体は「判断の負債」
  • 良い設計は、決断を早くする

次の章では、 ここまでの話を踏まえて、

「では、設計はいつやるべきなのか」 ――タイミングの話に進みます。