kbits

タールピットからの脱出――複雑性という単一の敵

原題: Out of the Tar Pit 著者: Ben Moseley、Peter Marks 公開日: 2006-02-06 ソースURL: MoseleyMarks06a.pdf アーカイブ日: 2026-06-11


要約

「タールピット(tar pit)」とは、Fred Brooksが『人月の神話』の冒頭で描いた、古代の獣たちが足を取られてもがき、もがくほど深く沈んでいった先史時代の沼の比喩である。大規模ソフトウェア開発は、まさにこのタールピットだ――そしてMoseleyとMarksは、我々をそこに引きずり込む粘性の正体を一語で名指す。複雑性(complexity)である。本論文は、その複雑性がどこから来るのかを解剖し、いかにして避け、隔離するかを論じた、関数型・リレーショナル両陣営をまたぐ設計論の古典である。

複雑性こそ唯一の本質的困難

著者らはBrooksの「銀の弾丸はない」が挙げた四つの困難――複雑性・同調性・可変性・不可視性――のうち、意味があるのは複雑性だけだと切り捨てる。残りの三つは複雑性の一形態か、複雑性ゆえに問題化するに過ぎない。信頼性の欠如も、納期遅延も、セキュリティの穴も、性能劣化さえも、煎じ詰めれば「システムを理解できない」ことに帰着する。理解こそがあらゆる問題回避の前提であり、複雑性はその理解を破壊する。DijkstraやHoare、Backus、Corbatóら歴代Turing賞受賞者の言葉を連ねながら、著者らは「単純さは難しい(Simplicity is Hard)」という不都合な真実を突きつける。

ここで言う複雑性は、計算複雑性理論(computational complexity)とは無関係であることに注意が必要だ。数行で書けるのに最高クラスの計算量を持つプログラムは「単純」でありうる。本論文の複雑性とは、人間が大規模システムを理解する際の困難さを指す。

理解の二つの様式――テストへの不信

システムを理解する方法は二つある。外側から観察するテストと、内側を吟味する非形式的推論(informal reasoning)だ。著者らは後者を圧倒的に重視する。Dijkstraの「テストはバグの存在を示せても、不在を示すことは決してできない」という洞察を引き、ある入力でのテストは別の入力での振る舞いについて何も語らないと指摘する。重要なのはバグを検出することではなく、そもそもバグを作り込まないことであり、そのためには理解を助ける単純さが、テストよりも推論よりも先に来る。

複雑性の出どころ

複雑性の主要因として、著者らは三つを挙げる。

状態(State)――最大にして最悪の原因。「再起動してみてください」「再インストールしてみてください」というサポートデスクの常套句は、すべて状態管理のバグの症状だ。可変状態は二つの様式の両方を破壊する。テストにおいては、ある内部状態で通ったテストが別の状態では無意味になる。状態が1ビット増えるごとに可能な状態数は倍増し、組み合わせ爆発を起こす。さらに厄介なのが汚染(contamination)だ――自分の手続きが状態を持たなくても、間接的にでも状態を持つ手続きを呼べば、もはや状態の文脈なしには理解できなくなる。「ラクダの鼻をテントに入れれば、全身が後を追う」。著者らは、現代の大規模システムに残る複雑性の最大の原因は状態だと断言する。

制御(Control)――物事が起こる順序のこと。a := b + 3c := d + 2 を並べたとき、プログラマは値の関係だけを言いたいのに、命令型言語の意味論は「テキストの順序=実行順序」という余計な指定を強制する。プログラマは「何が欲しいか(what)」ではなく「どう動くか(how)」を書かされ、問題を過剰指定(over-specify)させられている。読み手はこの順序が意味を持つのか持たないのかを毎回判定せねばならず、ここに微妙なバグが忍び込む。並行性はこれをさらに悪化させ、同じ入力・同じ初期状態でも再現性すら失わせる。

コード量(Code Volume)――その多くは状態と制御を扱うために書かれる二次的産物だが、測りやすく、他の原因と悪く相互作用する。Brooksが言うように複雑性はコード規模に対し非線形に増大する。ただし著者らはDijkstraに与し、状態と制御さえ管理できれば、この非線形性は崩せると見る。

これらに加え、「複雑性は複雑性を生む」「単純さは難しい」「力は腐敗する(Power corrupts)」という三原則が示される。とりわけ最後が鋭い――言語が強力であるほど(できることが多いほど)、それで書かれたシステムは理解しづらくなる。GCが手動メモリ管理という「力」を奪うがゆえに善であるのと同じく、状態という「力」を許す言語(ML、Schemeも名指しされる)には警戒せよ、と。

既存パラダイムの採点

著者らは命令型(OOPを代表例とする)・関数型・論理型の三様式を複雑性管理の観点で評価する。OOPは状態と振る舞いを密結合し、複数オブジェクトにまたがる制約に弱く、オブジェクト同一性(intensional identity)という余分な概念を持ち込む――結局は状態に依存し、その病から逃れられない。関数型は参照透過性(referential transparency)によって状態問題を根本から断ち、テストの弱点の一つを消し去る最大の武器を持つが、現実の状態を扱う段で苦しむ。Haskellのモナドは優雅な解だが、状態だらけのサブ言語を内部に作れてしまう危うさがある。論理型は「制御からの解放」という最も魅力的な約束を掲げるが、Prologは実行順序やカットといった手続き的要素でその理想から後退している。それでも各パラダイムが部分的な希望――関数型は状態の、論理型は制御の――を示している点を、著者らは見逃さない。

