mokky14's IT diary

IT関係の仕事メモ、勉強会の感想など書いてます。

TDDBC仙台 the 3rdに参加してきました

10/12のTDDBC仙台 the 3rd行ってきました。
the 3rdということで、ルパンがお出迎えw
f:id:mokky14:20131012202633p:plain

当日の様子は以下Togetterより:
http://togetter.com/li/576125

基調講演

TDD伝道師の和田卓人(@t_wada)さんの講演。
このイベントで何を勉強してきたか報告する場合は、
[動画で解説]和田卓人の“テスト駆動開発”講座
を見て下さいとのこと。

以下、講演の内容。

TDDの考え方

f:id:mokky14:20131014003130p:plain
動作するきれいなコードへ至るための方法として、2通りの道がある。
従来は、きれいな設計をしてから実装していた。しかし、実際には実装を始めてみて気がつく問題が出てくる。そうなるとなかなか「動作する」の線を越えられない。
これに対して、汚い設計でもまず動くコードを作成し、それをリファクタリングしていくことできれいなコードにしていくアプローチがある。これがTDDの考え方。
ただし、このアプローチは「動くんだからもう直さなくていいだろ」と言われる場合があるので注意。

TDDのサイクル

f:id:mokky14:20131014003148p:plain
この3つを真円に近づくように回すのが大事だと。
(JOJOは6部までしか読んでないので、黄金の回転分からんかった。。)

サイクルは素早く回すことが大事。対象を小さくして、一つずつ対処する。
時間がなくなってくると、Refactoringに時間が掛けられなくなり、真円から遠ざかる。
(思い当たる事が多々。。)

作る前から使う

作る前から使うことで、使う側の視点(使いやすさ)が得られる。
作ってから使うと、作る側の視点(作りやすさ)になってしまう。

不安なところをテストにする。

getterやsetterに不安なところはない。
複雑なメイン処理など、不安を感じるところのテストを書く。
TDDのテストはプログラムのテクニックで、品質担保が目的ではない。品質担保が目的のテストは他で行う。
(今まで、TDDはクラスの単体試験のテストケースを先に書くことだと思ってて、何だか違和感があったのが解消されました)

TDDの目的は「健康」

f:id:mokky14:20131014003213p:plain
コード、チームの健康を保つことがTDDの目的。

f:id:mokky14:20131014003350p:plainf:id:mokky14:20131014003357p:plain
TDDを導入すると、テストの実装工数が2割程度増加、バグ残存率が7割程度減。
デバッグにかかる時間が短くなるため、トータルの工数は減る。

ピアソンのバカ!

f:id:mokky14:20131014003113p:plain

TDDライブデモ

@i_takehiro さんと、@leecom さんによるデモ。
当日の課題はこちら

TDDということで、まずはテストから書き始め。
以下は自分の記憶を頼りに書いてるので、実際のデモで書いてたコードとは違うかも。

public class RangeTest {
    @Test
    public void 閉区間から下端点3を取得できること() {
        Range r = new Range(3, 8);
        assertThat( r.getLowerEndPoint(), is(3) );
    }
}

上記テストメソッドを以下の順番で実装。

  • assertThatを入力。
  • 「どうなったらテストOKなのか?」ということで、テストOKとする条件の is(3)を書く。
  • その結果を得るためのメソッド呼び出しrange.getLowerEndPoint()
  • メソッド呼び出すためのインスタンス生成Range r = new Range(3, 8);

この時点ではRangeクラスは存在しないので、テストケースのソース中に出ているコンパイルエラーを除去するようにクラスを実装(というよりEclipseのCtrl+1メニュー任せの空実装)。

public class Range {
    public Range(Integer i, Integer j) {
    }

    public Integer getLowerEndPoint() {
        return null;
    }
}

この時点でテスト実行。期待値3に対してnull返却されるためテストはエラーになる。

続いてメソッドを実装。ここで驚いたのが、

    public Integer getLowerEndPoint() {
        return 3;
    }

という実装でテストを通したこと。
いや、そりゃテストは通るだろうけど、、、こんなコードで通すことに意味あるの?
と思ったところで解説が。

これは、メソッド仮実装というやつで、テストケースが正しいことを確認することが目的。もしこの仮実装でテストが失敗するようなら、それはテストケースがバグってることになると。
納得。

で、仮実装を本実装にする、ではなく、次に別のテストを追加。

    @Test
    public void 閉区間4_9から下端点4を取得できること() {
        Range r = new Range(4, 9);
        assertThat( r.getLowerEndPoint(), is(4) );
    }

この技法を三角測量というそうです。
このテストを追加したら、当然もう仮実装のコードではテストをパスできないので、ちゃんと実装して、全てのテストがパスすることを確認。
それが終わったらリファクタリングして、テスト実行して、問題ないことを確認しながら進めていく。

TDDってどういうふうに進めてくのか分からんかったので、興味深く見させて頂きました。

昼ご飯

会場で弁当が用意されてました。うまかった。
f:id:mokky14:20131102221713p:plain

実践

人世初のペアプログラミング
言語はJava
終わったら、作ったコードをGithubに上げようと思ってたけど、最終的に書いたコード貰うの忘れたな。。
何故実装中にGithub使おうと思わなかったのか、今思うと謎。

やってみた感想としては、どこまでテスト書くかが悩ましい。
最初のうちはテストパターンは結構手を抜いて書いてたら、仕様漏れが発覚。テストが足りてなかった。
で、その後、「これだけやれば大丈夫だろう」というレベルでテスト項目を追加したけど、テストパターン1つにつきテストメソッド書いてassert文書くのは、作業感がありすぎてしんどかった。
気持ちの問題とは言え、やる気が出ないコード書くのはしんどい。コード書くテンポも落ちてたし。
もう少しテストが簡単に書ける方法がないと、「サイクルを素早く回す」ことが出来ないな、と思った。
そういう意味で、今日Groovyチームが使ってたSpockはすごく興味ある。
(後日追記) JUnit実践入門見たら、@RunWith(Theories.class)で、入力値と期待値をパラメータ化したテストケースが書けることを知りました。勉強不足orz

課題は良くできた課題だったなと思う。
課題2に入ったところでで終了になったけど、もう少し進みたかった。

今回は色々な言語チームがいて、それぞれの言語での実装が見れたのは面白かった。
他の言語見てると、Javaってやっぱり冗長だな~と思うことしばしば。
equals(Object)とかhashCode()とか実装すんのが面倒で手抜いたら、レビューで@i_takehiro さんからしっかり突っ込まれましたw

来年はGroovyで参加してみたいな~。もっと勉強しなきゃだけど。

最後に

懇親会に参加できなかったのが非常に残念 (T T
講師の和田さん、主催者の @135yshr さんを始めとするスタッフの方々、会場を提供して下さったデータコム様、参加者の皆様、ありがとうございました!