自動テストの経験がないエンジニアが「テスト駆動開発」を読む

# 書籍 : 「テスト駆動開発」を読んで
駆け足でしたが、Kent Beck著の「テスト駆動開発」を読み終えたので、本書を手に取ったきっかけから、読み終えての感想、今後更に知識を拡げたいと思った方向性についてまとめてみました。

## 投稿者のバックグラウンド
自社サービスの開発にバックエンド・インフラ中心に携わるエンジニア3年目。
言語はPHP(Laravel/CakePHP)やJavascript/Typescript(React)。
**個人、チームともに自動テストの本格的な経験はなし。(2023/12/12追記 : ※執筆時点の在籍チーム)**
読み始める前はチュートリアルでphpunitを少し動かした程度。

## 手に取ったきっかけ

- 自社で開発・運用中のサービスが種類もボリュームも増えてきた中、エンジニア、営業メンバー総出でのマニュアルテストによる品質の担保に限界を感じ始めてきた。
    - これまでもチーム内でテストを導入するかという話になったことは度々あったが、ビジネスの拡大フェーズでの最中にあり、①テスト自体のメンテナンスコストを抱えきれない、②参画メンバーのテストの習得にかけられる時間を捻出できない、等の懸念が多く見送られてきた。
    - 上記のような懸念を払しょくできるような、**効率の良いテストの回し方**はないか、というような淡い期待をもって手に取った。
- 加えて私個人としても、現在のエンジニアリングにおいてほぼ必須とされる自動テストの経験が皆無であることにスキル的な焦りがあり、**自動テストへの入門を兼ねて読んでみたい**と思った。

## 読み始める前に本書に対して持っていたイメージと誤解
- 「効率の良いテストの回し方」を説明する本、ではない。
- 自動テストのやり方自体を説明している本ではない (戦略は説明されています)。

なんというか色々と誤解していたと思います。ただ、イメージと違うので悪かったかというとそうではなく、今後のためにも読んでよかったと思える1冊でした(テストはまともに書けるようになろうと心に決めました)。

# 本書の概要

## 1. テスト駆動開発 (TDD : Test Driven Development) とは
[テストを書く] → [テストを動かし失敗させる] → [テストが成功するようにコードを変更する] → [テストを動かし成功を確認する] → [リファクタリングを行う]というステップを、できる限り小さなサイクルで回し続け、その繰り返しによって「動作するきれいなコード」を書くことを目的とします。

ただし、著者・訳者ともに度々指摘しているように、

> TDDは分析技法であり、設計技法であり、実際には開発のすべてのアクティビティを構造化する技法なのだ。*1

> テスト駆動開発における質の向上の手段は、リファクタリングによる継続的でインクリメンタルな設計であり、「単なるテストファースト」と「テスト駆動開発」の違いはそこにあります。*2

テスト駆動開発とは「単にテストを先に書く開発方法」ではなく、上記のサイクルを通じて開発プロセス全体を構造化することで、継続的な設計改善をコードにもたらすことを目的とした開発手法である、と読みました。


### 1-a. テスト駆動開発の種類と本書が対象とするテスト駆動開発について
本文中でも著者が、また、訳者による解説付録でさらに詳しく取り上げられていますが、テスト駆動開発にも現在様々な潮流があるようです。その中でも本書で一貫して取り上げられていたのは「一人で実践できるテスト駆動開発」でした。

## 2. 小さなステップでテスト駆動の開発を進めるために
テスト駆動開発で重要なのは、失敗するテストを書くことから、テストを通しリファクタリングを行うまでのプロセスを、いかに小さなサイクルで行うことができるかです。
本書ではそのサイクルを小さく抑えるために、コードを変更する実装フェーズにおいて、テスト駆動開発で利用される実装の戦略が紹介されていました。

### 2-a. テスト駆動開発の戦略① : 仮実装
やや慎重。ベタ書きの値や空のクラスや関数の実装を行い、ひとまずテストを通す(それらを修正するのは次以降のサイクルにおける関心ごととする)。

### 2-b. テスト駆動開発の戦略② : 明白な実装
スピードモード。書くべきもの (実装) が頭に浮かんでいるときは、その実装をすぐにコードに落とし込んでテストを回してみる。

### 2-c. テスト駆動開発の戦略③ : 三角測量
最も慎重な実装戦略。例えば2つの数字を足し合わせる関数をテストする際に、2つ以上の異なる条件でアサートを行う。2つのアサート文を満たすためには実装はべた書きではなくより一般化された形で行われる必要があるため、リファクタリングの過程で使われる。

