TDD勉強日誌 その1

tdd_study_thumbnail

TDDの勉強メモ。その10くらいまで続くと嬉しいですよね(他人事)

本を使って進める。使う本はこれ。

TDDとは?

TDD(Test-Driven Development)。日本語でテスト駆動開発と呼ばれる。テスト駆動開発が目指すのは“動作するきれいなコード”だ。最高。乗るっきゃないこのビッグウェーブに。

テスト駆動開発のルールは以下2つ。以下2つをループする感じで開発をすすめる。以下は完全に本書からの引用。

  • 自動化されたテストが失敗したときのみ、新しいコードを書く
  • 重複を除去する

テスト駆動開発のセオリーは以下(本書ではマントラと書いていたが、とにかくこのやり方で進めろということ)。

レッド→グリーン→リファクタリング

きっと塾の先生なら1回の授業で10回はこれを繰り返すだろう。TDDが会社ならきっとこれを社訓にするだろう。そんな感じ。とにかくこれが重要ってこと。

それぞれ一言で言うとこういうことをやる感じ。これも引用とさせてほしい。

  1. レッド:動作しない、おそらく最初のうちはコンパイルも通らないテストを1つ書く。
  2. グリーン:そのテストを迅速に動作させる。このステップでは罪を犯してもよい。
  3. リファクタリング:テストを通すために発生した重複をすべて除去する。

まだ読んだばっかりだけど、私が引用しているところを意識してひたすら進める、身体ににじみこませる。それがだい…それが〜一番大事〜なんだと思う。心に刻もう。

ここから先は具体的に本書に習ってコードを書きながら私のメモ取りとして使う。読んでくれている皆さんのためになるとはあんまり思わないのでここまで読んでいただければ良いと思う。

この見出しのまとめ
  • 2つのルールを遵守
  • レッド→グリーン→リファクタリング

テストコードを書け

で、本書の第1章では国際通貨を換算するモデルの開発を通してTDDを学ぶ。まずやるべきは簡単な条件でテストを通すこと。

異なる2つの通貨に対してもう一方を換算して合計値を出すようにするモデルの開発をする。それにあたりToDoリストを作る。ToDoリストにやることを思いついたらバンバン入れるのが良いらしい。Todoリストは以下だ。

Todoリスト
□$5 + 10CHF=$10 (*CHF:スイスフラン)
□$5 * 2 = $10

ToDoリストの使い方。何度でも言って良さそうなので重複するところもあるが書く。
思いついたらリストに追加。
リストのToDoをどんどん解消していく。
思いついたToDoはリストに追加。
ToDoをどんどん解消。思いついたエンドレスサマー

まずはテストコード。テストファーストということでまずテストを作るということ。

本書にも書いてあるが「じゃあ実装にどんなオブジェクトが必要なんだろう…?」じゃないのだ。まずはテストコードを書け。話はそれからだ。

(なんかひとり暮らしはピザを焼けの記事みたいだ)

んで、さっきのToDoリスト。2つある。簡単なのはどっちだ。圧倒的に後者。簡単な方から始める。手を動かせ。まずは$5 * 2 = $10を実現しろ。

本書ではJavaで書かれているが、私はPythonでやりたいのでPythonで書き直しながら進める。テストコードは以下。

#MoneyTest.py
from money import Dollar as Dollar
import unittest

class MoneyTest(unittest.TestCase):
    def testMultiplication(self):
        five = Dollar(5)
        five.times(2)
        self.assertEqual(10,five.amount)

このテストを徐に書くことで「これやらな…」ってのがポンポン出てくる。作法的によろしくないだろみたいな。でも、そういう気づいた問題は一旦ToDoに書くだけにして後に回す

今はまず$5 * 2 = $10だ。Dollarクラスが無いよ、その中身のメソッドが無いよと怒られている。もちろんコンパイルすらできない。

なので次の思考のベクトルは最低限動かすための実装(レッドバーを表示させよ)になる。関数は中身無くて良い。エラーを無くす。この際に気をつけることは一つ一つコンパイルエラーを解決していくことだ

この思考により書いたクラスが以下。

#Dollar.py
#import money

class Dollar:
    def __init__(self, amount: int):
        self.amount = amount

    def times(self, multiplier: int):
        pass

これでレッドバーが出る。
具体的に言うと”AssertionError: 10 != 0″が出る。

次はこれをグリーンバーにする。このときに意識することは、グリーンになりさえすれば良いということ。どういうことかと言うと、なんとなく__initi__()とtimes()を具体的にコーディングしたくなると思うんだけど、それはまだ。正解はこう。amountに10を直で入れる。

class Dollar:
    def __init__(self, amount: int):
        self.amount = 10

確かに。なるほど。これがグリーンバーになる最短コースだ。

最後にリファクタリング。コードを書く中で色んなことがToDoに入ってきているとは思うが、それは一旦置く。今は目先の$5 * 2 = $10を実現するためのリファクタリングをする。

そしてリファクタリングで意識することは重複の除去だ。重複というのはテストコードと実際のクラスとの重複だ。
具体的に言うと、Dollarクラスでamountに入れた10は5 *2だし、この5と2はテストコードで書かれるので、Dollarクラスに直書きされるべきではない。そうするとこの重複を除去するために具体的にコードを書くことになる。
もう一度言う。1つ1つToDoを解消していくことが大事。一気に解決しようとしない。

さらに追加で言う。ToDoを1つずつ解消と言ったが、テストを回すのはもっと細かい単位で行う。1つ変更を加えたらすぐテストしてグリーンバーが維持されるかを確認する。

変更かけてテスト。変更かけてテスト。変更かけて…。重複を除去した結果が以下。これによりToDoが1つ減る。

#Dollar.py
#import money

class Dollar:
    def __init__(self, amount: int):
        self.amount = amount

    def times(self, multiplier: int):
        self.amount *=multiplier

Todoリスト
□$5 + 10CHF=$10 (*CHF:スイスフラン)
☑$5 * 2 = $10
□新たなToDo(Dollarの副作用)
□新たなToDo(その他)
□…

以上。まとめる。多いけどこの通りにやる。

この見出しのまとめ
  • ToDoリストを作る
  • テストコードを簡単で良いから作る。通らなくていい。
  • レッドバーを出すための最短コースの変更をかける。エラーを無くす。
  • 浮かんだ問題をToDoリストに入れる。
  • レッドバーをグリーンバーにするための最短コースの変更をかける。
  • リファクタリングにて重複を除去する。
  • ToDoが1つ減る。そして新たなToDoに着手する。

とりあえずこの記事では以上。また今度書く必要が出たら書く。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です