Max Kanat-Alexander の「コード・シンプリシティ」を読みました。「Bugzillaプロジェクトの主任設計者の実体験に基づいた、ソフトウェアの簡潔性を保つさまざまな知見をまとめた書籍。」と紹介されています。
ブログを元にしているのか、Joel on Software やハッカーと画家の、もうちょいゆるい版と思うのがいいと思う。また経営者的な目線ではなくて、現場のマネージャやーリーダーの目線で書かれているという印象です。
悪いプログラマーと良いプログラマーの違いは理解力だ
プログラマの良し悪しに関する定義は、人の数だけありそうですが、ここでは理解力で。
ビジネスバリュー
ルールや指南が有効であるための前提というのが存在して、それを読み取れるか、というのは重要だと思う。この本では理解力を求めるけれど、あんまり前提に関して明確に書かれていない。だから読み取らないといけない。
ソフトウェアは人を助けるためにある
「金儲けをすること」は、個人的な目的、または組織の目的には当然なり得る。金儲けをすること自体に何ら問題はないからだ。ただ、ソフトウェアの目的にはならないだけだ。売り上げとして入る金額は、作ったソフトウェアがどれだけ人の助けとなっているか、ということと直接つながっているはずだ。
究極的には誰かが恩恵を受けていて、そのためにソフトウェアは存在する、という考え方。そうなっていなければ、そのソフトウェアには価値がない、というポジションです。特に著者はオープンソースソフトウェア開発の経験から語っているので、金銭的な利益だけに還元せずに、価値を計る方法が必要だったのだろうと勝手に邪推しています。
ソフトウェアの価値と、その大きさという指標はすごく大事だと思います。「この機能を追加すると、あるいは、この作業をすると、どんな価値が生まれるのだろう」と考えること多々あり。まだビジネス的な価値評価や、バリューチェーンが分かっていないので、常に分かるわけではないけれど、そういう視点で見るようにしています。
「こういう実装にするのが良いから」「こういう技術を使うといいから」みたいな動機だけでやらないように注意しています。ある実装方法がださださであっても、費用対効果が著しく高いのであれば、そうすべきだと考えているからです。
変更に備える
未来についてまったく予言せずに、いますぐにわかる現在の情報を元に、すべてのデザイン上の決定を行うのが最も安全だ。
これは、本論で論じてきた内容とは真逆に聞こえるかもしれないが、そうではない。デザイン上の決断を行う際、最も重要なポイントは未来だ。しかし、将来、変更ができるようにデザインを行うことと、未来を予言しようとすることは、違うことだ。
変更についていろいろ。変更しやすいけれど、特定の予想シナリオに依存しない、というのがどういうことか、また、一般的なやりかたがあるのか分かりません。分かりませんが、なかなか勇気づけられます。
最近、私が気にしているのは変更に対応しやすいコードです。要件はこの日までに、とか言ってもどうせ決まらないという諦めがあります。諦めの姿勢の是非は、今は問わないで。決められない人や、経済的な力関係で無茶してくることがあります。また、パフォーマンスのチューニングをしている過程で、やべぇこれじゃだめだ、って発見することも残念ながらあります。
そんなときに変更しやすくしておかないと泣きます。そして、最初に作っている時点では、どんな変更になるかは分かりません。
将来、要件が別に出てくる可能性を排除せずに、直近で既知の要件に基づいたデザインが必要だ。システムがしなければならないことが「X」のみであれば、いますぐその「X」ができるようにデザインしよう。未来には「X」でないことがあるかもしれないから、それを念頭に置いておけばよい。現時点でシステムは「X」だけができればよい。
古い考え方かも知れませんが、私が注意をするのは、低い結合度と高い凝集度を目指す、というものです。いきなり抽象クラスを作ったり、フレームワーク化をしません。ただ、作っているものや技術によると思います。
加減乗除ができる電卓プログラムにこの手法を使った場合、次のようになる。
- 足し算だけを行うシステムを計画する。
- 上記のシステムを実装する。
- 引き算機能を追加しやすいように作ったシステムのデザインを修正する。
- 引き算機能をシステムに実装する。足し算と引き算しかできないシステムが出来た。
- かけ算機能を追加しやすいようにシステムのデザインをさらに修正する。
- かけ算機能をシステムに実装する。足し算、引き算、かけ算だけできるシステムができた。
- 割り算機能を追加しやすくするためにシステムのデザインをさらに修正する(この時点では作業は少し、またはまったくないだろう。引き算とかけ算を実装する時点でデザインが改善されているからだ)。
- 割り算機能をシステムに実装する。これで、望んでいたシステムがそれに見合う優れたデザインで実装できた。
電卓ごときでこれをする人はいないと思いますが、私は、このやり方を好んでいます。外部から見た振る舞いやインタフェースが決定した段階では、内部の詳細な設計はできてないことが多いです。おおざっぱなデータの持ち方やロジックがある程度です。実際に作ってみたら、思ったより複雑だったり、簡単だったりします。なので、上記のようなやりかたをすることが多いです。
ただ、これは扱っている範囲が大きくなったときには、通用しにくくなることも、またありがちな話です。
いずれにしても、ショボイ機能であっても、ひとつずつ実装していきたいのには理由があって、
プロジェクトによっては、要件が複雑すぎて最初のバージョンを永遠にだすことができない、ということもある。この状況に陥ったら、機能を絞り込むことだ。
これです。ユーザに公開するかどうかは別にして、足し算までできたら、とにかくメインのブランチにマージしてしまって、本番に近い環境で動作させたいのです。そのためには、メインのブランチから離れている時間を短くしないといけなくて、さらにそのためには、断片的ではあっても動く機能をひとつずつ実装していきたいのです。
要件定義
「この仔馬が月面まで飛べるようにするにはどうしたらいい?」と誰かに訊かれたら、「解決したい問題は何か?」と質問しなければならない。この人は、実際には灰色の石を集めたいだけかもしれない。
これ聞くと嫌がられがちなので、気をつけないといけないんですけどね。それでもなんとか聞き出したいです。本当に必要な機能や作業はなんなのか、っていうのは重要です。
一方で、「ユーザを増やしたいってのが目的らしいけど、こんな機能を入れても増えませんよ」みたいな気分になっても、私は、我慢するようにしています。が、その話はまた、いつか。
まとめ
エントロピーが増大したコードを、きれいにしつつ、機能追加をしていった経験をもつ人の話は面白かったです。最初からきれいなコードを書けるのが理想ですが、実際には、そうなっていないことが多々あります。そういう実践的な立場からの教訓から学ぶことはありますね。