上記のような戦略を、自らの自信の度合いによって絶え間なく行き来することで、テストの力をかりて、時には慎重に、時には大胆に実装を進めつつも、継続的にリファクタリングを行っていきます。

本書では、著者が実際にこれらの戦略を用いながら、「多国通貨間の加算」のコードを例題として (非常に細かな) ステップバイステップでテスト駆動開発と解説を行っています。

## 3. テスト駆動開発と設計
これまでコードを書く時には、初めに全体の設計を練った上でそれに沿うような形で実装を進めていくことの多かった私にとって、テスト駆動開発において設計はどのように考えられているのか、というのはとても興味深い点でした。

著者ももちろんこの点については触れており、「「きれいな」に最初に取り組み、そのうえで苦心してあちこち設計の辻褄を合わせながらどうにか「動作する」を実現させる」アーキテクチャ駆動(*3)とは異なり、テスト駆動開発では「テストとコードの間の重複除去が、設計を駆動する」(*4)と述べており、テストとコードの間の重複除去のプロセスが、ナチュラルに良い設計に導いてくれるという立場である事だと思います。

> 独立したテストを心がけると、凝集度が高く、かつ結合度が低い小さなオブジェクトたちをたくさん組み合わせて問題に立ち向かうようになる。それはとても筋の良い設計として知られているし、そんな設計にたどり着けたときには喜びを感じるものだが、そもそもそのような高凝集かつ低結合の設計に無理なくたどり着く方法を、独立したテストを意識するまでは知らなかったのだ。*5

## 本書をどう読むか
今回はだいぶずれた形でイメージを持ったまま読み始めてしまったので、続きが気になる、からの最後まで読み進めてしまいましたが、2周目も間違いなくします。
その際には訳者の方もおすすめされているように、ペアプロ感覚で写経しながら読み進めてみたいです。

というのも、読んでいるだけでも感動したのが、(特に1部と2部については) 非常に細かいステップでコードの修正と解説が行われており、そのたびにコード例も記載されています。まるでライブコーディングを見ているかのような感覚にもなるほどのものだったため、凄腕プログラマとの貴重なペアプロの機会という意味でも、本書と対話しながらコードを書きたいと思いました。

## 本書をどう活かせるか
**1. テスト駆動開発のリズムを習得するためのチュートリアル本として活用する**
本文中でもテスト駆動開発は個人スキルと度々述べられているとおり、まずは個人で試してみるのがよいと思いました。<br>
読了後、実務でいくつかの機能追加を、拙いですがテスト駆動で行ってみましたが、チームでテストを導入していなくても、個人でテストを書く、他人に強制しない分にはまず怒られません。
またスピード的にも、不慣れな現時点でも普段と同等程度には出ていました。これについてはテスト駆動開発が、というよりもコードを変更するたびにマニュアルでテストする負荷が単に下がっただけかもしれません。

**2. テスト駆動開発に関する学びを拡げるための出発点として活用する**
本書の中で個人的に気に入った章が巻末の訳者によるテスト駆動開発の現在についての解説でした。本書のテーマを取り巻く複数の議論を俯瞰して捉えられることで、頭の整理や今後学びたい内容を探すうえでも非常に為になる章だと思います。

## まとめ
マニュアルテストの負担感と、自動テストのスキルがないことへの不安感から手に取った本書の想定読者としては、ある意味私はどストライクだったかもしれません(本書の原著執筆当時は自動テストを行っているエンジニアは少数だったとのこと)。
とはいえ、多くのエンジニアが当たり前のように自動テストを行うようになった現在においても良書として読まれ続けているということであれば、2周目ではまた違ったものが見えてくるかもしれません。

本書を通して①テストを書くこと = 開発プロセスへの単純な負担増加ではない、②個人としても実践できるテストを活用した体系的なプラクティスをいつでも参照できる状態にある、と感じることができたため、まずは当初の問題意識に立ち戻って、実際に自動テストへの習熟と実践を行ってみたいと思います。
効果がしっかり説明できるのであればいつかチームとしても取り組んでみたいですね。

## 書籍情報
著者 : Kent Beck
訳者 : 和田 卓人
書籍名 : テスト駆動開発  
注釈 : Kindle 版

## 本文からの引用
すべてのページ数はKindle版におけるページ数です。

*1 : p471
*2 : p520
*3 : p38
*4 : p260
*5 : p336

## この記事について
- この記事および私の発言については個人の見解であり、私の所属企業を代表するものではありません。
- 執筆時点での所属チームと現在所属中の企業およびチームとは異なります。