Skip to content

Instantly share code, notes, and snippets.

@wm3
Last active Dec 14, 2015
Embed
What would you like to do?
実践テスト駆動開発第1回

1章 テスト駆動開発のポイントとは?

この章の概要

開発における本書の基本的な考え

  • 開発における「予期せぬ変化を予期する」 (anticipate unanticipated changes)
  • 開発に「入れ子になったフィードバックループ」を形成する
  • ソフトウェアの「 内側と外側の品質」

TDDにおけるポイント

  • テストは「設計作業」
  • 「失敗するテスト」を書け
  • 「エンドツーエンド」のテストを行う

学習プロセスとしてのソフトウェア開発

開発は分からない事が多い

  • 技術面 … 完全には理解していない
  • 要件面 … 顧客は自分たちの組織の事をより深く理解し正していかないといけない

開発では「予期せぬ変化を予期する」必要がある

  • 必ず思いもよらないことが起こる
  • そもそも誰も行っていな事をやるのがソフトウェア開発

フィードバックは欠かせないツールである

最良のアプローチ

  • 実地からのフィードバック、タイムボックスに分割、それをデプロイする

フィードバックをあらゆるレベルに適用する

  • ペアプログラミングやユニットテストからリリースまで

変化を支えるプラクティス

重要な技術的な基盤が二つ

  1. リグレッションエラーを検出する事
  2. コードを出来る限りシンプルにしておく事
    • 書きやすさではなく読みやすさに最適化する
    • 常にリファクタリングする

コードを書く前にテストを書く

  • 何をしたいのかを先に明確にする

テスト駆動開発ひとめぐり

  • Red / Green / Refactor

テストを書く事による恩恵

  • 受け入れ基準が明確になる
  • 疎結合のコンポーネントを書くように促される
  • テストがコードの説明となる
  • リグレッションの検出するチャンスが増える

テストを実行することによる恩恵

  • コンテキストがまだ頭の中にあるうちに、エラーを検出できる
  • どうなれば作業を完了として良いのか把握できるようになる
    • 余計な実装(金メッキ、gold plating)をしないようになる
    • (これは思い当たる節がある人多そう)

テスト駆動開発の黄金律

  • 「失敗するテストを書く事なしに、新しい機能を追加してはならない」

コラム: リファクタリング: ローカルに考え、ローカルに実施せよ

  • 粒度の細かいリファクタリングを繰り返す
  • 大規模な「再設計」とは異なる

全体像

受け入れテストを書くことから始める

  • ユニットテストだけ書く事の問題
    • 不要な機能の実装
    • 統合が出来ないケースの発生
  • 完了した受け入れテストと実装中の受け入れテストを分ける

エンドツーエンドでテストする

端から端まで通したテストを行う

  • 相互作用も含めたテストを行う
  • デプロイのテストも行う
  • 手間がかかるので受け入れテストは自動で行う

コラム: エンドツーエンドテストの重要性: 怖い話

  • TDDを行っていたが、必要な実装が行われていない部分があった
  • エンドツーエンドテストが行われていなかった
  • デモセッションのような物をフィードバックの一環として行うべきだった

テストのレベル

(若干独特な定義という噂…)

受け入れテスト

  • ドメインエキスパートとの合意をとる
  • 既存の機能を壊していない事のチェック
  • エンドツーエンドテストとして書く

インテグレーションテスト

  • チーム外のコードと組み合わせて動くかどうかのテスト

ユニットテスト

  • 本書でメインに解説する

外側の質と内側の質

  • 外側の質 … 顧客やユーザのニーズにどれだけ応えられているか
  • 内側の質 … 開発者や管理者のニーズにどれだけ応えられているか

どちらも同じくらいに重要

ユニットテストによって内部品質を向上できる

  • というより、書き換えやすくできるように書かざるを得ない

コラム: 結合と凝集

  • 結合 … ある要素を変更した場合に他を変更しなければならない
  • 凝集 … 責務が意味のある単位としてまとまっているか

2章 オブジェクトをテスト駆動開発する

本書による良いオブジェクト指向設計の考え

  • 「オブジェクトの構造」ではなく「オブジェクト間のコミュニケーション」を設計する
  • 「オブジェクト」ではなく「ロール」を設計する

開発におけるポイント

  • 「値」と「オブジェクト」
  • 「デメテルの法則」
  • 「インタフェースの発見」

オブジェクトの網の目

オブジェクト指向設計で重要なのは各オブジェクトよりもオブジェクト間のコミュニケーション

  • (なおメッセージングはメソッド呼び出しと大体同じ意味だと思われます。Smalltalk 用語)

オブジェクト指向のシステムはオブジェクトの網の目のような構造

  • (網の目、という感覚が厳密には分からないです…)
  • 各オブジェクトのコミュニケーションの仕方を設計
  • それらを組み合わせる事で一つのシステムを構築する
    • 宣言的な定義
    • (DI 的な物に近いか)

(Alan Kay の発言)

"値"と"オブジェクト"

通常の「オブジェクト」を2つの種類に区別する事が重要

  • 値 … アイデンティティが無い、状態が不変、関数的
  • オブジェクト … 状態が変化する、振る舞いを表現

メッセージに従う事

(…難しい!)

宣言的アプローチの恩恵が得られるのは、依存関係が明示され、コミュニケーションパターンに従っている場合だけ

コミュニケーションパターン

  • オブジェクトのロール
    • ロールはインタフェースで(大体)表現される
  • どのメッセージをいつ送るか
  • 等を含めたやり取りのルールの事

ドメインモデルはコミュニケーションパターンの中に存在する

  • (DDDっぽい話題かと思われる)
    • (アプリケーションの設計を正確にコードとして表現できるか)
    • (静的なクラス構造の観点 … アプリケーションを正確にモデリングできない)
    • (コミュニケーションパターン(というかテスト) … アプリケーションのモデルの正確な表現になりうる)

コミュニケーションパターンに注目した場合のクラス構造とは違う発想

  • 例: ビデオゲーム
    • プレイヤーから見た視点 … アクター、風景、エフェクト等
    • システムから見た視点 … 見えるオブジェクト、衝突解決者等
  • オブジェクトは視点によってロールが異なる
  • 複数の視点はクラス階層では表現できない

コラム: ロール、責務、コラボレーター

  • CRCカード
  • 責務駆動設計から

命じよ、訊ねるな

  • デメテルの掟(最小知識の原則)とも
  • 悪い例: 「列車事故」コード
    • (暗黙的な依存性が生じている)
    • (宣言的なコーディング部分ではこれに当てはまらない、後の章で出てくる)

メリット

  • 内部構造を知る必要が減るので柔軟になる

  • 相互作用に明確な名前がつく

  • (処理をたらい回すだけのコピペコードが量産されるのでは?…と昔思った)

    • (個人的な経験上は、そんなに酷い事にはならない)

しかし、時には訊ねることもある

  • 実際には訊ねる必要があることもある
  • それでも列車事故コードは避ける

協力しあうオブジェクトのユニットテスト

  • テストできない?

モックを使う

  • エクスペクテーション … 隣接オブジェクトが何を呼ばれたかをチェックする

インタフェースの発見

  • モックを使ってテストをする事で、隣接オブジェクトが何のメソッドが必要かが分かるようになる

モックオブジェクトを用いて TDD をサポートする

モッカリー … 各テストに登場するモックを管理

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment