refactoring and test

Post on 08-Jul-2015

1.629 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

リファクタリングとテストの関係

t­wadahttp://d.hatena.ne.jp/t­wada/

@J2EE勉強会2005年8月20日

前回のおさらい

前回の結論(1)

● TDDはテスト技術ではない

● "Test"が指し示しているものは複数ある

– 開発促進と品質保証

– 2つの"Test"に優劣はない。「違う」だけ。

– どちらも非常に重要● テストをロールから分類する

– 開発者 / 顧客 / 品質保証担当者

前回の結論(2)

● TDDの"Test"は開発(者)のためのもの

– つまり、開発促進のテスト

● TDDの良さは設計技術でありながら品質保証技術に「かなり近い」こと

難しくなったソフトウェア開発

● ソフトウェアの複雑化● ソフトウェアの大規模化● プロジェクトの短納期化

● オブジェクト指向も(それなりに)使われだした

→ソフトウェアの品質が問題に(日経ビジネス)

→「テスト」が注目されてきた

テスト分類の混乱

● 単体、ユニット、結合、機能、システム…

● 単体テストとユニットテストは同じもの?– 単体って?

– ユニットって?

● 結合テストは何を結合する?● 品質保証? 動作確認?● だれが? いつ?

テストの目的に戻ろう

● 何のためにテストするのか● 誰のためにテストをするのか● テストで何を知りたいのか

「結局、何のためにテストを行うのか」

テストをロールによって分類する

● Developer(Programmer) Test– 開発者が行う、開発促進のためのテスト– 単体、ユニット、結合 …などなど

● Customer Test– 顧客(のロールを担うひと)が行うテスト

– 従来の「受け入れテスト」が多くを占める

● QA Test– 品質保証のためのテスト– 行う人は開発者かもしれないし、テスト担当者かもしれない

DeveloperTest

CustomerTest

QATest

「テスト」

それぞれのテストの目的

● Developer Test– 開発促進– フィードバックを伴う設計行為

● Customer Test– 進捗管理– 機能要件の検証

● QA Test– 品質保証– 非機能要件の検証

DeveloperTest

開発促進

設計行為

CustomerTest

進捗管理

機能要件

QATest

品質保証

非機能要件

「テスト」

TDD != 品質保証技術

● TDDは「こうしてみようか」をテストする

● QAテストは「こうあってはならない」をテストする

TDDは品質向上技術だが、品質保証技術ではない。そもそも「品質」の話が必要

あなたにとっての「品質」とは何ですか?

TDDは設計技法です

● 文脈

– プログラミングは設計行為である(J.Reeves)

– REDは仕様の設計

– GREENは仕様の実装

– Refactoringは内部設計の改善

参考:「ソフトウェア設計とは何か?」    http://www.biwa.ne.jp/~mmura/SoftwareDevelopment/WhatIsSoftwareDesignJ.html

TDDと品質保証の関係

● 目的は違えど、手段が品質保証技術に近い● 品質保証との親和性● 帽子を変えることで品質保証モードに入れる

前回の発表のねらい

● 議論の土台を作ること● 目的の視点からみたテストの整理

– Developer Testの概念の紹介

● TDDのTはDeveloper Testであることを理解してもらう– 品質保証のための技術ではなく、開発促進のための技術

今回のお題

今日伝えたいこと(1)

● リファクタリングの目的はコードの理解や修正が簡単になるようにすること

● リファクタリングは設計意志決定のバランスをとる

今日伝えたいこと(2)

● テストがリファクタリングを妨げるのは何かがおかしい

● リファクタリングを後押しするテストと、リファクタリングの役に立たないテストがある

● 目的に沿ってDeveloper Testを使いこなそう

第一部

リファクタリングについての整理

リファクタリングをめぐる混乱

● 三週間ほど前、リファクタリングをめぐって議論が繰り広げられました

● ひとりひとりが結ぶ「リファクタリング」の像が異なるという印象

「テスト」と同じ混乱の構図か

リファクタリングの定義(1)

リファクタリング(名詞)

外部から見たときの振る舞いを保ちつつ、理解や修正が簡単になるように、ソフトウェアの内部構造を変更させること。

リファクタリングの定義(2)

リファクタリング(動詞)

一連のリファクタリングを行って、外部から見た振る舞いの変更なしに、ソフトウェアを再構築すること。

リファクタリングの解釈のブレ

● 外部から見た振る舞い

– 外部?

– 振る舞い?

– public? publish?

● テストで担保する?● パフォーマンス?

「テスト」と同じ混乱の構図

● 違う内容のものを同じ名前で呼んでいる– 「テスト」の意味合いの違い– 「外部から」の意味合いの違い

誰が、何のために、で再整理しましょう

