オブジェクト指向設計実践ガイドの9章を読んだ(読了)

あとから自分で読み直せるように、ブログにまとめつつ読んでいます。

9章 費用対効果の高いテストを設計する

変更可能なコードを書くための3つのスキル

意図をもったテストとは

テストは慣れないうちはコストがかかるだけ、価値のないものに感じられる。 テストから優れた価値を得るためには、「テストの意図を明確にし、なにを、いつ、どのようにテストするか」という根本的な理由の理解と、それを実現するための技術が必要だ。

テストの価値を列挙すると、以下のようになる

  • バグを見つける
  • 仕様書になる
  • 設計の決定を遅らせる(変更可能性を上げる)
  • 抽象を支える(抽象的なインターフェースを具現化する)
  • 設計の欠陥を明らかにする

何をテストするかを知る

ほとんどのプログラマーはテストを書きすぎている。

不必要なテストにかかるコストはとても高く、関わっているプログラマーがテストそのものを諦めてしまうほどになる。 そうして、テストを諦めはじめても、手元には「期限の切れた役に立たないテスト(負債)」が残る。

最もコストが高く、最も利用性の低いコストは、不安定な内部の実装に結合するテストだ。 そうしたテストは、対象のクラスをリファクタリングするたびに壊れてしまう。

オブジェクト指向におけるテストは、オブジェクトの境界に入るメッセージか、出ていくメッセージに集中すべきだ。

テストすべきもののガイドラインはまとめると、以下のようになる。

  • 受信メッセージについては、その戻り値の状態
  • 送信コマンドメッセージについては、送るという挙動自体
  • 送信クエリメッセージは、テストしなくてよい

いつテストするかを知る

初級者にオススメしたいのが、「テストファーストでコードを書くこと」だ。 設計スキルがないと非常にむずかしいが、「あらゆるところで結合されきったコードを書く」という状態から卒業できる可能性がある。

ただし、初級者はまた「コストが高く重複のあるテストを、疎結合性を無視したオブジェクトのまわりにばらまきながらコードを書く」から、そのテスト自体が最終的な設計を保証するものにはなりづらい。

(書いてて胸が痛くなってきた…。)

テストの方法を知る

Rubyにおいては、MinitestかRSpecのどちらかの選択が主流だ。

テストにおいては、アプリケーションのオブジェクトを2つのカテゴリーに分けることが、考えの助けになる。

そのカテゴリーとは

  1. 自身がテストをするオブジェクト
  2. それ以外のオブジェクト

だ。

テストは、2のものについて可能な限り無知で有り続けることが望ましい。 ただし、かといって1のオブジェクト内部にどこまでもアクセスできると考えることはやめたほうがいい。テスト対象の縁沿いをとらえる視点を仮定しよう。

(縁沿い…とは…)

受信メッセージをテストする

テストダブルを作るというテクニック

テストしたい対象から、代用品として呼び出される対象やオブジェクトのことを「スタブ」と呼ぶ。 スタブはテストを高速化するために便利だが、「実際はアプリケーションが正しく動作しないのに、テストは動作する」という状態に導く可能性をもつ。

プライベートメソッドをテストする

「プライベートメソッドは書かないこと。書く場合はそれらのテストをしないこと。ただし、書く意味があるならテストしてもよい」

送信メッセージをテストする

テストしたい対象の要素が処理を行うための代用品やオブジェクトのことを、「モック」と呼ぶ。

まとめ

規則を学んだが、規則は規則であるため、ときに上手に破ることが必要だ。

設計についての強要は道具であるので、繰り返し使えば手に馴染む。目的通りの「変更に強いアプリケーション」をつくるために、ベストを尽くそう。

感想

後半のMiniTestはとりあえず挙動とやりたいことだけ見ながら読んだ。 しかし、「テストは少なくなる」とかいいつつ結構テスト書いてたように見えたんだけど気のせいだろうか。

設計の考えは一朝一夕で身につかないだろうし、読んだ知識を実践して、少しずつでも自分のアプリを「変更可能性の高いもの」にできるようがんばります。