ブログトップ 記事一覧 ログイン 無料ブログ開設

Strategic Choice

2014-12-19

[]セカンドシステム症候群

システムの「2番目のリリース」は、(悪い意味で)ヤバい。

どういうこと?

ファーストバージョンをリリースした開発者が設計する「セカンドバージョンのシステム」は、その開発者の設計するもっとも危険なシステムとなる傾向があります。

どうして?

ファーストバージョンでは、未知のことも多く、リスクが高いため、慎重な判断をすることが多くなります。よい機能を思いついても、「それは次回使おう」と、いったん保留されます。しかし、セカンドバージョンになると、知っていることも多く、自信もあるため、保留していたものを含め、機能を盛り込みすぎてしまいます。

機能を盛り込みすぎると、システムの実装が複雑になり、品質が悪くなります。機能そのものも複雑になり、使い勝手が悪くなるので、結局は使用されない機能となります。

また、保留していた機能を組み込んでも、ファーストバージョン時点では現実的であった機能や技術も、もはや必要とされていなくなったり、時代遅れになっているケースもあります。その部分は丸々無駄ということです。

どうすれば?

自制心を働かせ、「多機能主義」にならないようにします。

そのために有効なのは、改めて「利用者」を明確に定義し、イメージすることです。

開発者の持っている利用者のイメージは、意識的であれ無意識的であれ判断に影響を及ぼします。これが機能を追加したい欲望の「枷」になります。以下の問いを、改めて考えてみることです。

  • だれか?
  • 何を必要としているか?
  • 自分たちに何が必要だと考えているか?
  • 何を望んでいるか?

補足

「多機能主義」は、セカンドバージョンにその傾向がありますが、実はその限りではありません。例えばパッケージアプリケーションの場合などは、バージョンアップを経るごとに、どんどん「無駄に」多機能になってしまうことがあります。これは、利用者が不特定多数で、イメージしにくいことも原因と考えられます。

出典

2014-12-01

[]プログラマをコードから遠ざける例のアレ

アニメや漫画はあまり見ない方なのですが、ふとしたきっかけで「進撃の巨人」のアニメを見ました。その設定の斬新さや、緻密かつ衝撃的なストーリーに、あっというまに虜になりました。キャラクタも魅力的です。

その「進撃の巨人」で、主人公のあるセリフについて、この業界のアナロジーになっているなぁ、と思うところがありました。


簡単に「進撃の巨人」の世界を紹介します。設定だけなので、あまりネタバレはないと思います。

人類は、なぜか突如現れた大量の「巨人」たちによって捕食対象とされ、絶滅寸前までに追い込まれます。巨人は、知能はありませんが、巨大ゆえ圧倒的な体力があることに加え、ほぼ不死身*1です。人類との戦力差は圧倒的で、かろうじて絶滅を逃れた人類は、巨人が越えられない高さの「壁」を円筒状に構築します。現在、その壁の円の中で細々と暮らし、反撃の機会を伺っています。


主人公であるエレン・イェーガーは、自らに巨人に対抗しうる力を身につけるため、軍隊に志願し、訓練兵となります。3年間の巨人打倒の訓練後、卒業しますが、配属先には3部門あります。

  • 壁の外に出て、巨人の調査を行う、危険な任務の「調査兵団」。
  • 壁の中で、壁や街の警護を行う、比較的安全な「駐屯兵団」。
  • 王様の警護という名目のもと、壁の最も内側でマッタリ暮らす「憲兵団」。

慣例で、訓練成績上位10名が、優先的に、安全で快適な「憲兵団」に配属できることになっています。訓練兵はそれを目指して必死に巨人を倒す訓練に励みます。

主人公エレンは、訓練中の同期(アニ・レオンハート)との会話によって、このシステムの矛盾に改めて気づき、そのことで「憲兵団」志望の別の同期(ジャン・キルシュタイン)と口論になります。その内容です。

