テスト駆動は開発速度を遅くするのか.
テスト駆動をやってみました.
しかし,テストを書いても工数削減はできませんでした.
成果は出ませんでした.
という記事を非常に良く見ます.
残念ながらテスト駆動は開発速度を鈍化させると"感じる"のは多くの場合,正しいと思います.しかし、**テスト駆動が理由で開発速度を鈍化させている"事実"は少ない。**と思います。
その言語化を試みました.
テスト駆動に何を求めているのか
Q. テスト駆動をなぜ始めるのか?
A. 技術負債が辛く、解消したいから。
残念ながら,プロダクトを作り始め、しばらく経った後に技術負債の大事さに気づき,テストを書こう.テスト駆動を始めよう.というモチベーションになります.
そういった技術負債の改善を考えたテスト駆動は失敗する可能性が高い.
です.
地獄環境下からのテスト駆動
そもそも"技術負債"とは何でしょう?技術負債がたまった状態とは,どういう状態なのでしょうか?
Martin FowlerのIs High Quality Software Worth the Cost?のグラフを参考に説明いたします.以下の画像は私が加筆訂正したものです.
図で青線はプログラムの内部の質が高い場合,茶色の線はプログラムの内部の質が低い場合を表現しています.
ここで,プログラムの内部の質が低い状態.というのは,技術負債がたまった状態とほぼ同義です.
逆に,プログラムの内部の質が高い状態.というのは,技術負債が少ない状態です.
端的に言ってしまうと,技術負債がたまっていると,技術負債がたまっていない状態に比べて,1つの機能を実装するのに多くの時間がかかります.これが「テスト駆動をしよう。」と思ったときに失敗する原因の1つです。
開発初期段階の場合、テストもなしで、シンプルな実装のほうが開発速度が速いということはよくあります。そして、その実装もしばらくたったあとでも、手動テストでカバーでできる時期があります。しかし、しばらくするとテストの工数が膨らんできて、手動テストが厳しくなってきます。そうした後で、テストを書こう。テスト駆動をしよう。という話になります。しかし、その時点ですでに地獄になっています。
もう一度、話をしますが、"技術負債がたまった状態とは、1つの機能を実装するのに多くの時間がかかる状態"です。人間でいえば、体に"重し"を付けた状態で走っているような状態です。その状態でテスト駆動でテストを書いたとしても、開発速度は出ません。しかし、**技術負債がたまらないと「テスト駆動をやろう。」というモチベーションにならず、**結局、技術負債を積みながら開発することになります。そもそもテストを書こうと思うタイミングが遅すぎるのです。
テスト駆動は開発効率が"悪い"
元も子もないことを言いますが,テスト駆動は開発効率が悪いです.
ここで言う開発効率とは
開発効率 = 機能数 ÷ 時間(工数)
です.1機能にかかる工数が大きくなります.
個人的な所見ですが,機能のコードと,それに対するテストのコードは大体同じぐらいの行数になるように書くとちょうどいい感じのモジュールの粒度感になります.LOCで生産性を測るのは前時代的ではありますが,まぁ普通に実装を書くより長い時間がかかる.というぐらいの認識でよいです.そして,「テスト駆動しよう」といった場合,テスト駆動のその周辺に関する知識について色々調べる必要が出てきます.特に,今まで意識していなかったテストライブラリの使い方だったり,テスト環境の構築.テストを書く上でのベストプラクティス,テスト可能なモジュール設計等,その勉強しながら開発するとコストは大きくなります.そのため,慣れるまではテスト駆動をした場合の工数の1.2,1.3倍ぐらい開発工数がかかる感触があります.
この内容を開発工数を固定にしたグラフを作ると以下のようになります.
このように「開発工数」に対する,「機能開発工数」の割合は小さくなります.その上,テスト駆動に不慣れな場合,余計に工数がかかり,単位時間当たりの開発効率が非常に下がります.ここがテスト駆動が遅く感じるもう1つの要因です。
しかし、これは正直な話を言うと**"感じる"というだけで"事実"ではない**。と思います。これは今までテストのコストを踏み倒していたのをきっちりと払うようになった。というだけです。
テスト作成後の地獄
技術負債がたまってプロダクトのテスト工数がしんどい・・・でも、俺たちは頑張ってテストを書くんだ!
そして、俺らは技術負債を完済しきった!やった!
そんな輝かしいストーリーは大体起こりえないです。実は、テストにも"保守性"というものが存在します。
図の引用:xUnit Test Patternsから学ぶユニットテストの6つの目指すべきゴール
本来的には、保守性の高いテストを書いている場合、機能追加をして、新たなテストを書いても、工数が増えません。しかし、モジュール同士が密結合であったり、無理にライブラリのクラスをモックにしていると、少しの変更で、すぐに壊れるテストが生まれます。
そうした場合、機能の追加。修正のたびに、壊れるテストを修復する作業が多くなり、自動テストの恩恵を受けられなくなります。今までテストを書いてこなかった技術負債のたまったプロダクトに無理やりテストを書くと頻発します。
自分は、ちょっとテストに無理があるかもな。と思ったプロダクトに対して、頑張ってテストを書き、**90%以上のカバレッジを自動テストでカバーしたことがあります。そして、ほぼすべてのテストコードを捨てました。**結局、少しの修正でテストが壊れる、だれも保守できないテストが生まれました。
"テスト駆動は開発速度を鈍化させる"という幻影
a. 技術負債を返済するためにテストを書こう。そのためにテスト駆動をしよう
-> 技術負債がたまった状態だと、開発に時間がかかる。しかし、その状態でテスト駆動に活路を求めてしまう。
b. 今までテスト駆動をやっていなかったけど、これからやろう!
-> 慣れないテストライブラリの使い方で時間がかかる。そして、テストを書いていないときは、機能開発に時間がかからなかったのに・・・という気持ちになる。(実際は、今まで払っていなかったテストのコストを払っているだけ)
c. 全部のテストを書けた!やった!
-> テスト駆動に不慣れな状態。テストライブラリに不慣れな状態で書いたテストの保守性が低いため、機能を実装するたびにテストが壊れて動くかなくなり、その修正の工数が膨らむ。結果、テストを捨てる。
大体、1,2を同時に起こす場合が多いです。そして、その工数に耐え切れず死にます。そして、耐え切っても、テストを捨てることになったりします。そうなるとどうなるか?
技術負債がたまって開発がつらい。
でも、頑張って技術負債を返さないとずっと辛いまま。
テスト駆動というのがあるらしい。これでいけるかも。
技術負債を返すためにテスト駆動してテストを書いていたのに開発効率が落ちた.
頑張って書いたテストは不安定で全然テストが通らない.
技術負債も返した感じはしない。むしろテストを書くだけ、工数が増えた。
俺は頑張って技術負債を返そうとした。
そのために頑張った。
裏切られた.
何が原因?
テスト駆動は悪.テスト駆動は糞。
という言説につながっている気がします。ここでは議論しませんが、ソフトウェアテスト≒テスト駆動ではありません。ただし、"テスト駆動"という名前から、"自動テストを書くこと"をテスト駆動と誤認されている節はあります。少なくとも書籍"テスト駆動"を読むまでは、私も、そういう認識でした。それは完全な間違いではありませんが、"自動テストを書くこと"は"テスト駆動"の一部でしかありません。
**テスト駆動は技術負債に対する"銀の銃弾"ではない。にもかかわらず、"テスト"と名前に冠しているため、その誤認から"銀の銃弾"扱いをされて、風評被害を食らっている節がある。**というのが、私の意見です。
先ほどの3つの事象の原因を私なりに整理すると、以下のようになります。
a. 技術負債を返済するためにテストを書こう。そのためにテスト駆動をしよう。
-> 技術負債自体が問題
b. 今までテスト駆動をやっていなかったけど、これからやろう!
-> テストに関するコストの軽視が問題
c. 全部のテストを書けた!やった!
-> ソフトウェアテストの難しさが問題
実際のところ、テスト駆動が原因か?と思われるところは2.が関係するかも。ぐらいです。
"テスト駆動はスキル"は @t_wada さんの言説ですが、テスト駆動やソフトウェアテストは練習すると習得できるスキルです。それは、私も実感しました。しかし、残念ながらスキルというのは習得するのに時間がかかる。というのも事実で、私がテスト駆動を始めて、プロダクションのコードでしっくりくるまで1年かかりました。テスト駆動により、一時的に開発速度が遅くなる。ということは否めないです。
"テスト駆動"は"手洗い・うがい"
「インフルエンザにかかりました。特効薬として、タミフルを飲みました。」
これは、インフルエンザに対するアプローチとして正しいものです。
「技術負債の解消のために、テスト駆動をする。」
というのは、技術負債のアプローチとして正しくないと私は思っています。したがって、この文章の最初にあった
Q. テスト駆動をなぜ始めるのか?
A. 技術負債が辛く、解消したいから。
は、実はそもそもスタートから間違っているところがあります。
「技術負債の予防のために、テスト駆動をする。」
のほうが正しい認識だと私は思います。そのため、テスト駆動は、"インフルエンザ予防"のための"手洗い・うがい"のようなものです。テスト駆動は、テストを書くことが主たる技法ではありますが、設計技法でもあり、技術負債のカナリアでもあります。
テスト駆動読め。
これに尽きる。いや、本当に。