日々の記録。

プログラミングのメモや感じた事などを記録。

Kent beckのテスト駆動開発を読んで

読んだ本

著者: Kent beck タイトル: テスト駆動開発 第2版

読んだ動機

色々なアジャイルの本(例えばアジャイルサムライやエクストリームプログラミング)で「自動テスト」が出てくるので、改めてKent beckの原典を読んでみようと思った。

TDDについての情報

Kent beckは、エクストリームプログラムを世に出した人。xUnitの最初のsUnit(Smalltalk unit)の作者の一人。 TDDは「テスト駆動開発」の略。読む前のイメージは「自動テストを書いてから実装する」・・・それだけ。

読み進めるにあたり関心のある点

  • TDDの目的
  • テストコードの管理について
  • 他人のテストコードについて
  • GUIのテスト、DBのテスト,マルチスレッドなどの非同期や並列処理のテスト(あったらいいな程度で期待はしていなかった)

こんなところに興味を持って読んでみた。

得られた知見

TDDの目的

この本から感じたことは、TDDはテストにあらず。実装を早く行い設計を継続的に改善するための開発手法。いわゆる「製品のテスト」との代替ではないということを感じた。

実際、書籍には以下のように書かれている。

TDDはテスト技法ではない(Cunninghamの公案)。 TDDは分析技法であり、設計技法であり、実際には開発の全てのアクティビティを構造化する技法なのだ。(p278)

しかし、p188にはこんな記述もある。

どうやってソフトウェアをテストすれば良いのだろう〜自動テストを書こう。

‥‥

TDDの手法

before TDD

昔々の20年近く前の開発・・・C言語で開発をしていた頃を思い出すと次のステップになる。

  1. 数百行のソースコードを書いてコンパイル
  2. さらにx倍のコードを書いて機能を一通り書く。コンパイル
  3. さあ動作確認
  4. デバッグ
  5. 修正 (以下3~5をエンドレスで繰り返す)

「テストをしていない関数」を使って「大きな機能」を実装して、さらに「そのテストをしていない大きな機能」を使って別の機能を実装する・・・当然バグが出まくる。デバッグに時間がかかる。そんな環境を知っている。

after TDD

TDDの手法は上の方法の真逆を行く。 (テストコードではない、製品やサービスのためのコードを「製品コード」とします)

  1. まずはテストを1つ書く
  2. 全てのテストを走らせ、新しいテストの失敗を確認する
  3. 小さな変更を行う(意訳:製品コードを書いたり変更したりする)
  4. 全てのテストを走らせ、全て成功することを確認する
  5. リファクタリングを行って重複を除去する (p1)

私がこの本を読んで最も大切と感じたことは「テストコードを使って製品コードを細かく動かすことで、「動作していない製品コード」をできるだけ無くす。」ことだ。動かしていないコード(私はこれをよく「絵に描いた餅」と言っている)ではなく、「動くコード(テストをpassしたコード)を使って「より大きな機能の実装」に取り組む」ことができる。(書きかけ。)

次に印象に残った事は、TDDの流れでは「リファクタリングを行って重複を除去する」というステップが伴っていること。私の経験上では、実際のプロジェクトでは1~5の手順に乗っ取るのではなく3,4のみのものばかりに遭遇する(実際には4もない)。設計もなく設計の見直しもなく3ばかりだったら、そのプロジェクトはやばい兆候だと思う。(書きかけ)

テストコードの管理について

私自身が感じているテストコードについての課題として、「プロダクトコードを複数人が入れ替わりで触っている環境で、今はいない誰かが書いたコードをメンテナンスしないといけない状況になった時、存在するテストコードをどこまで信じて良いのだろう? テストがpassしている事は分かる・・・けどそもそも内容も把握できていない何百のテストを信じて良いのだろうか?」という課題がある。それに対してヒントがあるかと思ったけど、やっぱり記載がなかった。

これは私の所感になるけど、結局テストコードを適切に維持するには、テストコード以前に、製品コードが適度にモジュール化されていて(クラスでもライブラリでも言い方はなんでも良い)、そのモジュールの責任範囲が明確になっていて、その責任範囲に置いて「これをテストする」という事が明確になっていなければ、テストコードの維持管理はできないのではないだろうか?

今携わっている環境で感じる事は、

  1. 数百のテストコードが何をしているか分からない
  2. そもそもテスト対象のクラスの責任範囲が分からない(1クラスが数千行のコードからなる)

つまるところモジュール化が行われていない環境でテストコードを作成していても、テストコードの管理はほぼ不可能と感じている。(そもそも製品のコードが管理できていないのに、テストコードの管理は時期尚早なのかもしれない)

この本への不満

  • 著者の暗黙知による話が多い
    • 本文中には、「目指すのは動作する綺麗なコード」「より良いコードを書けば、よりうまくいく」など「綺麗なコード、良いコード」についての言及があるが、具体的にどのようなコードが「良い」なのか、この書籍だけでは分からないと感じた。
    • この本の1部はTDDを使った開発の例となっているが、話の展開が、著者の経験や設計論の暗黙知に依るところを感じ分かりづらいと感じた。
    • 「パターン」という章があるけど、パターンというより単なるエッセイになっている。特にパターンに対する定義付けがなく、内容が分からない箇所があった。
      • 例 「三角測量」の項目で、文章中で「2つ以上の例がある時だけ一般化しよう」という記載があるけど、「〜という方法を三角測量という」といった定義付けがなく、読み手の推測で判断する箇所があった。
      • 例 デザインパターンとして出てくる「Imposterパターン」・・・「既存オブジェクトと同じプロトコルを備え、実装は異なる新たなオブジェクトを作ろう」とあるけど、これのどのあたりがデザインパターンとして分類される内容なのか、またImposterパターンとはなんなのか、私の読解力では理解できなかった。(そもそもデザインパターンは「既存オブジェクトと同じプロトコルを備え、実装は異なる新たなオブジェクトを作ろう」これを基礎とした設計カタログではないかと思うのだけど)

感想

身もふたもないけど、この本を読むならリファクタリングを読んだ方が良いと感じた。 理由としては、

  • リファクタリングの方が、暗黙知が少なく(個人的には)読みやすい
  • 「小さく書いて小さく動かす」というTDDとの共通点もリファクタリングの本に含まれている
  • カタログが1つ1つ簡潔にまとまっていて体系立っている
  • 良いコード、悪いコードの事例として参考になる

などなど、リファクタリングの方が得られることが多いのではないかと思った。

もう一つ感じた事は「テストコードの管理は・・・」について気になっていたけど、そもそも「製品コードのモジュール化」がなければ、テストコードの管理も何もないのでは、とこの記事を書きながら気づいた。

おまけ

アジャイルの書籍で必ず「自動テスト」という項目を見かけるけど・・・、TDDでのテストケースは「テストではなく開発の技法」という内容が記憶に強く残っている。 これらの本での自動テストの説明は、簡略化されまた美化されすぎている気がする。