2009-05-03

明日の空模様

ある Mac プログラマから "WebKit ってドキュメントがすくないよね" という話を聞いた. WebKit の挙動が気に入らないので直せないかと調べたところ, Mozilla と比較した文書の少なさに呆れたという. 私としては連載枠が貰えたのもひとえに文書がないおかげだから, そこに不満はない. (むしろめでたい.) けれどコードを直したい人が不便なのは困ったことだ.

WebKit に比べ, Mozilla の内部は網羅的ではないにしろそれなりに文書化されている. この違いはどこから来るのだろう.

私の印象は, Mozilla が "書き直し" プロジェクトだからというものだった. Netscape は Netscape Natigator 4.x のコードベースを捨て, ほぼスクラッチから Gecko を書いたとされている. 私の仄暗い経験によれば, 書き直しのプロジェクトは最初にちゃんと "設計" をしようとする傾向がある. 素朴なソフトウェア観に従うと, あるコードベースが保守できないほど酷くなるのは, "最初にちゃんとした設計をしなかったから" だという結論されることが多い. だから次は "ちゃんと設計しよう" と考え, ドキュメントを書いたりする.

けれど, そもそもプロジェクトの開始時点ではまだ "対象を理解していなかった" と見ることもできる. ソフトウェアの扱う対象, 解こうとする問題を開発者が理解していなければ, 設計は決まりようがない. 下手に決断しても飛ばないロケットができるだけだ. 未知の問題に挑むなら多少の困難が伴うのは仕方がないこと. 理解の程度それ自体の自覚に大きなズレがないかぎりは悲観することでもないだろう.

この見方に従うと, 無知から生まれた間違いを後で正せなかった <ソフトウェアの成長不良> こそが 未知の問題に挑んだコードが保守できなくなる原因だと捉えることができる. 書き直しがうまくいくのは big design upfront の勝利ではなく経験の勝利なのだ.

だから経験を明文化する意味で文書を書くのには意味がある. けれど希望に溢れる書き直しプロジェクトの文書にそうした過去の影を見ることは少ない. あおく柔らかな芝生の眩しさばかりが目を刺す. 次世代版はポータブルなメニーコア VM 上に構築されたスケーラブルでディストリビューテッドかつモジュラーでプラッッガブルなアプケーションプラットホームですかそうですか.

口あたり

話が逸れた.

件の Mac プログラマは, 私の <二度目だから文書が多い> 説に異議を唱えた. かわりに Gecko に比べ WebKit のコードは <すっきりしている> から, ドキュメントがなくても良いんじゃないかという. WebKit コードベースのすっきり加減についてはいくらか異論があるものの, 彼の指摘は的を射ている. つまりコードのスタイルと文書化の程度には相関があるかもしれない.

柔軟性や再利用性を高めようと間接化, 仮想化, パラメタ化をすると, コードは本来の対象と少し <距離> ができる. 問題と距離のあるコードは読み手にとってわかりにくい. それは修辞や隠喩に覆われた文章と似ている. その距離を埋める手っ取り早い方法として文書が選ばれる. 設計の背後にある意図を自然言語で説明すれば, ニブチンな読み手もわかってくれるだろうというわけ.

この <距離> を単に <抽象化> と読ぶのはおそらく乱暴すぎる. 抽象が必ずしも距離をうむわけではない. 距離を縮める, 理解の助けになる抽象もある. 持ち込まれる距離は抽象によって異なる. 先の 3 つ のように柔軟性をもたらす抽象は距離をつくりやすいとおもう. ぴったりくっついていたら相手の変化に振り回されてしまうからね.

改めて眺めると, 文書が多いとされる Gecko は XPCOM ベースの仮想化過剰なコンポーネント群で, 文書のない WebKit は具象クラスと相互依存のモノリシックだ. どちらが良いかはともかく, コードから対象までの距離が短く見通しが良いという意味で WebKit のコードを <すっきりしている> と評するのはありかもしれない. 便乗して Gecko のコードはコクがある, なんてのは口から出まかせにも程があります. 識者のテイスティング求む.

目くばせ

話が逸れないうちに本題へ進もう.

不要な抽象を持ちこまないのは YAGNI の大きなテーマだ. YAGNI に従うなら, 本当に必要になるまで, つまり実際に再利用や変更がおこるまでは距離をつくる抽象を持ち込むべきでない. 一方で, 経験からいずれそうした抽象が必要になるとわかることもある. あとで変更するのが目に見えているだけに二度手間が推しい. 今のうちに抽象をつくりこみたい. 絶対必要だってば. 私のなかの博打打ちがそう告げる. でも待って. <いずれ> や <今のうちに> は典型的な YAGNI 違反の堕落ですよ. 私のなかの清教徒がすかさず咎める. 睨み合いが始まる.

結果主義と投機気質の板ばさみにあった玉虫色の私は, 結果主義者の顔をたてながら投機屋への隙を残すようになった. 実際に距離をつくることはしないが, いつでも距離をおける道を選ぶ. そして投機屋がそれに気付くことを祈る. たとえば, インターフェイスの抽出はしなしなくても具象クラスを特定する箇所(インスタンス化など)は減らしておく. 新しいクラスの抽出はしなくても関係の深いプロパティの宣言をまとめておく. メタプログラミングはしなくてもそれとなく名前づけのルールを揃えておく. データドリブンにはしなくても値の設定を局所化しておく... 投機屋なら嗅ぎ分けられる, 結果主義者には気付かれないこうしたサインを, 私は <目くばせ> と呼んでいる. 目くばせのうち運のよかったものは, やがて本物の抽象に引き上げられるだろう.