リファクタリングの「誰が」

● これは、私たちプログラマーです● 自分達で、自分達のコードをわかりやすく、シンプルにするのがリファクタリング– 他の人が書いたコードを理解のためにリファクタすることはあるが、特殊例

リファクタリングの「何のために」

● シンプル設計● コードを理解しやすく● コードを修正しやすく● コードをシンプルにすること ≒ 設計をシンプルにすること

大目的

「理解や修正が簡単になるように」

何がリファクタリングへと駆り立てるのか(RtPより)

● 新しいコードを追加しやすくしたいため● 既存のコードの設計を改善したいため● コードをより良く理解したいため● コーディングの不快感を減らしたいため

リファクタリングの「いつ」

● 教条的なことを言うなら、「常に」です● 気づいたときに

● サイクルに織り込んでいるのがTDD

● 「大きいリファクタリング」は、話が別● 小規模なリファクタリングは機械でも出来るし、いつもやっていることです

– rename系、extract系、inline系

リファクタリングは何ではないのか

● 非公開メソッドの中だけではない● パフォーマンスチューニングではない● バグフィクスではない● 他人のひどいコードの手直しではない

● 手戻りではない (Refactoring is not rework)

パフォーマンスチューニング?

● パフォーマンスのためにリファクタすることはほとんどない

● まず計ってからものを言うべし● 普通はデータベースがボトルネック、コードを見るよりExplain Planするべし!

「シンプル」とは何か

● コンテクストに依存する– チームで決めること– チームによってなにがシンプルかが変わる

● パターンはシンプルさのために使う

– Compositeの方が単純なとき

– Strategyの方が単純なとき● 分岐から構造へ

まとめると

リファクタリング、私の理解

● 目的は、理解や修正が簡単になるように● 設計行為としてのリファクタリング

● 外部からみた振る舞い

– publishedメソッドの事前条件と事後条件のこと

– publishedメソッドの変更もときどきリファクタリングと呼んでいます

● 「テスト」

– 大きい粒度のテスト、Mockベースのテストではなくて実オブジェクトベースのテスト

テストがある

テストがない

リファクタリング

privateprotected

public published

リファクタリング前提の設計?

● 逆を考えるとわかりやすい– 「一発で正しい設計を行え、修正や改善は許可しない」と言われたら?

● 「修正が効かない」というプレッシャーをあたえると人間は脆い

● テストとバージョン管理で安全に後戻りができるようになる– 安心して前に進むことができるようになる

技術的負債

● スケジュールの無い開発は存在しない● 負債を追ってでもリリースを優先することも● リファクタリングで負債を減らしていく

● 「ええい、やめだやめだ、スクラッチから書き直そう!」とならないために

● リファクタリングは「捨てない技術」

道はひとつではない

● 「動作する、きれいなコード」● きれいな、から攻めるか● 動作する、から攻めるか

動作する(すぐには)動かない

汚い

きれい

動作する(すぐには)動かない

汚い

きれい

動作する(すぐには)動かない

汚い

きれい

動作する(すぐには)動かない

汚い

きれい

TDDのテンポ

● Red, Green, Refactor● Red, Green, Commit, Refactor, Green, Commit

「動作する」を満たしてから

「きれいな」にとりかかる

動作する(すぐには)動かない

汚い

きれい

動作する(すぐには)動かない

汚い

きれい

Red

動作する(すぐには)動かない

汚い

きれい

Red

Green

動作する(すぐには)動かない

汚い

きれい

Green

Ref

acto

r

動作する(すぐには)動かない

汚い

きれい

Ref

acto

r

Red

動作する(すぐには)動かない

汚い

きれい

RedGreen

動作する(すぐには)動かない

汚い

きれい

Ref

acto

r

Green

動作する(すぐには)動かない

汚い

きれい

Ref

acto

r

RedGreen

リターンマッチは可能だ

● 設計の善し悪しは、最初に設計したときには決まらない

● だんだんと「より良い」設計に変えていくことが出来る

– ただし、非常に大規模なアーキテクチャ変更は別

● メジャーバージョンアップ● システムのリプレース

進化的設計(Evolutionary Design)

● フレームワークは最後に出来る● ボトムアップ● フィードバック

ここで提示しているのは極論かもしれませんが、

こんな考え方もあることを紹介したいのです。

第二部

リファクタリングをサポートするテ

ストとは何か

テストの資産価値

● リファクタリングの邪魔になるようなテストは価値が低い

● テストはリファクタリングの支えになるものであって、妨げになるものではない

● どのテストもメンテナンスコストはかかる● 半年後であっても読みやすく、リファクタリングの支えになるテストは資産価値が高い

再度Developer Testを分類する必要が出てきました

Developer Testの分類のキーポイント

