「このシステムは複雑だ」と言われることがある。 だがこの一言は、少なくとも3つの異なる状態を指しうる。
1と2の間には程度の差しかない。だが2と3の間には、対処法が変わるほどの断絶がある。 同じ「複雑」という語で呼んでいるかぎり、その断絶は見えない。
この文書は、その断絶がどこにあるかを特定し、 設計が守るべき境界はそこであると述べることを目的とする。
領域の呼び名と定義は「クネビンフレームワーク」に依る。本文書はそれを前提とする。
なお、クネビンをソフトウェアの結合の議論に接続したのは Vlad Khononov『ソフトウェア設計の結合バランス』(原題 Balancing Coupling in Software Design)である。 以下の複雑性の定義と結合の三次元は同書に依り、 4層モデルおよび文書との接続は本ハンドブックの解釈である。
同書は結合の本題に入る前に、まず「複雑性」という語を確定させる。 システムに変更を加えようとするとき、次のどれにあたるかを問う。
| 変更の結果を | 領域 |
|---|---|
| 正確に言える | 明確系。これは複雑ではない |
| 自分は言えないが、詳しい人に聞けば分かる | 煩雑系。これも複雑ではない |
| 変更して観察するしか、知る方法がない | 複雑系。これが複雑性である |
つまり複雑性とは量ではない。 原因と結果の関係が、事後にしか特定できないことである。
この定義が効くのは、規模と複雑性を切り離せるからである。
行数もクラス数も依存グラフの辺の数も、複雑性の指標ではない。 指標になるのは、変更の前に影響範囲を言えるかどうかだけである。
冒頭の3つの状態のうち、1と2が煩雑系、3が複雑系にあたる。 断絶はそこにあった。
同書の骨子は、結合を共有知識として捉える点にある。
2つのモジュールが結合しているとは、何らかの知識を共有しているということである。 共有された知識が変われば、共有している側すべてに変更が波及する。これがカスケード変更である。
ここが境界と接続する。
したがって結合そのものは悪ではない。モジュールが協働する以上、結合はなくせない。 問題になるのは、境界を越えさせる結合だけである。
同書はこの判定のために、結合を3つの次元で測る。
| 次元 | 問い |
|---|---|
| 強度 | どれだけの知識を共有しているか |
| 距離 | 共有している相手はどれだけ遠いか |
| 変動性 | その知識はどれだけ変わるか |
強く結びついていても、近くにあり、かつ変わらないものなら害は小さい。 弱い結合でも、遠く、頻繁に変わるものに繋がっていれば害は大きい。 結合を減らすのではなく釣り合わせるという主張は、この3次元から出てくる。
ここが最も誤読されやすい。 クネビンが出てくると「複雑系 → 煩雑系 → 明確系と登っていくのが設計の目標」と読みたくなるが、そうではない。
クネビンは梯子ではない。 5領域は状況の種類の分類であり、上下関係はない。 むしろ明確系は混沌系と崖で隣接しており、安全地帯ですらない(「クネビンフレームワーク」参照)。
意味のあるソフトウェアは明確系に入らない。 明確系は「誰にでも自明で、前例どおりにすれば済む」領域である。 そこに完全に収まるものは、自分で作る理由が薄い。既製品を買えば済む。 価値のあるシステムは、解こうとしている業務の難しさを必ず引き受ける。これは設計では消せない。
実際の境界は、煩雑系と複雑系の間にある。
| 明確系 | 煩雑系 | 複雑系 | |
|---|---|---|---|
| 変更の影響 | 見れば分かる | 調べれば分かる | やってみないと分からない |
| 必要なもの | なし | 時間と知識 | 実験と観測 |
| 設計上の扱い | 目指さない | ここに留まる | 落ちたら引き戻す |
煩雑系で十分である。 設計者が全体を頭に入れている必要はないし、入る規模でもない。 「調べれば分かる」が成立しているかぎり、モジュール化は機能している。
設計の目標は明確系への昇格ではなく、複雑系への転落を防ぐこと、 落ちたものを煩雑系へ引き戻すことである。
ここからは本ハンドブックの立場である。
煩雑系の定義は「調べれば分かる」だった。 では、この「調べれば分かる」を成立させているものは何か。2つある。
構造だけでは足りない。
LIMIT 20 を参照している箇所をすべて列挙できたとする。構造の側は健全である。
だがその 20 が業務上の判断なのか、性能上の妥協なのか、誰かの既定値がそのまま残っただけなのかが分からなければ、
変えてよいかは分からない。
「コードから何が読めるか」で述べたとおり、コードに残るのは判断の結果であって、判断そのものではない。
| 症状 | 失われたもの | 直す場所 |
|---|---|---|
| 影響範囲を追えない | 構造 | 結合の設計 |
| 影響範囲は追えるが、変えてよいか分からない | 判断の記録 | 文書 |
両方が失われたとき、変更は「やってみて観察する」以外の方法を持たなくなる。 それが複雑系である。
したがって次が言える。
文書が失われることは、システムを煩雑系から複雑系へ落とす。
これは比喩ではなく、煩雑系の定義そのものからの帰結である。 煩雑系とは「詳しい人に聞けば分かる」状態であり、 その詳しい人が退職したあと、その席に座るのが文書だからである。 席が空いたまま埋まらなければ、定義上、そのシステムは煩雑系ではなくなる。
この見方を採ると、設計書に書く項目がひとつ増える。 決定そのものに加えて、その決定の影響がどこまで届くかである。
前者は決定を記録している。 後者は決定と、その決定が引いた境界を記録している。
後任が「調べれば分かる」状態に置かれるのは後者だけである。
前者しかない設計書は、Redis を使っているという事実は伝えるが、
参照箇所を増やしてよいかどうかについては何も言わない。
そして参照箇所が静かに増えたとき、影響範囲は誰にも列挙できなくなる。
境界の記述は、越境の検出にも効く。 「ここを広げると全体の可用性になる」と書いてあれば、 それを広げる変更は設計判断として扱われ、記録される。 書いていなければ、同じ変更が実装の都合として無言で通る。 これは「層の越境パターン集」で扱った上向きの越境そのものである。
領域の判定は主観に頼らない。次の順で問う。
3で「とりあえず動かして様子を見る」を選ぶこと自体は間違いではない。 複雑系ではそれが正しい進め方である。 問題は、そこで得た知見を記録しないと、次の人も同じ実験からやり直すことである。 複雑系での実験は、記録して初めて煩雑系への引き戻しになる。
本ハンドブックは繰り返し「この判断は誰が検証するのか」を問うてきた。 その問いに答えられる状態が、ここでいう煩雑系である。
検証者が特定でき、判断の記録が残っているかぎり、 システムはどれだけ大きくなっても煩雑にとどまる。 複雑になるのは、規模が閾値を超えたときではなく、その問いに誰も答えられなくなったときである。