本質と偶発、そして理想世界

Brooksの「本質/偶発」をより厳格に再定義する。本質的複雑性とは「ユーザーから見た問題そのものに内在する複雑性」であり、それ以外はすべて偶発的複雑性だ。ユーザーが存在すら知らないもの――スレッドプール、ループカウンタ、キャッシュ――は定義上、本質ではありえない。Brooksは複雑性を本質的と見たが、著者らは「大半は偶発的だ」と反論する。

これを証明するのが「理想世界」の思考実験である。性能を気にせず、言語とインフラが完璧な支援を与える世界では、非形式的要求を形式的要求へ変換し、それをそのまま実行するだけでよい――これは宣言的プログラミングの本質に他ならない。この世界でデータを分類すると、入力データのうち将来参照されるものだけが「本質的状態」であり、派生データは可変・不変を問わず再導出可能なので、すべて「偶発的状態」と判明する。キャッシュも、導出計算の保存も、すべて偶発的なのだ。そして制御は理想世界では完全に不要となる。

回避と分離――そしてFRP

著者らの処方箋は二語に集約される。回避(Avoid)分離(Separate)。本質でない状態と制御は徹底的に避け、避けられないものは純粋なロジックから切り離せ。Kowalskiの定式「アルゴリズム = ロジック + 制御」がこの分離の精神を象徴する。性能のために偶発的状態を再導入せざるをえない場合も、それを「宣言的に指定」してインフラに管理を委ね、アプリケーションロジックが状態不整合のリスクに触れないようにする。

この原則を具現化したのがFRP(Functional Relational Programming)だ(関数型リアクティブプログラミングとは無関係なので注意)。本質的状態をCoddのリレーショナルモデルで、本質的ロジックを純粋関数で拡張したリレーショナル代数で表現する。システムは三層に分離される――(1)本質的状態(基底リレーションの定義、他を一切参照しない土台)、(2)本質的ロジック(導出リレーションと整合性制約、状態を変えない)、(3)偶発的状態と制御(性能ヒントの集合、除去しても遅くなるだけで壊れない)。この分離の真価は、各層の「力」を独立に制限できる点にある。宣言的な整合性制約は互いに参照できないため、追加しても複雑性は線形にしか増えない――メソッド間相互作用で複雑性が爆発するOOPとは対照的だ。論文は不動産仲介システムを例に、6つの基底リレーション、3つの関数、13の導出リレーション、整合性制約群、そして「PropertyInfoをキャッシュせよ」「RoomとFloorを非正規化せよ」といった3つの性能ヒントを宣言的に書き下し、机上の空論でないことを示す。

著者らは末尾でこう結ぶ――タールピットからの脱出路は、銀の弾丸は、FRPではないかもしれない。だが、それが単純さ(simplicity)であることに疑いの余地はない、と。


論評

この論文の構造そのものが、その主張を体現している。前半で「複雑性とは何か、どこから来るのか」を診断し、後半でFRPという具体的処方を示す――しかし著者らは最後の一文で、FRPはあくまで一例であって核心は単純さだと自ら相対化してみせる。この知的誠実さこそが、20年を経てなお本論文が読み継がれる理由だろう。提案された具体策(FRP)は主流にならなかったが、診断のほう――「状態が複雑性の元凶であり、本質と偶発を見分けよ」という思考の枠組み――は、その後のソフトウェア工学が歩んだ道を正確に言い当てていた。イミュータブルデータ構造の普及、React/Reduxの状態とビューの分離、イベントソーシングやCQRS、そしてRustが所有権という「制限」で状態の力を飼い慣らしたこと。これらはすべて「回避と分離」の異なる現れである。

一方で、本論文の弱点も20年の歳月が明らかにした。著者らはFRPインフラの試作がわずか1500行のSchemeで済んだと誇るが、これは楽観に過ぎる。彼らが「偶発的」として隔離した性能・制御・状態管理こそ、分散システムの時代には最も手強い本質的困難へと変貌した。ネットワーク分断、結果整合性、合意形成――これらはリレーショナル代数の優雅さの外側にあり、「インフラに任せる」と一言で片づけられるものではない。著者らが偶発的複雑性をインフラへ押し込めたとき、その複雑性は消滅したのではなく、ただ視界の外へ移動しただけだったとも言える。

それでもなお、本論文が我々に遺した最大の贈り物は、一つの問いを習慣づけたことにある。設計の現場で「これは仕方のない複雑さだ」と諦めかけたとき、立ち止まって「本当にそれは本質的か、それとも我々が持ち込んだ偶発か」と問い直す――その一拍の逡巡である。Brooksほどの巨人でさえ本質と見誤った偶発的複雑性の巨大さを暴き、状態・制御・コード量という三つの容疑者を白日の下に晒した功績は、タールピットの粘り強さに抗い続けるすべての技術者にとって、いまも灯台であり続けている。