複雑と煩雑は違う

「このシステムは複雑だ」と言われることがある。 だがこの一言は、少なくとも3つの異なる状態を指しうる。

  1. 規模が大きく、全体の把握に時間がかかる
  2. 詳しい人でないと手を出せない
  3. 触ってみるまで、何が起きるか誰にも分からない

1と2の間には程度の差しかない。だが2と3の間には、対処法が変わるほどの断絶がある。 同じ「複雑」という語で呼んでいるかぎり、その断絶は見えない。

この文書は、その断絶がどこにあるかを特定し、 設計が守るべき境界はそこであると述べることを目的とする。

領域の呼び名と定義は「クネビンフレームワーク」に依る。本文書はそれを前提とする。

なお、クネビンをソフトウェアの結合の議論に接続したのは Vlad Khononov『ソフトウェア設計の結合バランス』(原題 Balancing Coupling in Software Design)である。 以下の複雑性の定義と結合の三次元は同書に依り、 4層モデルおよび文書との接続は本ハンドブックの解釈である。

複雑性とは、結果をいつ知れるかである

同書は結合の本題に入る前に、まず「複雑性」という語を確定させる。 システムに変更を加えようとするとき、次のどれにあたるかを問う。

変更の結果を領域
正確に言える明確系。これは複雑ではない
自分は言えないが、詳しい人に聞けば分かる煩雑系。これも複雑ではない
変更して観察するしか、知る方法がない複雑系。これが複雑性である

つまり複雑性とは量ではない。 原因と結果の関係が、事後にしか特定できないことである。

この定義が効くのは、規模と複雑性を切り離せるからである。

行数もクラス数も依存グラフの辺の数も、複雑性の指標ではない。 指標になるのは、変更の前に影響範囲を言えるかどうかだけである。

冒頭の3つの状態のうち、1と2が煩雑系、3が複雑系にあたる。 断絶はそこにあった。

結合がこの境界を動かす

同書の骨子は、結合を共有知識として捉える点にある。

2つのモジュールが結合しているとは、何らかの知識を共有しているということである。 共有された知識が変われば、共有している側すべてに変更が波及する。これがカスケード変更である。

ここが境界と接続する。

したがって結合そのものは悪ではない。モジュールが協働する以上、結合はなくせない。 問題になるのは、境界を越えさせる結合だけである。

同書はこの判定のために、結合を3つの次元で測る。

次元問い
強度どれだけの知識を共有しているか
距離共有している相手はどれだけ遠いか
変動性その知識はどれだけ変わるか

強く結びついていても、近くにあり、かつ変わらないものなら害は小さい。 弱い結合でも、遠く、頻繁に変わるものに繋がっていれば害は大きい。 結合を減らすのではなく釣り合わせるという主張は、この3次元から出てくる。

目指す先は明確系ではない

ここが最も誤読されやすい。 クネビンが出てくると「複雑系 → 煩雑系 → 明確系と登っていくのが設計の目標」と読みたくなるが、そうではない。

クネビンは梯子ではない。 5領域は状況の種類の分類であり、上下関係はない。 むしろ明確系は混沌系と崖で隣接しており、安全地帯ですらない(「クネビンフレームワーク」参照)。

意味のあるソフトウェアは明確系に入らない。 明確系は「誰にでも自明で、前例どおりにすれば済む」領域である。 そこに完全に収まるものは、自分で作る理由が薄い。既製品を買えば済む。 価値のあるシステムは、解こうとしている業務の難しさを必ず引き受ける。これは設計では消せない。

実際の境界は、煩雑系と複雑系の間にある。

明確系煩雑系複雑系
変更の影響見れば分かる調べれば分かるやってみないと分からない
必要なものなし時間と知識実験と観測
設計上の扱い目指さないここに留まる落ちたら引き戻す

煩雑系で十分である。 設計者が全体を頭に入れている必要はないし、入る規模でもない。 「調べれば分かる」が成立しているかぎり、モジュール化は機能している。

設計の目標は明確系への昇格ではなく、複雑系への転落を防ぐこと、 落ちたものを煩雑系へ引き戻すことである。

煩雑系を保つのは設計だけの仕事ではない

ここからは本ハンドブックの立場である。

煩雑系の定義は「調べれば分かる」だった。 では、この「調べれば分かる」を成立させているものは何か。2つある。

  1. 構造 — 影響がどこまで届くかを追跡できること
  2. 判断の記録 — 追跡した先を、変えてよいかが分かること

構造だけでは足りない。

LIMIT 20 を参照している箇所をすべて列挙できたとする。構造の側は健全である。 だがその 20 が業務上の判断なのか、性能上の妥協なのか、誰かの既定値がそのまま残っただけなのかが分からなければ、 変えてよいかは分からない。 「コードから何が読めるか」で述べたとおり、コードに残るのは判断の結果であって、判断そのものではない。

症状失われたもの直す場所
影響範囲を追えない構造結合の設計
影響範囲は追えるが、変えてよいか分からない判断の記録文書

両方が失われたとき、変更は「やってみて観察する」以外の方法を持たなくなる。 それが複雑系である。

したがって次が言える。

文書が失われることは、システムを煩雑系から複雑系へ落とす。

これは比喩ではなく、煩雑系の定義そのものからの帰結である。 煩雑系とは「詳しい人に聞けば分かる」状態であり、 その詳しい人が退職したあと、その席に座るのが文書だからである。 席が空いたまま埋まらなければ、定義上、そのシステムは煩雑系ではなくなる。

設計書に何が増えるか

この見方を採ると、設計書に書く項目がひとつ増える。 決定そのものに加えて、その決定の影響がどこまで届くかである。

前者は決定を記録している。 後者は決定と、その決定が引いた境界を記録している。

後任が「調べれば分かる」状態に置かれるのは後者だけである。 前者しかない設計書は、Redis を使っているという事実は伝えるが、 参照箇所を増やしてよいかどうかについては何も言わない。 そして参照箇所が静かに増えたとき、影響範囲は誰にも列挙できなくなる。

境界の記述は、越境の検出にも効く。 「ここを広げると全体の可用性になる」と書いてあれば、 それを広げる変更は設計判断として扱われ、記録される。 書いていなければ、同じ変更が実装の都合として無言で通る。 これは「層の越境パターン集」で扱った上向きの越境そのものである。

実務での判定

領域の判定は主観に頼らない。次の順で問う。

  1. この変更の結果を、変更する前に言えるか
  2. 言える人はいるか。調べれば分かるか
  3. なぜ分からないのか

3で「とりあえず動かして様子を見る」を選ぶこと自体は間違いではない。 複雑系ではそれが正しい進め方である。 問題は、そこで得た知見を記録しないと、次の人も同じ実験からやり直すことである。 複雑系での実験は、記録して初めて煩雑系への引き戻しになる。

まとめ

本ハンドブックは繰り返し「この判断は誰が検証するのか」を問うてきた。 その問いに答えられる状態が、ここでいう煩雑系である。

検証者が特定でき、判断の記録が残っているかぎり、 システムはどれだけ大きくなっても煩雑にとどまる。 複雑になるのは、規模が閾値を超えたときではなく、その問いに誰も答えられなくなったときである。