(エレン)「おかしいと思わねぇのか。巨人から遠ざかりたいがために、巨人殺しの技術を磨くって仕組をよ。」

(ジャン)「けど、それが現実なら甘んじる他にねぇな。」

(エレン)「だから、どうやって巨人に勝つっていうんだよ!!できるやつばっかが内側に引きこもりやがって。」

(ジャン)「俺に言われてもしらねぇよ。」

人類の最優先事項は「巨人の打倒」です。壁の中の資源は限られています。かといって、外に出れば巨人に食べられるだけです。どん詰まりです。しかし、なぜか、巨人に対抗しうる力を持った優秀なものほど、巨人から遠ざかる社会システムになっているのです。

腕の上がった人ほど、コードを書くことからリタイヤしていくのは、良いソフトウェア*2ができにくくなるので、とっても遺憾です。


主人公エレンは、(私怨もありますが、)人類のため、自由のため、巨人を「一匹残らず」駆逐することが目的です。成績上位だったにも関わらず、危険な調査兵団を志願し、実際に入団します。この「強い目的意識」というか、もう「気合」が、彼の魅力の一つです。「目的」があって、それを支える強い意志があって、目的に導かれた「手段」を選択をしています。

見習いたいです。

*1:ダメージを受けても数分で再生してしまいます。厄介です。

*2:私の「よい」の定義は「改善し続けるコトができる」です。

2014-11-28

[]テストコード:テストをやりすぎない

どういうこと?

テストのやり過ぎは、本来の目的を果たさないどころか、それを損なうことさえあります。

どうして?

テストのやり過ぎには、以下のような懸念があります。

  • テストのために、本物のコードの読みやすさを犠牲にするようになってしまう。
  • テストのカバレッジを、100%にしないと気が済まなくなる。
  • テストが神格化され、プロダクト開発の邪魔になる。

どうすれば?

テストをやり過ぎないようにします。

本物のコードをテストしやすいように設計するには、両者に利点がなければなりません。本物のコードは単純で疎結合なものにして、テストは読み書きしやすくすします。テストをしやすくするために、本物のコードにゴミを入れてはいけません。

コードの90%をテストするほうが、残り10%をテストするよりも楽です。最後の10%にはユーザインタフェースやどうでもいいエラーケースが含まれています。その部分はバグのコストが高くないので、テストが割に合いません。

現実的には、カバレッジが100%になることはありません。もしも100%になっていたとしたら、バグを見逃しているか、機能を実装していないか、仕様が変更されたことに気づいていないか、のどれかです。

バグのコストによって、テストコードにかける最適な時間は違ってきます。Webサイトのプロトタイプを作っているのであれば、テストは書かなくても問題ありません。ただ、宇宙船の制御装置や医療機器を作っているのであれば、テストに投資しなければなりません。

プロジェクトの一部にすぎないテストが、プロジェクト全体を支配している状況は異常です。おそらく、テストが、触れてはいけない神のようになっているのです。プログラマたちは、ある種の儀式としてテストを行っています。貴重なエンジニアリングの時間を犠牲にしていると自覚し、それを取り戻さなければなりません。

2014-11-27

[]テストコード:本物コードはテストに優しく

どういうこと?

本物のコードを書くときに、前もってテストを書いておいたり、前もって書かないまでも、後から書くテストを意識しておきます。

すると、面白いことに、テストしやすいような、テストに優しいコードを設計するようになります。そして、このことは、テストそのものへの好影響だけでなく、本物のコードの設計品質を飛躍的に向上させることになります。

どうして?

本物のコードは、テストに優しい設計を行うと、振る舞いごとにうまく分割されて、自然に構成されていきます。

プログラムをクラスやメソッドに分割するというのは、疎結合にしたほうがテストしやすいからです。プログラムが密結合していて、クラス間でメソッド呼び出しがたくさん行われ、メソッド呼び出しに多くの引数が必要だったらこうはいきません。プログラムが理解しにくいだけでなく、テストコードも汚くて読み書きしにくいものになっているはずです。