玉虫色の腰抜けながら, 目くばせには良いところもある. 目くばせは投機的抽象ほどコストが高くない. 間接化によるリーダビリティや凝集の低下, メタプログラミングに伴うデバッグのしずらさ, データ駆動にありがちなデプロイのトラブル. 目くばせはこうした面倒を招かない. また, 目くばせは博打が外れても傷が少ない. 一度持ちこんだ距離を取り除く作業は(リファクタリングブラウザの支援があってもなお)面倒になりがちだ. けれど目くばせの段階ではまだコード上に距離はない. 間違いに気付いたらひっそり取り下げればいい.

結果主義者に気付かれたために....というよりは気付かれなかったために, 目くばせを駄目にされてしまうこともある. たとえば秘めやかな規約を踏みつけて場違いな名前をつけられてしまう. 内心では宣言的なつもりだったデータの設定に分岐やループを持ち込まれてしまう. 投機屋にとっては悲しいことけれど, これは目くばせが相手をアフォードしなかった, つまり適切ではなかったと考える方が自然だろう.

目くばせと投機的抽象の違いは, コードの将来に対する負担にある. 目くばせ自体には多少の手間がかかるかもしれないけれど, そのせいで複雑さが増すことはない. 平たく言えば後腐れない. 投機的抽象は目にみえる複雑さを持ちこむ. (複雑さというのに抵抗があるなら洗練と言ってもいい.) 見通しが外れた複雑さ/洗練はゴミとして残り, コード環境を汚染しつづける.

目くばせと YAGNI に違いはあるのだろうか. 本来は同じものだと思う. ただ, YAGNI の教条主義的な側面がプログラマの経験や予感から目を逸らさせる嫌いはある. また原理主義的なアジテーションに反発する気持ちが本来の意図に水を差すこともあるだろう. そう考えると, <目くばせ> は伝言ゲームによって失なわれつつあった YAGNI の肌ざわりを 別の言葉で説明しただけなのかもしれない.

快晴

そんな話をリファクタリング原理主義者の友達に話したところ, 別の見解を教わった. (リファクタリング原理主義者とは, ソフトウェア開発を 試行錯誤による理解の螺旋 だと強く信じる一派をいう. Eclipse, VisualStudio ユーザに多い.)

彼らの立場によれば, <距離> を気にする時点で何かが間違っている. よくリファクタリングされたソフトウェアは問題に対する書き手の理解を完全に反映しているはずで, 理解を完全に反映する以上そこに <距離> はないはずだ. 柔軟性や再利用性も, それが本当に必要なら問題に含まれる. 距離の概念がはらむ投機性はない.

別の言い方をすれば, <距離> は問題の不十分な理解(または理解の不十分なコード化)を示唆している. そして <距離> の存在を許している点で投機的抽象も目くばせも大差がない. 投機的抽象は怪しいモデルを押しつけることで, 目くばせはあるべき抽象を見逃すことで, 理解とコードの関係を曇らせてしまう. だからコード上の試行錯誤によって ある瞬間/スライスの適切な抽象を, 時には抽象がいらないという理解を確かなものにして, 曖昧さの雲を晴らすべきだ.

彼はこのように主張し, 続けて訴えた: 確かな理解を得てコードの快晴を保つために必要なものは, 高い試行錯誤(=テストとリファクタリング!)の技術と, 試行錯誤こそが良いソフトウェアをつくるという信念ではないか...

曇りない快晴のコードは YAGNI に則っている. 何かが必要 <かもしれない> という曖昧さがないからだ. この YAGNI は, 私が目くばせとして正当化を試みたものより高い水準を満たすように見える. これを <目くばせの YAGNI> に対し <快晴の YAGNI> と呼ぼう. リファクタリング原理主義者が水準の高い <快晴の YAGNI> を標榜するのは自然なことだ. YAGNI は リファクタリングの論拠であり, リファクタリングは YAGNI の技術的基盤である. 絆は深い.

曇り空の下で

YAGNI には二つの顔がある.

まず不確実性という現実に折合いをつける経験則として <目くばせの YAGNI> がある. ここでは "明日できること" を "不確実で曖昧なもの" と捉える. 不確実さを強調した上で, それとどう付き合うべきかの指針を示している.

次に理想のソフトウェアをあらわす <快晴の YAGNI> がある. ここでは "明日できること" を "今日やること" の補題とみなす. そして "今日やること", つまり今ある問題への完全な理解を通じて "明日できること" の金メッキを剥ごうとする.

快晴の理想に照らされると, 目くばせが所与としたはずの曖昧さは姿を消す. けれど現実のソフトウェア開発には湧き上がる曖昧さの雲とそれを薙ぎ払う試行錯誤の戦いがあり, 空模様は二つの間の関係で決まる. おそらく多くのソフトウェアは曇天に押しやられつつ, どうにか嵐を逃れてリリースに漕ぎ着けるのだろう. 空を覆う雲は 負債 と呼ばれることもある.

リファクタリング原理主義者は, 快晴は正義であり, 商業的な成功にもつながると信じている. 信念を貫くために試行錯誤の技能を高め続けている. 私はそこまで強い信念を持つことができない. 信念を保つには試行錯誤の腕が足りない. いつも嵐の予感に怯えている. 遠い雷鳴に身を震わせ, 青空に焦がれながら雲の切れ間を追いかけて歩みを早める.