TDDをやってみてわかったこと
プロジェクトの要所で部分的に TDD を実践したら開発がとてもはかどったので、感じたことをまとめました。
🙆♂️ システムの仕様を把握するのが楽になる
プロジェクトにジョインしたときはテストがひとつも書かれておらず、引き継ぎをしてくれる人もいなかったので、仕様を把握する術はコードを追うことしかなかった。その結果、仕様の把握に多くの時間を割くことに。
もしテストが書かれていれば、引き継ぎしてくれなくてもかなりの時間を短縮できたはず。たとえば、レコードを生成する処理のテストにレコードの生成条件と生成されるレコードの対が記述されていれば、それを見ただけでそのコードの挙動がわかる。さらに、例外的な値が入力されたときの挙動も記述しておけば、れっきとした仕様書にもなる。
🙆♂️ 実装時間を短縮できる
「テストを書く時間がないのではない、テストを書かないから時間がないのだ」という主旨のことを言っていた人がいたけれど、 今回のプロジェクトで実感した。
テストを変更して、失敗することを確認して、アプリケーションのコードを変更して、テストが通ることを確認する。この手順は煩雑なように見えて、実は後戻りすることなく着実に実装を進められる開発手法だと思う。
🙆♂️ ひとつのことに集中できる
タスクのゴールが「テストを通すこと」に決まるので、他のことに気を取られずに集中して実装できる。直したいところを見つけても「あとでやろう」となって、結果的にシングルタスクになって実装スピードが上がる。
🙆♂️ バグの少ないコードを書ける
テストでは、あらゆるパターンで何度も挙動を試すので、バグを撲滅しやすい。 手作業だとどうしても漏れがあるし、人によってテスト能力が違うから属人的でもある。
🙆♂️ 実装がサクサク進む
TDD は「テスト」という問題があって、それに「コード」で回答している感覚。テストが通る (正解)、通らない (不正解) という明確な基準があるので、難解な問題を解く感覚で実装できる。テストが通ったときの達成感はたまらない。
また、テストがあればいくらでもリファクタリングできるので、とりあえずテストが通るコードを書いて、それからより良いコードに書き直してコミットする、みたいな書き方ができる。note の下書き → 推敲 → 投稿みたいな段階があってコードが書きやすい。
🙆♂️ 仕様を深く理解できる
テストではいろんなパターンを想定するので、テストを書くなかで仕様を理解できていないことに気づくことも多い。たとえば、例外的なパターンを書くと「この場合はどうなるんだ?」とわからなくなることがしばしば。テストを書く過程で仕様が明確になるとも言える。
🙆♂️ 設計に気をつけるようになる
テストを書くなかで「あれ、テストが書きにくいな」と思ったら、設計がおかしい証拠だと考えられる。テストを書かずに設計のおかしさに気づくのは難しいけれど、テストを先に書けばおかしな設計はそもそもできなくなる。
🤔 テストを書く時間は無視できない
「実装時間を短縮できる」と言ったけれど、それはすでにテストが用意されている場合の話で。何もないところにテストを導入するのは、それなりに時間がかかる。工数が倍近くになることもなくはない。
🤔 メンテナンスが大変かも
テストコードは更新されなければ廃れてしまう。作った当初は機能していても、メンテナンスしなければ徐々に使い物にならなくなる。
初期開発だと仕様がコロコロ変わったり、根本の仕様が変わったりすることがあって、そのたびにテストを書き直すのはたしかに無駄に感じる。ある程度、仕様が固まったプロジェクトに対して、品質を高めるためにテストを書くのが賢明かもしれない。
🤔 チームで考え方を共有する必要あり
今回はひとりで開発したので関係なかったが、これがチーム開発なら、テストの重要性と書き方、管理のしかたをチーム全体に周知する必要がある。もしテストをメンテナンスする習慣がチームに浸透していない場合、つまりテストの管理が属人化している場合、テストはどんどん廃れていく。周知するためのコストは無視できない。
全体を通して
テストの重要性と有用性がよくわかった。今やテストがないと不安にすらなる。TDD をきっちりやるのはとても大変なので、以下の条件にあてはまるところのように要所で導入すればいいのではないかと思う。
- 動作が不安なところ
- バグがあったら致命的なところ
- 仕様があいまいになっているところ
逆に、以下の条件にあてはまるならテストは書かない。
- 仕様がコロコロ変わる可能性がある
- 仕様が根本から変わる可能性がある
- チーム全員でテストを書くことが難しい
- バグが発生してもさほど困らない、とりま動けばいい
難しそうなことでもやってみると案外親しみやすかったりするので、今後もいろんなことにちょっとずつ手を出してみる。