どうすれば?

コードを設計していて、「これをテストするのは難しそう」と思ったら、立ち止まって設計を考え直します。以下は、テストと設計の典型的な問題を示したものです。

特性テスト容易性の問題設計の問題
グローバル変数を使っている。グローバルの状態をテストごとに初期化する必要がある。
(そうしないとテスト同士が干渉してしまう。)
どの関数にどんな副作用があるのかわかりにくい。
関数を個別に考えることができない。
すべてが動くことを理解するにはプログラム全体を把握しなければいけない。
多くの外部コンポーネントに依存している。最初に足場を設定しなければいけないので、テストを書くのが難しい。
テストを書くのが楽しくないので、みんなテストを書こうとしなくなる。
依存しているものが落ちるとシステムが使えなくなる。
任意の変更にどんな影響があるのかを理解するのが難しい。
クラスのリファクタリングが難しい。
システムが考えなければいけない故障状態や回復経路が増える。
コードが非決定的な動作をする。テストは当てにならず、信頼できない。
テストが正常に動かないことがあるので、最終的に無視されるようになる。
プログラムが競合状態になったり、再現不可能なバグが発生したりする。
プログラムを論理的に判断できなくなる。
バグを追跡したり修正したりするのが非常に難しい。

一方、テストしやすい設計にしていれば、いい兆候です。以下は、有益なテストと設計の特性を示しています。

特性テスト容易性の利点設計の利点
クラスが小さい。
あるいは内部状態を持たない。
テストがしやすい。
メソッドをテストするのにセットアップがあまり必要にならない。
検査する状態が隠されていない。
状態の少ないクラスは単純で理解しやすい。
クラスや関数が1つのことをしている。完全にテストをするためのテストケースが少なくて済む。小さくて単純なコンポーネントがモジュール化されている。
システムは疎結合である。
クラスは他のクラスにあまり依存していない。
高度に疎結合化されている。
各クラスは独立してテストできる。
(複数のクラスを同時にテストするよりもずっと簡単。)
システムは並列的に開発できる。
クラスは他の部分を気にすることなく簡単に修正や削除ができる。
関数は単純でインタフェースが明確である。明確な動作をテストできる。
単純なインタフェースなのでテストが楽。
インタフェースがわかりやすくて再利用しやすい。

2014-11-26

[]テストコード:テスト名はテスト機能名

どういうこと?

テスト関数は、テストする「メソッド」や「状況」でひとまとめにします。そして、その名前は以下のようにします。

Test_<対象メソッド名>_<状況>()

どうして?

テスト関数には、テストの内容を表した名前をつけるべきです。テストコードを読む人が、以下のことをすぐに理解できるようにするためです。

  • テストするクラス
  • テストする関数
  • テストする状況やバグ

どうすれば?

テスト関数名は、テスト機能をうまく表現するように命名します。

例えば、「SortAndFilterDocs」というメソッドのテスト関数であれば、まずは「Test_」という接頭辞をつけて情報をひとまとめにします。

void Test_SortAndFilterDocs() {
	...
}

次に、状況に応じてこのテスト関数を分割するかどうかを考えます。分割する場合は、「Test_<関数名>_<状況>()」という形式にします。

void Test_SortAndFilterDocs_BasicSorting() {
	...
}

void Test_SortAndFilterDocs_NegativeValues() {
	...
}
...

長くて変な名前にならないかと怖がることはありません。他のコードから呼び出されるものではないので、長くなっても構いません。テスト関数の名前はコメントだと思えばいいのです。

ほとんどのテスティングフレームワークでは、テストが失敗したらその関数の名前が印字されるようになっています。だから、名前は説明的なほうが役に立ちます。

また、テストコードのヘルパー関数の名前は、アサートを使っているかどうかで分けるようにします。たとえば、「assert() を呼び出しているヘルパー関数は、すべて『Check...()』という名前にして、その他は普通のヘルパー関数のような名前にする」などのルールが考えられます。