● 目的● 粒度● 何を担保するのか● フィードバックまでの時間● 資産価値● メンテナンスコスト● 設計改善効果

Developer Testを目的と粒度で分類する

● Unit Test– テスト対象以外は全てMock

● Assembly Test– テスト対象のコラボレータは本物を使う

● Functional Test– コンポーネントをブラックボックスとして扱う– 永続化層も本物

DeveloperTest

CustomerTest

QATest

CustomerTest

QATest

Developer Test

Unit Test

Assembly Test

Functional Test

Developer Testの分類、もうひとつの視点

インタラクションベーステスト

● テスト対象のオブジェクトがコラボレータときちんと相互作用するかどうかを検証する

● Mockを多用する

– テストの初めでコラボレータのMockを作成

– Mockにexpectationをセット

– テストの最後でMockをverify

ステートベーステスト

● テスト対象のオブジェクトの振る舞いの事前条件、事後条件を検証する

● setUpでデータを準備

● assertEquals等で事後条件のチェック

インタラクションベースステートベース

Unit Test

AssemblyTest

FunctionalTest

リファクタリングを担保するテストとは

● ある程度大きい粒度のテストでないと、リファクタリングの前後を担保できない

● インタラクションベースのテストはリファクタリングの役にたたないことが多い

リファクタリングの誤解

● 「リファクタリング前後でテストが失敗してはならない」?

担保するテストはGreen to Greenであるべし

しかし、

全てのテストがGreen to Greenとは限らない

リファクタリングの最中には

● ステートベースのテストは失敗しない

● インタラクションベースのテストは失敗してもいい

● あくまで「想定の範囲内」であれば、ですが

なぜインタラクションベースのテストは失敗してもいいのか

● 内部設計を改善するということは、オブジェクトたちの相互作用(インタラクション)も変わる可能性が高い– 責務の再配置には、インタラクションの変更がつき従う

– インタラクションが変わるのは悪いことではなく、良いこと

インタラクションベースステートベース

Unit Test

AssemblyTest

FunctionalTest

リファクタリングの支えになりにくい領域

CustomerTest

QATest

Developer Test

Unit Test

Assembly Test

Functional Test

リファクタリングの支えになりにくい領域

私のチームがテストの粒度に使っているメタファ

● はしご● 踏台● 階段

● 調子のいいときには三段飛ばし● 心配なときには一段ずつ

トップダウンとボトムアップ

● インタラクションベースのテストだけを積み上げて正解に辿り着くのは難しい

● 受け入れテストだけを拠り所に開発を行うのは足場が少なすぎる

足りないピースは?

低コストな機能(Functional)テスト

● 大きいリファクタリングのキーポイント● 機能のブラックボックステストをいかに低コストで行うかがカギ

● 例えばJ2EEであれば

– Selenium

– HttpUnit

– Cactus

Mockでテストできないもの

● オブジェクトたちが実際に協調して動くこと

● Mockは妄想。妄想でもインタラクションの設計はできる

● 詳細なシーケンス図と役割が似ている?– 違いはコードで書かれること– 図とコードの距離

インタラクションベーステスト(Mock)のデメリット

● 価値が前方(気づき)に集中する

● メンテナンスコストが結構高い● テストがなかなか資産化しない

           => 資産価値が低い

最後にちょっとMockテストの弁護をします

Mockのメリット(1)

● フィードバックの早さ

– MockのテストはGreenにするまでの時間が短い

● 例外系のテストが行いやすい– ネットワークエラー– データベースエラー

Mockのメリット(2)

● 悪い設計に気づくまでの時間が短い

– Mockのセットアップがめんどくさい

                => インタラクションが複雑

– Mockを沢山作らなければならない

                => デメテルの法則に反している

● 責任の配置を考える機会が増える

– Tell, don't Ask

– QueryからCommandへ

テスト設計の勘どころは、次回以降をご期待ください

今日伝えたかったこと(1)

● リファクタリングの目的はコードの理解や修正が簡単になるようにすること

● リファクタリングは設計意志決定のバランスをとる

今日伝えたかったこと(2)

● テストがリファクタリングを妨げるのは何かがおかしい

● リファクタリングを後押しするテストと、リファクタリングの役に立たないテストがある

● 目的に沿ってDeveloper Testを使いこなそう

Enjoy Testing!

Special Thanks

● J2EE勉強会に参加されているみなさま● 角田さん● ひがさん● 中村さん● 稚内北星学園大学様(会場提供ありがとうございます)● かくたにさん● kdmsnrさん (今回はblikiに本当に御世話になりました)

● TDD,Refactoringを編みだしたKent Beck氏● そして、それを私に教えてくれた、masarlさん

ご静聴ありがとうございました

top related