テスト駆動開発のはじめの一歩|t_wadaさんに聞く1人で始める自動テストのコツと考え方

和田卓人(t_wada)さんテスト駆動開発の始め方メインカット

アジャイル型の開発が導入されていない現場であっても、そして一人であっても、実践可能なアジャイルに関するプラクティスは存在します。

例えば、自動テストや、テストファースト、テスト駆動開発(TDD:Test Driven Development)です。ユニットテストフレームワークを使ってテストコードを書いて開発しながらテストを実行する「自動テスト」、実装の前にそのテストコードを書く「テストファースト」、テストと実装を繰り返しながらインクリメンタルに設計・開発を行うのが「TDD」。これらプラクティスのなかで、はじめの一歩となるのが自動テストですが、1人で実践するには、どこからはじめるか、どうテストを組み立てればよいのか、あるいは自分のテスト方法は適切なのか、不安を持つこともあるでしょう。

そこで本稿では、さまざまなチームや組織へのテスト手法の導入を支援し、精力的に講演や執筆などを行ってきたこの分野の第一人者、ITコンサルタント・ソフトウェアエンジニアの和田卓人(わだ・たくと / @t_wadaさんに、1人で自動テストやTDDを実践するにあたっての手法や考え方について話を伺いました。

和田さん自身が1人で自動テストをはじめたときの経験や、初学者へのアドバイス、自動テストやTDDに対する考え方、テストがないプロジェクトの攻略法、そこから成長していくための心得など、テストを軸によりよい設計・開発を行うためのヒントが満載です。

和田卓人(t_wada)さんテスト駆動開発のインタビューカット 取材はリモートで実施された

テストが嫌いだったからテストコードを書きはじめた

──最初に和田さんご自身のお話を伺いたいと思います。和田さんが一番最初に実施した自動テストやTDDはどのようなものでしたか。

和田:2001年ごろ、受託開発でJavaで書いていたときに、JUnitを知って自分のコードに対してテストコードを書きはじめたのが最初でした。プロの開発者になって1年か2年目ぐらいでしたね。

なぜテストコードを書きはじめたかというと、テストが嫌いだったからです。自分の書いたコードに対して、後から手動で動作確認したり品質保証したりするのが苦手だったんです。若手のプログラマにありがちかと思いますが、作るのは楽しいが、作り終わると楽しくないという。またこれも若手にありがちなんですが、自信過剰で自分が書いたコードにバグはないよと思っているため、後からテストでバグが出てくると、あまりよい気持ちがしない。だから苦手だなと感じていたんですね。

そうしたときに、2000年ごろに日本でもアジャイルソフトウェア開発の手法としてエクストリームプログラミング(XP)が話題になり、その中で自動テストやJUnitを知りました。

自動テストには、個人的にものすごく衝撃を受けました。テストは嫌いだけどプログラミングは好きなので、「テストもコードで書いていいんだ、プログラミングの対象にできるんだ」というのが衝撃だったわけです。

そうして自分が書いたコードに自分でテストを書くようになると、まずプログラミングの対象が増えて嬉しいし、よい効果が生まれることも経験できて、次第にテストコードを書くことにのめり込んでいきました。そもそも嬉しかったのは、自分でテストコードを書くと自分でバグを見つけられることですね。他人にバグを指摘されると情けない気分になりますが、自分で見つけるのはあまり嫌じゃない。その結果、自分のレベルが上がっていく感じがしました。

──自動テストを実践しはじめたころ、難しさや課題を感じたことはありましたか?

和田:当時は全部をテストしようと思っていなかったので、課題や難しさはあまり感じませんでした。身も蓋もない答えになってしまいますが、「高望みしなかったのであまり困難がなかった」という感じです。そのころは自動テストについての情報が少なかったわけですが、少ない情報の中でできることをやるぐらいの期待値だったので、あまり苦戦しなかった感じですね。

まずは真似から、手を動かすところから入る

──情報が少なかったから期待値が低く、難しさを感じなかったと。

和田:現在は状況が大きく違います。情報はものすごく多く、その分、期待値も高くなる。自動テストを書くのもわりと当たり前になっています。

その中で、これまであまりテストを書いたことがないという人には、学習コストが問題になってきます。自動テストの世界って、実装コストはそれほど高くないんですが、それは自動テストの書き方をわかっている人の話で、まったくわからないところから書きはじめるにはかなり難しさがあります。現代においてはその学習コストの山を越え、自動テストの効果を実感できるようになるまでが、一番のハードルになっていると思います。

──そんな中で初学者がこれから、1人で自動テストやTDDに取り組もうと思ったら、どのような方針で学んでいくのがよいと思いますか?

和田:アジャイルな開発プラクティスの中で、例えばペアプログラミングは仲間がいないとできませんよね。それに対して、TDDや自動テストはプロセスと独立していますし、1人でもできます。アジャイル型のプロジェクトじゃなくても、例えばウォーターフォール型のプロジェクトの中でも1人で取り組めますし、1人で成果を出せます。これはとてもよいところだなと思っています。

では、どのようにして1人で学習していくのか。これは、基本的に真似から入ることをお勧めしています。いわゆる写経(書籍などのサンプルコードをそのまま入力して動かしてみること)やチュートリアルですね。

なぜかというと、手を動かして学ぶのが最も効果の高い学習方法だと考えているからです。自動テストについて本やプレゼンテーションで学ぶだけでなく、実際にテストコードを書いて、「開発に自信がつく感じ」や「不安が薄れる感じ」といった心理状態を経験してもらうのが大事だからです。

もう一つ、技術の世界は、やってみて初めてわかるものが多いんですよね。「こういうものだ」と頭で決めつけて理解した気になるよりも、実際に手を動かし経験として知識を取り入れる体験が、少なくとも自動テストに関しては大事だと思っています。

そして、実際にやってみると、「最初に思っていたのと違う」という体験をすると思います。TDDや自動テストという言葉だけを聞くと、テストの部分、つまり何かを検証する工程というイメージが強いと思いますが、体験してみると、もっと開発や設計に近いプログラミングテクニックだと気付きます。こうした気づきは、やってみないとわからないところなので、ぜひ手を動かして学んでみてほしいと思います。

あと、そうして手を動かして学ぶときに初学者がつまずきやすいのは、その前段の環境構築なんですね。動かしはじめるところで挫折することもすごく多い。真似から入るということで、学習教材として、例えばGitHubからダウンロードして即動かせるものや、Webブラウザ上でそのまま動作を試せるものなどを選び、環境構築の手順を飛ばしてはじめるのも初学者にはよいと思います。最近ではテストコードを書くときにAIに支援してもらうような場面も増えてきていますので、そういった支援ツールを併用するとつまずきにくくなると思います。

最初に思ったものはだいたい間違っている。大切なのはフィードバック

──ここから、TDDの実際のスキルに関して伺いたいと思います。

イベント「TDD Boot Camp 2020 Online」での和田さんによる基調講演「見てわかるテスト駆動開発」の動画で、FizzBuzz問題を題材にJavaとJUnitを使ってTDDのライブコーディングをしているところを拝見しました。

ここにあるように、まず最初はタスク分割によるTODOリスト作成になると思います。動画ではまるで魔法のようにスムーズにタスクが分割され、TODOリストへと整理されていましたが、これは初学者にとってはそんなに簡単ではなく、つまずきポイントなんじゃないかなと思いました。これをどうクリアするかについてお聞かせください。


動画内で和田さんがデモを行ったFizzBuzzの問題は以下引用の通り

1から100までの数をプリントするプログラムを書け。ただし、3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

この問題を和田さんは以下のようにTODOリストへと整理する。

[  ] 数を文字列に変換する
[  ] 3の倍数のときは数の代わりに「Fizz」に変換する
[  ] 5の倍数のときは数の代わりに「Buzz」に変換する
[  ] 3と5両方の倍数のときは数の代わりに「FizzBuzz」に変換する
[  ] 1からnまで
[  ] 1から100まで
[  ] プリントする

問題文、TODOリストともに動画「 TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング」より抜粋引用


和田:いい質問です。僕はTDDの啓蒙をもう17〜8年ぐらいやってますからね。経験を重ねたのでスムーズにできるだけで、普通はあんなにスムーズに行くわけはないんですね。

複雑なものを複雑なままにせず、単純なものの組み合わせに分割して解決するというのが、ソフトウェア開発の歴史によって得られたモジュール化の原則です。TODOリストの作成は、これを、やることリストの形で具現化したものです。作ろうとしているものを要素に分割して、その中でより単純なものから順番に倒していく(テストコードを書く)わけです。ただ、言うは易しで、これができればすでに熟練者なんです。

TODOリストの作成はTDDの中でも一番難しい部分なので、初学者にはできないことをあまり気にしないでほしいですね。設計の要素が大きいですし、後ほど説明する「テスト容易性」がわかっていないと分割しにくい。ですので、初学者ヘの第一のアドバイスとしては「TODOリストの作成は、だんだん上手くなるので、最初は気にしないでください」となります。

その上で、要素を階層化してピラミッド構造のツリーを作る訓練は有効だと思っています。いわゆる段階的詳細法ですね。難しいものを中ぐらいの要素の組み合わせに分割して、その要素をさらに分割して、というのを繰り返して、対象をトップダウンで分割していく訓練です。

しかし、大事なのはここからです。そうやって得たものをその通りに作ろうとしないことです。最初に思ったものって、だいたい間違ってるんですよね。その間違いに気付いてよりよいものに近づけていくという、フィードバックを反映して方向修正していくのが、TDDにおいて肝心なところです。

手を動かして作っていくと、やっぱりこれが必要とか、あるいはこれは考えすぎとか、そういったフィードバックが自分の中にやってくるんですね。頭ではこっちのほうがきれいと思っていたけど、書いてみるとこっちの方がきれい、というのもプログラミングにはよくあります。それをとにかく設計に反映し続け、TODOリストにも反映し続ける。それによって、地に足のついた設計と実装ができあがる。TDDはこれを目指しています。

最初はピラミッドのような構造を想像できないと拠り所がないし、逆に最初に作ったピラミッドにこだわってるとよいものはできない。そのバランスを取っていくには、フィードバックが回らないとできない。なので、テストを書いてリファクタリングをしてフィードバックを回していこうというイメージです。

──最初にTODOを上手に書けないと、書くテストもよいテストにならないだろうと思っていたのですが、お話を聞くと、まずはそれでよいということですね。

和田:そうです。最初に考えたものは間違っているという前提に立てるかどうかが、一つの分水嶺なんですよね。フィードバックを大事にするということです。

初学者の最初は、できるところからはじめる、あるいは、「作り方はわからないけどこうなってほしい」という最終ゴールから決めるのでも構わないですね。「これはやらなきゃいけないだろう」というものを羅列するだけでも構いません。

──もう一歩進んだときに、業務で直面する仕様は一定でなく、複雑なものもあります。そのときにTODOやタスク分割を考える上で、汎用的な考え方はあるでしょうか?

和田:そうですね。先ほどの質問ともつながりますが、その場合も段階的詳細法のように、対象を要素に分解して把握する手法が参考になると思います。特に、抽象的なものから具体的なものへと枝分かれしながら降りてくる構造を作る練習ですね。これはテストに限らない汎用的なテクニックで、タスク分割に取り組んでいく上で基本として拠り所になると思います。

そしてツリーをつくる際も、だいたい最初に作ったツリーよりも途中でもっとよいツリーが見つかります。フィードバックを反映して最初とは違うツリーになることを躊躇しないことが大事だと思います。

初学者や生真面目な方が陥りがちなのが、最初から完璧な設計をしようとすることです。TDDの研修を行うとTODOリストを作るのに1時間ぐらいかける人もいますが、それはやりすぎですね。ツリーは途中で形が変わるので、まずは叩き台となるツリーをざっくりと作るのがスキルとして大事だと思います。

テストしやすいところからはじめて、テスト容易性の感覚を磨く

──先ほどのライブコーディングの動画でも、タスク分割のときにテスト容易性の話がありました。Javaの場合は「プリントする」という項目はテストが難しいから後に回すというように。ただ、こうしたテスト容易性の高低を判断するには経験が必要かと思います。テスト容易性について、どのような考え方やものさしを持てばよいかお聞かせください。

和田:TDDや自動テストでは、テストが書きやすい設計を意識して問題を分割するのが効率的です。テストできるところをなるべく増やしながら開発を進めることによって、より「確からしい開発」ができるということですね。

自動テストにおけるテスト容易性は、大きく分けて「観測容易性」「制御容易性」「対象の小ささ」の3つで構成されます。

観測容易性は、テスト対象の振る舞いや結果が、自動テストから調べやすいかどうかです。例えば、テストコードからアクセスしにくい奧のほうで副作用が起きるようなものは観測容易性が低い。また、FizzBuzzの例で挙がった「プリントする」という部分は、人間は目で見ればよいのですが、Javaから標準出力への出力みたいなものを見るのは結構難しい。このようにテストコードから調べやすいかどうかが観測容易性です。

制御容易性は、もっとシンプルで、テストコードから動かしやすいかどうかです。単純なコードであれば動かすだけでよいのですが、ネットワークとかデータベースとかいったものが絡むと、いろいろ準備が必要でテストから動かしづらくなります。このような状態を制御容易性が低いと表現します。

まずはこの2つが満たされていれば自動テストが書けます。さらに、それらに加えてテスト容易性に影響するのが対象の小ささです。テスト対象が狭く小さいほど、テストの範囲が狭くなって、テストが書きやすくなり、テストの確からしさも自分で確信しやすくなります。この3つがテスト容易性を支えている構成要素です。


先に引用したFizzBuzzにおけるTODOリストは、テスト容易性、重要度を軸に、以下のように整理されている。

テスト容易性:高 重要度:高
[  ] 数を文字列に変換する
[  ] 3の倍数のときは数の代わりに「Fizz」に変換する
[  ] 5の倍数のときは数の代わりに「Buzz」に変換する
[  ] 3と5両方の倍数のときは数の代わりに「FizzBuzz」に変換する

テスト容易性:低 重要度:低
[  ] 1からnまで
[  ] 1から100まで
[  ] プリントする

動画「TDD Boot Camp 2020 Online #1 基調講演/ライブコーディング」より抜粋引用


その上で、テスト容易性の高低の判断ですね。まず対象の小ささについては、「長い関数より短い関数のほうがテストしやすい」というように単純に捉えてもいいでしょう。

あとの観測容易性と制御容易性ですが、これらは経験やスキルの問題となりますね。経験を重ねると熟練度が上がり、「テストが面倒だから、こことここは分離しとこう」とか、「ここは動かしにくいから分離して、動かしやすいところを広めに取ろう」とか、そういったことが考えられるようになります。まずは、「テストしやすいとは何か」「テストしにくいとは何か」について感覚をつかむことが必要になっていきます。

──和田さんが初めて自動テストを行ったとき、やれそうなところをやってみたとおっしゃっていましたが、そのときもテスト容易性のようなことを意識されていましたか?

和田:意識していたというよりも、小さいところからやっていったので、結果的に観測容易性や制御容易性が高いものを選んでいったことになります。

なので初学者の人は、網羅的にテストしようと考えない、期待値を高くしないっていうところが大事で、テストのやりやすいところから自動テストを取り入れていくのがポイントですね。

腕が上がってくると、テスト容易性の低いところの面積を最小にして、テスト容易性の高いところの面積を最大にできるようになってきます。そうすると、テストを書きにくい狭い範囲は別のやり方でやろうという判断もできるようになります。

初学者の人は、現状の設計に対してテストコードを書いてみて、どういうようなテストがやりにくいという感覚を磨き、経験を重ねるのが大事だと思います。

テストがなくテスト容易性の低いコードは、大外から攻める

──テスト容易性の低いものをテストしなければならないときには、どのようなアプローチが考えられるでしょうか?

和田:テスト容易性の低い対象にテストを書こうとすると、「テスト対象のコードの設計を変えないとテストを書きにくい、でもコードを安全にいじるためにこそテストを書きたい」というジレンマに陥ります。でも、やっていくしかない。

そこで最初は、テストを書きにくいのは承知の上で、大外からテストを書いていきます。つまり、エンドツーエンドテスト(E2Eテスト)やインテグレーションテストといった、内部の設計にあまり影響を受けない自動テストを書いて、粗くテストで包んでいくイメージです。Webシステムであれば、SeleniumやPlaywrightに代表されるブラウザ操作の自動化などを利用して、ユーザー操作と同じレベルでテストします。内部のコードがどれだけ汚かったとしても、ユーザーが操作できる部分についてはテストもできる、というざっくりしたアプローチですね。

粗くカバーできれば、内部の設計に手を入れる余地が得られます。手を入れて、もしもシステムがおかしくなれば、テストが失敗してくれるという確信ができるわけですね。そうして中の設計をじわじわテストのしやすい設計に変えていく、というやり方をするわけです。

こういった一連のアプローチを「アイスクリームコーンからのテストピラミッド」と呼んだりします。「テストピラミッド」は、以下の図を見てもらうのが早いでしょう。

テストピラミッドの図版

これは、自動テストを、ユニットテスト、インテグレーションテスト、E2Eテストという3つの階層で考えた際、下に階層に行くほど、テストケース数が多いのが望ましい、という比率を、ピラミッド型の図版として表現したものです。「アイスクリームコーン」とは、その逆のアンチパターンで、「上の階層に行くほどテストケースが多い」という比率を示しています。

アイスクリームコーン型の図版

しかし、既存のテストコードが一切ないところからピラミッドを作るのは困難です。そこで最初はアイスクリームコーン型でもよくて、それをじわじわとピラミッド型に変えていくやり方、つまり「アイスクリームコーンからのテストピラミッド」なアプローチが必要というわけです。

このとき、E2Eテストで粗く包めているならそれが一番コスパがいいじゃないかと感じる人も多いでしょう。でも、短期的にはよいのですが、中長期的にはコスパが悪いのです。E2Eテストは動作が遅くて不安定で、テストが偶然失敗する状況も少なくないため、結果的にテストの結果をみな信用しなくなってしまう。また、E2Eのテストケースが増えると、実行時間がかかりすぎる。ですから、やはりピラミッド型に寄せていきたいわけです。

──では、アイスクリームコーン型をピラミッド型にしていくにはどのような手法が考えられるでしょうか。

和田:テクニックとしては、Test DoubleやHumble Objectという手法を使ったりします。

Test Double(編注:ここでいうDoubleとは「身代わり」のようなニュアンス)は、テスト用の偽物を使うテクニックです。モックやスタブといったテクニックが代表的です。偽物を使うことによって、テストのサイズを下げたり、インテグレーションテストをユニットテストにしたりします。

もうひとつのHumble Objectとは、FizzBuzzのTODOリスト作成でも出てきたように、テスト容易性の高いところと低いところに分けて、テスト容易性の低いところをすごく狭く薄くして脇にどけておくという設計パターンです。データベースやネットワークを扱うようなテストが書きにくいところを狭くしておいて、そこはTest Doubleを使ったりE2Eテストでテストしたりする戦略です。

こういった基本パターンについては、雑誌『WEB+DB PRESS』の「サバンナ便り」というコラムで述べたものと、それをプレゼン資料にまとめたものがあるので、そのあたりを参照していただければと思います。

──「仕事の中で自動テストを実践する」ケースでは、テストコードが存在せず仕様もよくわからない、いわゆるレガシーコードに直面することがあると思います。

和田:仕様がわからないということは、たぶん自分が書いたコードじゃなくて、ドキュメントを探してもドキュメントがない、あるいはドキュメントはあるけどメンテされてなくて目の前のコードとずれているということですね。むちゃくちゃよくある状況ですね。

こういったときにどうアプローチするかについては、書籍『レガシーコード改善ガイド』で扱われています。

同書に出てくる、仕様化テスト(characterization test)を書きます。ここでは、仕様がわからないので、「どうあるべき」という「TO BE」は失われていると考えてあきらめます。では何に対してテストを書くかというと、「AS IS」つまり「現状」に対してです。「現状はこう動いてる」というのを、自動テストとして写し取っていきます。

「こうあるべき」という仕様のゴールがわからないので、テストのゴールをもっと手前に設定するわけです。テストの結果、動きが変わったかどうか、つまりいじって壊したかどうかがわかればよいというゴールにする。壊したかどうかは、現状と動きが変わったかどうかを調べれば、つまり現状の動きはこうであるというテストを書いていけばわかります。

その際の方向としては、制御容易性から攻めます。対象をどうやって動かすのか調べて、自動テストから無理やり動かせば、対象の動きがわかります。動いたものをテストに移植していき、それを是とする感じですね。それができるようになったら、さっきの「アイスクリームコーンからピラミッド」作戦を実行していきます。

適切なテストコードとは、自信が増えるテスト

──続いて、自分の書いたテストコードの善し悪しを評価する方法についてお聞きしたいと思います。先ほどのライブコーディング動画では「one assertion per test」(テストごとにアサーションは1つだけ)とおしゃっていました。これを基準とすればよいでしょうか?

和田:いえ、その答えはノーです。動画の中ではちょっと言い過ぎたと後悔しています。テストコードのリファクタリングのヒントとして、テストごとにアサーションは少ないほうがよいのは確かです。1つのテストに多数のアサーションがあると、何をテストしたいのかわからないし、テストが失敗したときの振る舞いに問題があるからですね。

ただ、2つ揃ってはじめて意味があるアサーションもありますし、必ず1つにしなきゃいけないというわけではない。あくまで、大まかな指針であり、テストコードは「意味のあるひとまとまりにしましょう」ということだと思ってください。

その上で、いい感じのテストが書けているかどうかというのは、とても大事な問いです。いい感じのテストかどうか評価するためには、短期的な視点と中長期的な視点があります。

基本的に、テストコードが適切かどうかの判断基準は、開発者の自信が増えるかどうかなんですね。もっと言えば、根拠のある自信がつくかどうかです。「自分が書いてきたコードは、少なくとも自分が書いた通りに動いているという自信」および「これからどんな変更が入っても柔軟に対応できるという自信」が大事なんです。

中長期的な視点では、そのよい状態が続くかどうかを考えます。ここにちょっと難しさがあって、今の自分にとってよいテストコードであっても、将来の自分にとってよいテストコードでないことがありえるんですね。これは、将来、どういった設計変更があるかよくわからないからです。そういった将来に対しても自信を持って支えてくれるテストコードになっているかどうかが、中長期的な話です。

ただ、両者はトレードオフの関係になる場合もあります。例えば現状の設計に対してカバレッジを重視したガチガチのテストを書いてしまうと、現状に過剰適応したテストになることもありえます。そうすると、将来やってきた変更に対するメンテナンスコストが高くなってしまうかもしれないわけです。

ですから、将来の変更に対してあまり負荷なくついていけるテストコードというのも目指したい。ただし、これはだいぶレベルの高い状態なので、腕が上がってきたらでよいです。まずは自分の自信を支えられているかどうかが大事です。

──どうしても、テストコードの直接的な書き方の善し悪しに目が行ってしまいますが、目指すところは自信が持てるかどうかということですね。

和田:まずはそうです。

ただ慣れてきたら、その先には、もちろん適切なテストコードというのはあります。リファクタリングを支えるとか、バグを防ぐとか。参考図書を挙げると、『単体テストの考え方/使い方』という本では、よい自動テストには4つの柱がある、といったことが書かれています。

また、自動テストという考え方が登場して20年経ち、10年以上メンテナンスするシステムにおけるテストコードなどについても各組織から知見が示されています。こちらの参考図書としては、『Googleのソフトエンジニアリング』などがあります。

いろいろとわかってきたら、そうした方向を目指すのがよいと思います。

──次も1人でTDDを実践する場合の判断の話で、自分のリファクタリングの正当性を評価するにはどのような考え方があるでしょうか?

和田:この場合の正当性は、自分自身にとっての正当性ですよね。これも先ほどの回答と一緒で、リファクタリング後のほうが自分が状況をコントロールできているという自信を持てれば、それはよいリファクタリングです。

リファクタリング時も含め、「正しい設計というものがあってそこにたどり着くのがゴール」と捉えられがちですが、そもそも設計に「正しい」という状態はないと考えたほうがよいです。「固定的なものを作る」をゴールとするなら正しい設計というのもありえますが、現実のソフトウェア開発ではゴールが動くので、動くゴールについていけるのがよい設計です。

これは将来の変更に備えるということではなくて、どこからでもリファクタリングできる状況や体制、自信の問題ですね。なので、リファクタリングの正当性というのはあまり問題ではなく、リファクタリングを支えて自信を持てる自動テストが必要なわけです。

マーティン・ファウラーが著した書籍『リファクタリング』を読むと、逆向きで対になるリファクタリング手法が多いことに気付きます。例えば、「関数に抽出する」というリファクタリング手法に対し、逆となる「関数のインライン化」というリファクタリング手法があるんですね。これは、状況によって必要な設計変更の向きは異なるので、どちらでもできるようになっておこうという話です。

先ほども言いましたが、「正しい設計」というものはなく、ゴールが変わったらリファクタリングしながらそっちに寄せていく、つまり、ソフトウェア開発というのはリファクタリングし続けることとも表現できます。そして、リファクタリングにはそれを支えるテストが必要です。自動テストをさまざまな粒度でさまざまなところに書いておくことで、動くゴールに対して、リファクタリングしながら追従していけるんです。ゴールはどっちに動くかわかんないけど、どっちに動いてもリファクタリングしながらついていけばいいよ、という静かな自信。これが自動テストによって得られる、大事な心構えだと思っています。

チームに広めるには、押し付けないこと、真似してもらえるようにすること

──続いて、1人で自動テストやTDDを学んだあと、チームや組織に広げる場合についてお聞きしたいと思います。まず、1人で自動テストを書く場合と、チームで取り組む場合で、考え方の違いなどはあるでしょうか?

和田:自分にとって読みやすいテストと他の人にとって読みやすいテストは異なることを理解する必要があります。1人でテストコードを書いていると、自分が一番理解しているので、「ここは説明せずともわかるだろう」という感じのテストになりがちです。他の人はテストコードの読み手になるわけですが、書き手にとっての書きやすさと読み手にとっての読みやすさは異なるという認識を持つといいでしょう。

中長期的には、書きやすいテストコードよりも読みやすいテストコードのほうがずっと大事です。チームでは書き手よりも読み手のほうが多いですし、書かれる時間より読まれる時間のほうが長いですから。もちろん、上達すれば書きやすさと読みやすさは両立できるようになりますが、それは置いておいて。そのためチーム開発の場合は、自分が書いたテストコードを他の人にレビューしてもらったり、ペアプログラミングしたりとか、そういった理解容易性への投資とか備えが大事になります。

──最後の質問です。1人でTDDや自動テストを実践した結果に価値を感じて、それらをチームや組織に広げていけないかと考えたときに、注意すべきことは何でしょうか。

和田:難しいテーマですが、第一原則は「押し付けないこと」です。自分がよいものだなと思うものを、他の人に勧めたくなったときに、押し付ける感じになることがあります。「自動テストを書くのが正しい」という「正しさ」の話や、「プロの開発者なら自動テストを書くべきである」といった「べき論」や「プロ意識」といったトピックとともに語られがちです。しかし、熱く押せば押すほど、周りが引いていくということもあるでしょう。

こうしたトピックが響く人もいれば響かない人もいるので、もし自分以外の人にも広めたいと思うのだったら、とにかく、熱意やプライドの話ではなく、損得や苦楽の話に変換することをおすすめします。「自動テストを書いたほうがラクだし得」という話にするわけです。

背中を見せることで、「ラクだし得」を示せることもあるでしょう。チームの中で自動テストを書いているのは自分だけだったら、自分だけはバグが少なく、仕様変更に対する反応速度が速い、しかもラクしている、というところを見せるのも大事だと思います。

もう一つは、最初のほうでも話しましたが、真似してもらいやすい状況を作るのも大事です。「自分の真似をしてくれればOK」「このテストコードをコピー&ペーストして書き換えれば、あなたのコードもテストできるようになるよ」といった感じで、土台を作って提供するわけです。もし広めたいなら、真似してもらって環境作成や学習のコストを下げる環境を作るところまで自分でやる、ということですね。

自動テストは1人から始められて、自分がこれまで書いてきたコード、これから書いていくコードに自信を持てるようになるプログラミング技術です。まずは真似をして手を動かすところから学び始めてみてください。手を動かすと、見える景色が変わってきます。

──ありがとうございました。

合わせて読みたい関連記事

「1人アジャイル」から始める、アジャイル開発導入のススメ|Agile Journeyローンチによせて

アジャイル開発とデータベース設計 - 変化に対応するシンプルな実装のために必要なこと

カンバンボードで業務を可視化・整理しよう - 組織に合ったカンバンの設計・運用をヴァル研究所の実践に学ぶ

取材・構成:高橋正和
編集:勝野久美子(トップスタジオ)
制作:はてな編集部

和田卓人(わだ・たくと))X(Twitter): @t_wada / GitHub:twada
タワーズ・クエスト株式会社取締役社長。受託開発のプログラマとしてキャリアをスタートさせ、2000年ころにエクストリームプログラミング(XP)、その後テスト駆動開発(TDD)に出会い、傾倒。以降、講演、原稿執筆、書籍翻訳 / 監修などさまざまな活動を通じて、TDDの啓蒙に努める。『テスト駆動開発(オーム社)』『プログラマが知るべき97のこと(オライリージャパン)』『SQLアンチパターン(オライリージャパン)』『事業をエンジニアリングする技術者たち(ラムダノート)』など出版に携わった書籍多数。