抽象化が、私の見るべきものを隠していた
私はきれいな抽象化が大好きだ。雑然として複雑なものを、その散らかりを覆い隠す整然としたインターフェースで包み込み、一段高い視点で考え、下層の細部を忘れられるようにすること——そこには確かな美的快感がある。だから私は絶えず抽象化に手を伸ばした。早すぎるほど早く、熱心に、そしてあまりにも頻繁に。そして驚くほど多くの場合、私が手を伸ばした抽象化は、複雑さをまったく管理していなかった。それは、私がもっとも見る必要のあるものをまさに隠し、その特権と引き換えに新たな混乱の層を私に課したのだ。
これがつらい教訓だったのは、まさに抽象化が本当に良いもので、本当に強力だからだ。間違いは、抽象化を使ったことではない。間違いは、それを誤って使ったこと、そしてきれいな表面への愛着を、優れたエンジニアリング判断と取り違えたことだった。
良い抽象化が本来果たすべき役割
抽象化が何のためにあるのかを明確にしておく価値はある。なぜなら、この失敗のすべては、何か実在するものの歪曲だからだ。良い抽象化は、いま考える必要のない細部を隠し、散らかったもの全体を一度に頭に抱え込まずに、一段高いレベルで推論できるようにする。それはエンジニアリング全体の中でもっとも強力な道具の一つだ——おそらくは唯一無二の道具であり、一度には到底把握しきれないほど複雑なシステムを構築することを可能にするものだ。
抽象化がうまく機能しているとき、それはほとんど目に見えない。あなたは、燃焼のことを考えずに車を運転するのと同じように、下に何があるかを考えずにそれを使う。それは、あなたが実際に気にかけているレベルのために、限られた注意力を解き放ってくれる。それが理想であり、それは良い理想であり、そして実在する。だがそれこそが、この失敗モードをこれほどまでに魅力的にしているものでもある。あらゆる抽象化がこれを約束し、そのうちごく一部だけが約束を果たすのだ。
間違った抽象化が代わりにすること
悪い抽象化は良い抽象化の逆をする。しかも、外から見るとほとんど見分けがつかないまま、それをやってのける。必要のない細部を隠すのではなく、必要な細部を隠すのだ。境界を間違った場所に引くせいで、あなたが推論する必要のあるまさにそのものが、自分自身で築いた壁の向こう側に追いやられ、突然手の届かないところへ行ってしまう。
そしてそれは、最初の罪の上に第二の罪を犯す。下層にある複雑さを実際には取り除いていないのだ——その複雑さは依然としてそこにあり、手つかずのまま、表面の下でその働きを続けている。抽象化はただ、その上に新たな層を一つ加えるだけだ。だから今や、理解すべき複雑なものが一つではなく二つになる。下にある散らかった現実と、その上に被せたしっくりこない抽象化、加えて両者のあいだの常に厄介な関係だ。あなたは考えるべきものを減らそうとして、それを増やしてしまったのである。
早すぎる抽象化——理解する前にコミットしてしまう
私の間違いのもっとも一般的な形は、早すぎる抽象化だった。私は、問題を実際に十分理解して正しい構造が何であるかを知る前に、きれいで汎用的で優雅な構造を作ってしまうのだ。それは良い、先を見据えた設計のように感じられた。たいていは逆だった。
抽象化とは、根本的には、ある特定の形へのコミットメントだ——境界をどこに引くか、何を隠し何を露出させるか、各部分がどう関係するかについての決定である。そして、形づくろうとしているものを理解する前にある形にコミットすることは、間違った形を固定する確実な方法だ。さらに悪いことに、いったんそれが定着すると、あなたはその上に構築を始め、新たに作るものすべてが、学んだのではなく推測で決めた構造への投資を深めていく。早すぎる抽象化は、間違っている危険があるだけではない。それは積極的に自らの誤りを根付かせるのだ。
漏れる抽象化は、二つのものをデバッグさせる
不完全に隠す抽象化——たいていは機能するが、機能しなくなる瞬間がある抽象化——のために、特別な責め苦が用意されている。抽象化が隠すはずだった現実の奥深くで何かがうまくいかなくなったとき、その漏れはあなたに両方の層を一度に理解することを強いる。あなたが考えればよいと約束されたきれいな表面と、それが完全には隠しきれなかった下層の散らかりとを。
これは類を見ないほど消耗させる。抽象化の眼目はそもそも、あなたに一つのことだけを考えさせることだった。それがいまや、障害のせいで二つのことを考えさせられ、その上に両者のあいだの対応関係、さらにバグが実際にどちらの層にいるのかという問いまで抱え込むことになる。あなたは抽象化と、それが抽象化している当のものとを同時にデバッグしており、助けてくれるはずだった抽象化は、いまやあなたと問題のあいだに立ちはだかる余計な障害物になっている。漏れる抽象化は、抽象化が一切ないよりも悪くなりうる。なぜなら、抽象化がなければ、少なくともあなたを混乱させる層は一つだけだったのだから。
必要のなかった層のコスト
私がきちんと勘定に入れていなかったのは、抽象化のあらゆる層が、間接性の層でもあるということだ——あなたと実際に起きていることのあいだに立つ、もう一つのものだ。すべてが順調に動いているとき、その距離は利点だ。それこそが、下層を考えずに済ませてくれるものだからだ。だが理解したり、デバッグしたりする必要が生じた瞬間、その同じ距離は純粋なコストになる。各層は、あなたが見なければならないもう一つの場所であり、頭の中で行わなければならないもう一つの翻訳であり、問題が潜んでいるかもしれないもう一つの候補地なのだ。
だから、本当にその元が取れない抽象化は、中立ではない。それは恒常的な税金であり、システムについて推論しなければならないたびに課され、結局必要なかったと判明した利便性と引き換えに徴収される。私はこうした税金を熱心に積み上げていた。きれいな表面に魅了され、そのほとんどに支払いをしながら、ごく一部からしか利益を得ていないことに気づかずに。
抽象化は具体から勝ち取れ
最終的に役立った規律は、私の本能のほぼ逆だった。何が結局必要になるかについての推測から、抽象化を前もって押しつけるな。具体的で繰り返された経験から、それを勝ち取れ。まずは、その具体的で、不格好で、個別なものを何度か作ってみよ。実際の継ぎ目がどこにあるのか——自然な境界が実際にどこに落ちるのか、どの細部が本当に寄り集まり、どの細部がそうでないのか——を感じ取れ。そして、現実がその関節を示してくれてはじめて、現実が実際に引いた線に沿って抽象化せよ。
良い抽象化は、具体に押しつけるものではなく、具体から発見されるものだと、私は理解するに至った。それは、すでに深く理解しているものの圧縮であって、理解することを回避する近道ではない。私がそのやり方で作った抽象化——遅く、しぶしぶ、具体がそれらの居場所を教えてくれた後に作ったもの——こそが、実際に持ちこたえたものだった。私が早く、巧妙さと美学から作った抽象化こそが、その後何ヶ月も格闘し続けるはめになったものだった。
より深い教訓——抽象化は複雑さを管理するのであって、理解の代わりにはならない
すべては結局、抽象化が何のためにあるのかという混同に行き着く。私はそれを、問題を理解することの代用として求めていた——まるできれいなインターフェースがあれば、下層の散らかったものを実際に理解するという難しい仕事を飛び越せるかのように。それはできない。抽象化は、すでに理解している複雑さを管理するための道具であって、それを理解する仕事を回避するための道具ではない。
何かを理解していないことから、抽象化によって抜け出すことはできない。できるのはただ、自分自身の混乱を、より整って見える表面の下に隠すことだけだ。そこでそれは辛抱強く待ち、後になってあなたを待ち伏せする——いまやきれいなインターフェースをまとって。まずものを理解せよ。抽象化はその次だ。そしてそうするときには、何があるのか実際に分かる前に単に優雅に見えただけの線ではなく、理解が明らかにしてくれた継ぎ目に沿って境界を引け。
— シグナルなし、リターンなし、投資助言ではない。