本質的な複雑さ批判
森田が大ファンであるところの Dan Luu が「人月の神話」の Fred Brooks をディスる 記事を書いており、 痛快なのでみんなでこれ読んで与太話しようぜ、という回。(Dan Luu のページは Pocket か Instapaper 必須なのでみなインストールされたし。)
ここで批判されているのは Brook の Essential Complexity / Accidental complexity に関する記述。 極めて雑に復習すると、Brooks は「問題には “essential complexity” すなわち “本質的な複雑さ” というのがあるから、 プログラミング言語とかツールとか計算機性能の改善とかで “accidental complexity” / “偶発的な複雑さ” を減らしていっても限度があるよね、 ソフトウェア開発って難しいですね・・・という話だった。
Dan Luu はそんなわけねーとこの主張を一蹴し、自身の仕事から反例を二つ引き合いに出す。 森田に馴染みある方の例はこんなかんじ: オープンソースの分散 OLAP DB Presto に保存されている モニタリングのデータ相手に SQL を書き、結果を R で ggplot する。 Presto の性能、SQL の宣言的な簡潔さと ggplot の表現力は明らかに仕事を桁違いに簡単にして、問題の偶発的な複雑さを粉砕している。
一方で、と話は続く: Presto と ggplot が吹っ飛ばいた偶発的複雑さの量はすごいけど、一方でいま更に速いコンピュータがあったら 俺が遭遇した残りの偶発的複雑さも消し飛ばせるんだけどなーと愚痴タイムに突入し、 字数が足りないといいつつ Presto と ggplot の残念バグを次々に列挙してしていく(ここが一番楽しい)。
話の肝はこうだ: Brooks は偶発的な複雑さを倒しても本質的な複雑さが立ちふさがるから無駄といったけど、 この問題なんてちょろい SQL を書く本質的な複雑さは皆無にも関わらず Brooks 現役時代の 1986 年には偶発的な複雑さが桁違い過ぎて解こうとすら思われない類の問題でしょ、 テクノロジの進歩で解ける問題変わってるじゃん。
本質的な複雑さの占める割合ゆえに計算機が速くなって偶発的な複雑さを倒しても有り難みは薄いという Brooks は想像力を欠いていた。 1986 年の計算機は桁違いに遅かった。スクリプト言語も GC もメインストリームではなかった。 Brooks は計算機の遅さやテクノロジの未熟さに伴う偶発的な複雑さによって誰も解こうとしない類の問題が無限にある事実に目を向けるべきだった。 Brooks に限らず昔の人の話は想像力が足りてことがよくある。眉唾せよ。Dan Luu はそんなかんじで話を締めくくっている。
複雑さの属性
「人月の神話」の知名度を「本質的な複雑さ」なるフレーズが持つミームの強さが手伝い、 これを引き合いに出して偉そうなことを言う人はいまでも少しはいるだろう。 だから今更でも釘を差しておく Dan Luu はいい仕事をしたと思う。
とはいえ「人月の神話」とかさすがに大昔すぎて、この「本質的」「偶発的」の二項対立に付き合って話を続けるのも忍びない。 Dan Luu も脚注で「本質的と偶発的の区別とかあんまし意味ないよね」と Michael Feathers の Tweet を紹介している。 (最近 blog 書いてないと思ったらソーシャルメディアで時間を溶かしていたのか Feathers! それより 本書いて!)
ここで一歩下がって考える:「本質的/偶発的」という切り口はいまいちだけれど、 眼の前の複雑さが持つ「属性」に目を向けて打ち手を選ぶのはそれなりに意味のあるヒューリスティクスに思える。
たとえば自分は複雑さの「局所性」について気にすることが多い。 局所的な複雑さ・・・たとえばこのアルゴリズムが難しい、このコンポーネントのコードがゴミすぎる・・・みたいのは、 割と個人の努力でやっつけられる。仕事で成果を出したいなら、 目についた複雑を局所性でソートして個人に力量で倒せそうないちばんでかいやつ、 つまりいちばん局所的でないやつ、に取り掛かるのが良い。
局所性の高い(同時に濃度も高い)複雑さは、少人数でやっつけられる割にやっつけるとかっこいい。なので Enginering blog などで華やかに語られがちである。局所性の低い複雑さはしんどい割に解決への道筋が地味なので、表舞台に現れない。放置も多い。
別の言い方をすると: 局所性の高い複雑さは目立つので、みな熱心に取り組む。だからただ指摘すればよい。誰かがやってくれる。 局所性の低すぎる、つまりコードベース全体にベローンと薄く広がっている複雑さは、組織の力がないと倒せない。下っ端には荷が重い。
だから局所性の両端は他人に譲り、自分は中間くらいにある仕事を探したい。
局所性の低い複雑さの例: 昔 C++ なブラウザの仕事をしていた頃、コードベースのスレッドの扱いにはいつも苦しめられていた。Controller ぽいクラスが複数のスレッドから参照されるのだが、いまいちどのメソッドがどのスレッドから呼ばれうるのかわからない。オブジェクトを bind して thread pool に投げるイディオムが、このマルチスレッドの壊れやすさを助長していた。もうちょっと message passing ぽく実装するなり immutable なオブジェクトを増やすなり手堅いマルチスレッドのコードを書くパターンは色々あるわけだが、少なくとも当時はそういう配慮はみられなかった。結果として森田はいつも race condition で苦しんでいた。(当時の愚痴.)
今の仕事である Android アプリの Java コードはマルチスレッドだが、もうちょっと安全に書かれておりそこまで race の辛さはない。一方、何かとブロッキングの API を呼んだりロックを待ったりするので、同期にともなう性能劣化に苦しめられている。先のブラウザのコードは non-blocking なコードが支配的なのでこうした問題は起きにくい。
こういうプロジェクトに染み渡ったコーディングのパターンみたいのは局所性が低い。C++ でも Java でも非同期かつスレッドセーフなコードを書く方法は定番が広く知られているので、この問題を解決しても特にかっこよくはない。一方でこの複雑さを倒すにはコードをくまなく書き換え同時に新しいダメコードの発生を抑制する必要がある。しんどい。個人で戦える範囲を超えている。だからこういう問題には近づかず、心を無にしてやりすごすと決めている。大局的だと思っていた問題がクールな発明で局所的に解決できるケースも稀にあるが、加齢にともないそういう博打はしなくなった。こいつらを ScyllaDB の Seastar で書き直すぞ!スレッドセーフでノンブロッキングだ!とか言えればかっこいいんだけどさー。
というわけで「複雑さの局所性」を森田は割と気にしている。そういう empirical(与太話的) な複雑性の指標は誰もが持ってると思うんですけど、 和良さんとかどうですか。