目次を表示する

コードの考古学 ── 設計思想に宿る哲学の源流

第5話 証明できない真実 ── ゲーデルの呪いと設計の限界

場面

1930年9月7日、ケーニヒスベルク。

「数学の基礎に関する認識論の第二回会議」の三日目、討論セッションが始まった。発言者たちは互いの議論を活発に交わしていた。ダフィット・ヒルベルトへの敬意が場に漂っていた——数学界の巨人、半世紀以上にわたって形式化の夢を追い続けた老哲学者への。

ヒルベルトの夢は明快だった。数学のすべてを公理の集合から形式的に証明できるシステム——完全で(complete)無矛盾で(consistent)、**決定可能な(decidable)**システム。人間の直観ではなく、機械的な手続きによって真偽が決まる数学。1900年に掲げた「ヒルベルトの問題」の中に、この野望は刻まれていた。

討論の最後、24歳の若い数学者がほとんど独り言のように発言した。クルト・ゲーデル。その言葉を正確に聞き取った聴衆はほとんどいなかった。しかし隣席にいたヨハン・フォン・ノイマンだけが、即座にその意味を理解した。会議の後、フォン・ノイマンはゲーデルを引き留めて問い詰めた。

ゲーデルが1931年に発表した結果は、ヒルベルトの夢を数学的に葬り去るものだった。

基本的な算術を表現できる任意の形式体系において、その体系が無矛盾であれば、真であるが体系の中では証明できない命題が存在する。

どんなに公理を追加しても、その追加した公理からまた証明できない真の命題が生まれる。不完全性は不滅だ。ヒルベルトの夢は、夢でしかなかった——数学的証明によって。

五年後の1936年、アラン・チューリングが等価な結果を計算の世界で示した。停止問題(Halting Problem)——「このプログラムは有限時間内に停止するか」を一般的に判定するアルゴリズムは存在しない。工学的な困難ではなく、数学的な証明による不可能性だ。


答え

ゲーデルとチューリングが同じことを異なる言語で語った洞察は、設計者にとって解放的でもある。

「まだ解けていない」と「解けない」の間には、深淵がある。

完全で無矛盾で決定可能なシステムは、基本的な算術を超えた世界では存在できない。これはいまだ誰も作っていないというのではなく、作れないことが証明されている。その限界を認識することは、不可能な目標を追うことへの果てしない徒労から人を解放する。

限界を正確に知ることは、限界の中で最善を尽くすための前提条件だ。


CS への翻訳

ゲーデル=チューリングの不完全性は、三つの形でソフトウェア設計に顔を出している。

一つ目:静的解析の原理的限界

停止問題の証明から直接導かれる——「あらゆるバグを検出し、かつ誤検知を出さない」型チェッカーは存在できない。ライス(Rice)の定理(1951年)はさらに一般化する:非自明なプログラムの性質はすべて、一般的には決定不可能だ。

型チェッカーはいつでも二つの悪のうちひとつを選ばなければならない:見逃すか(false negative)誤って警告するか(false positive)。完璧な型システムは、ゲーデルが完璧な形式体系は存在しないと言ったのと同じ意味で、存在できない。

二つ目:CAP定理 ── 分散システム版の不完全性定理

2000年、エリック・ブルーワーが「CAP予想(CAP conjecture)」を提唱した。2002年、ギルバートとリンチが数学的に証明した。

ネットワーク分断(Partition)が発生した場合、分散システムは以下の三つを同時に満たすことができない:

  • Consistency(一貫性):全ノードが同じデータを返す
  • Availability(可用性):全リクエストが応答を受け取る
  • Partition tolerance(分断耐性):ネットワーク分断時も動作する

現実のネットワークは分断される。だから実際の選択は C と A のどちらを犠牲にするかだ。

graph TD
    subgraph "CAPの三角形"
        direction TB
        CAP["分散システムの設計空間"]
        C["Consistency\n(一貫性)\n全ノードが同じ値を返す"]
        A["Availability\n(可用性)\n全リクエストに応答する"]
        P["Partition Tolerance\n(分断耐性)\nネットワーク障害時も動作"]
    end

    CAP --> note["ネットワーク分断下では\nC と A を同時に満たせない\n(数学的証明済)"]

    subgraph "主要システムの選択"
        CP["CP システム\nZooKeeper / etcd\n分断時は応答を拒否して\n一貫性を守る"]
        AP["AP システム\nCassandra / DynamoDB\n分断時も応答を返し\n結果整合性を許容する"]
    end

    note --> CP
    note --> AP

    subgraph "哲学的系譜(インスピレーションの流れ)"
        G["ゲーデルの不完全性定理\n1931年\n完全+無矛盾の形式体系は不存在"]
        T["チューリングの停止問題\n1936年\n一般的な停止判定は不可能"]
        CAP2["CAP定理\n2002年(Gilbert-Lynch)\nC+A+Pの同時保証は不可能"]
        G -.->|同じ「不可能性」の構造| T -.->|同じ「不可能性」の構造| CAP2
    end

    style CP fill:#d4edda,stroke:#28a745
    style AP fill:#d4edda,stroke:#28a745
    style note fill:#fff3cd,stroke:#ffc107
    style CAP2 fill:#f8d7da,stroke:#dc3545

