技術的負債とテスト駆動開発

TDDBCのUstを見てから、テスト駆動開発についてちゃんと勉強しようと、テスト駆動開発入門レガシーコード改善ガイドを読み始めました。

ほとんどの開発現場がそうであるように、うちの開発現場でもレガシーコードで溢れているのですが、レガシーコードとは一体なんなのでしょう。レガシーは「遺産」という意味なので、技術的負債と考えればよさそうです。では、どのようなコードが技術的負債なのでしょうか。

テストがないコードはレガシーコードだ!

レガシーコード改善ガイドに以下のような文章がありました。

テストのないコードは悪いコードである。どれだけうまく書かれているかは関係ない。どれだけ美しいか、オブジェクト指向か、きちんとカプセル化されているかは関係ない。テストがあれば、検証しながらコードの動きを素早く変更することができる。テストがなければコードが良くなっているのか悪くなっているのかが本当にはわからない。

ここで言うテストとは、テストコードのことを指しています。なぜテストコードがないとレガシーコードなのか、コードがきれいで拡張性が高いだけではなぜ不十分なのか。

新規のプロジェクトが立ったとき、ほとんどのエンジニアは美しいコードを書きたいと思っているはずです。コードがきれいで拡張性が高く、将来の仕様変更や機能追加にも柔軟に対応できるようなコードです。でも、もしテストコードがなかったら、それは達成できません。

テストがないコードはゆっくりと腐っていく

最初に作られたときはどんなに素晴らしいコードであっても、度重なる仕様変更や機能追加、あるいは障害対応によってゆっくりと腐っていきます。最初はあんなにきれいで、拡張性が高くて、仕様変更にも柔軟に対応できるキャパシティを持っていたコードが、そうではなくなります。

ソースコードを変更するたびに、きれいなコードを維持していくよう丁寧にリファクタリングしていればそんなことにはならないのですが、テストコードなしでのリファクタリングは非常に難しいです。「今回は緊急のバグフィックスだからとりあえず動いているしリリースしよう」だとか、「外部仕様的に変更したい箇所はここだけだけど、複数の機能から使われてるからコピペで別クラスを作って対応しよう」だとか、そういう理由でリファクタリングが行われず、一度リリースされてしまった機能については、「動いているコードを触るのはよくない」とコードの汚さが正当化され、数年の月日を経てコードが腐っていきます。

テストコードがあると、何が違うのか

テストコードがあると何が違うのでしょうか。手動テストでしっかりと動作を保証してやれば、問題ないのではないでしょうか。

テストコードがあるということは、テストの実施にかかるコストがほとんどゼロだということです。例えばリファクタリングを施すとき、1ステップの修正ごとにテストを実行できます。手動テストではテストの実施にかかるコストがゼロにならないので、こまめにテストをするとそれだけ工数がかかってしまいます。だからコーディングが終わったあとにテストを実施することになりますが、コーディングが終わったあとのテストでバグが出ても、それがどの作業によるものなのかがすぐにはわかりません。いざ原因をつきとめて、そこを修正したことによって他の部分に問題が出る可能性もあります。

技術的負債を返済する

レガシーコードに苦しみながら、テストコードを一向に書かずに手動テストを実施している、、これは技術的負債の利子を払っているだけで、負債は全く減っていません。技術的負債を返済するには、テストコードを書かなければいけません。

技術的負債に苦しむ現場では、「誰だよこんなコード書いたの!」的な喚き声が聞こえてくることがあります。ただ、大抵の場合そのコードを書いた人が犯人ではありません。修正した人も犯人ではありません。テストコードを書かない文化、開発プロセス、に問題があります。

テスト駆動開発のプロセスの素晴らしさ

テスト駆動開発の開発プロセスの素晴らしさは、コードは生まれた瞬間から既にテストコードが存在している点です。開発中ですら、レガシーコードになることが一瞬もありません。「実装コードを書く前にテストコード書く」ただそれだけのことが、レガシーコードを永遠に産みださない夢のような現実です。