三つ目:不完全性定理が貫く共通構造

ゲーデルの証明の核心は、「この体系の中では証明できない」という命題を体系の中で構成することにある(ゲーデル数)。停止問題の証明も、「自分自身を入力として受け取るプログラム」という自己参照を使う。CAP定理の証明も、同様に二つのノードが矛盾した状態に至ることを構成的に示す。

いずれも「完全なシステムは自分自身の限界を内部から乗り越えられない」という形をしている。

第4話で見たラッセルのパラドックスは、この系譜の最初の発見だった。「自分自身を含まない集合の集合」も、ゲーデルの「証明できない命題」も、チューリングの「自分自身を入力にとるプログラム」も、すべて自己参照という同じ刃で形式体系を切り裂いている。ラッセルは型階層という「禁止令」でこの刃を封じようとした。ゲーデルは、その封じ込めを潜り抜ける刃が常に存在することを証明した。CAP定理は、分散システムの「分断」がこの刃を物理層で再現していることを示している。


設計への示唆

このことを知った設計者は、要件定義の場で根本的に異なる問いを立てるようになる。

❌ 「不可能を要件にする」という罠

要件書(ネットワーク障害時の仕様)
- 全ノードのデータは常に最新かつ同一でなければならない
- 全リクエストには必ず応答を返さなければならない
- ネットワーク障害時も動作しなければならない

CAP定理は、この三つを同時に満たすシステムを構築することは——工学的な努力の問題ではなく——数学的に不可能だと示している。これは「非常に難しい」ではない。「存在できない」だ。

この要件を受け入れたエンジニアは、不可能への取り組みを始める。どれだけ優秀であっても、どれだけ時間をかけても、数学的な壁を超えることはできない。

✅ 限界を明示し、トレードオフを選択する

設計決定(ネットワーク障害時の仕様)
選択:AP(Availability + Partition Tolerance)を優先する

根拠:
- ネットワーク分断時、ユーザーへの応答を止めることは許容できない
- 結果整合性(eventual consistency)を明示的に受け入れる
- 同期更新が失敗した場合、非同期で最終的に収束させる設計を採用する

受け入れる制約:
- 同一データを同時に参照する2ノードが、短時間(<5秒)異なる値を返す可能性がある
- 書き込みの強一貫性は保証しない
- 読み取り時に最新でない可能性をUIで明示する

この設計書は、限界を認識したうえで、その限界の中で最善の選択をしている。「一貫性を諦めた」のではない。「CAP定理の制約のもとで、この用途においてはAPが最善だと判断した」のだ。

同様のことが静的解析にも言える。

❌ 「リンターで全バグを消せる」という期待

コードレビューガイドライン
- ESLintでエラーなし → マージ可能
- 型エラーなし → 安全なコード

ライスの定理は、「型エラーなし」が「バグなし」を意味しないことを証明している。型システムは一定のクラスの誤りを確実に排除するが、すべての誤りを排除することは(定理上)できない。

✅ 何を検出でき、何を検出できないかを明示する

静的解析の役割(設計文書)
- ESLint: 構文エラー・スタイル違反を排除(偽陰性はほぼない)
- TypeScript: 型の不一致を排除(偽陰性あり:any、型アサーション)
- テスト: 仕様の通りに動作することを確認(仕様の正しさは保証しない)
- コードレビュー: 意図・文脈・ドメイン知識を確認(機械的検出不可)

残存リスク: ゲーデルの不完全性定理により、自動検出できない真のバグが
           原理的に存在し得る。多層防御と段階的デプロイで対処する。

ゲーデルが1930年のケーニヒスベルクで静かに発言したとき、彼は数学の夢を壊したのではなかった。彼は数学者たちを、不可能なものを追う徒労から解放した。

どんな形式体系も、自分自身の完全性を内側から証明することはできない。どんな分散システムも、ネットワーク分断下でCとAを同時に保証することはできない。どんな型チェッカーも、すべてのバグを見つけ、かつ誤検知なしで動くことはできない。

これらは工学的な失敗ではない。数学的な地平の端だ。

問い:あなたのシステムの要件の中に、CAP定理的な「三つを同時に満たせ」が隠れていないか。そしてそれを誰もまだ口に出していないのはなぜか。