初めてTDDやってみたら、身に沁みてTDDの 〝良さ〟 を理解した話

この記事は「ウィルゲート Advent Calendar 2024」の 9日目の記事です。 adventar.org

こんにちは、プロダクト事業部開発グループ ソリューション開発ユニットの武田です。

直前で参画していたプロジェクトで、TDD(テスト駆動開発)をする機会がありましたので、それについての経験談やメリット等をお話させて頂きます。

この記事で分かることは以下のとおりです。

  • TDD(テスト駆動開発)の概要
  • TDDのメリット
  • 実際にTDDをやってみての感想

以下の内容には言及しないのであしからず。

  • 厳密なTDDについて
  • TDDの詳細
  • TDDの実例

はじめに

ある日のウィルゲートの執務室。
とあるプロジェクトでPM兼エンジニアをしていた武田はとある不安を抱えていた。
「障害を出したくない……」
開発者であれば誰しもが直面する不安だが、こと今回においては少々事情が違った。

  • 既存プロダクトと社内の業務システムを新しく連携するプロジェクト
  • 業務システムでは、顧客との契約、進行状況、納品結果などを管理している
  • 問題が発生した際の影響範囲が大きく、対応もそこそこ大変になる

こういった理由から、より不安を助長させてしまっていたのだ。
その時、以前聞いた先輩の話が武田の脳裏をよぎる。

「武田くん、よく覚えておくといい。TDDは開発スピードを保ちつつ、障害やバグの可能性を抑えることができるんだ。」(意訳)

その話を思い出した武田は「絶対に障害を抑えてみせる」という強い気持ちと共に、今回のプロジェクトにTDDを取り入れることを決意したのだった。

TDD(テスト駆動開発)とは

SmallTalk や JUnit の開発者である Kent Beck によって考案された、テストファーストなソフトウェア開発手法の一つです。
以下のサイクルを繰り返して、目的とする機能を実装していくのが特徴です。

  1. 実装したい機能のテストコードを書く
  2. テストをパスする最低限のプログラムを実装を行う
  3. 実装したプログラムをリファクタする

出展: テスト駆動開発(TDD)とは?目的やメリット・デメリット、やり方を解説

TDDのメリット

TDDのメリットは主に以下が挙げられます。

仕様が明確になる

"何を作るのか" が明確になり、悩んだり迷うことなく実装に集中することができる。

バグを早期に発見できる

テストを実行しながら開発を進めるため、不具合に気づきやすくなる。

安心してリファクタすることができる

常に動作を保証するテストコードが存在するため、デグレが発生しにくくなり安心してリファクタできる。

実際に取り入れてみて

結論から言うと、今回のプロジェクトにTDDを取り入れたのは正解でした。
おかげさまで納期を守りつつ、大きな障害を起こすこともなくプロジェクトを終えることができました。
様々な恩恵を受けることができたのですが、中でも以下の点が大きかったです。

  • 早期に設計へ立ち返ることができる
  • 安心してコードを記述できる
  • 何よりレビュワーに優しい

早期に設計へ立ち返ることができる

開発を進めていく中で、テストコードが書きづらいクラスやメソッドが度々現れました。
テストが書きづらい主な原因は、設計に起因していることが多いです。

  • 単一責任の原則に反している
  • 他モジュールとの結合度が高すぎる
  • インターフェースが複雑すぎる など

これらの要素はテストコードを書く難易度を上げてしまいます。
しかし、TDDは テスト→実装→テスト の小さなサイクルを頻繁に回していくので、早い段階で設計が悪いことに気づき、設計へ立ち返ることができました。

これは蛇足ですが、当プロジェクトの後に、業務システムを変更するプロジェクトを控えており、今回開発した機能にも改修が入ることになっていました。
しかし、今回の件で変更に強い設計することができたため、コストを抑えて改修することができそうです。

安心してコードを記述できる

TDDのメリットをモロに享受することができた例です。

実装をする際は様々な不安がつきまといます。

  • 本当に仕様を満たせているのか?
  • 他の機能に影響が出ないか?
  • バグを孕んでいないか? など

しかし、TDDはテストコードを最初に書くことによって、 "仕様を明確" にしつつ "動作を保証 " しながら開発を進めることができます。
これらによって生み出される安心感は、我々の負担を低減し、開発生産性の向上に寄与してくれました。

何よりレビュワーに優しい

これはTDD自体の恩恵というよりも、TDDの副産物によるメリットかもしれません。

プルリクエストのレビューは、様々な観点を元にコードとにらめっこする必要があり、レビュワーに少なくない負担がかかります。
しかし、テストコード自体を仕様書とみなせば、レビュワーの仕様理解にかかる時間が減ります。また、テストをパスしている = 仕様が満たせている と考えることもできます。
さらに、TDDを実践できていれば、各クラスが適切な粒度に分割されているはずです。すると、自然とプルリクエスト1つあたりの大きさも小さくなり、レビュワーがコードを理解するのにかかる時間を低減することができます。

もちろん、TDDによって全てが楽になるわけではありません。しかし、これらの恩恵によってレビュワーの負担を低減することができ、より重要な部分のレビューに集中することができました。

感じた課題

基本的にはメリットが多かったものの、以下のような課題や課題になりうる部分もありました。

  • テストコードを書くのに慣れていないと開発にかかる時間が伸びる
  • チーム内でテストファーストを浸透させないと、TDDが形骸化することがある
  • そもそもテストの内容が間違っていたら意味がない

しかし、今回のプロジェクトのメンバーは元々テストの重要性を理解している人が多く、テストファーストの浸透も早かったです。そのため、TDDが形骸化することはありませんでした。
また、スプレッドシート等を駆使して、テストの網羅性を担保していたため、テストが漏れるということも少なかったです。

逆にテストに慣れていないジュニア層が多いプロジェクトだったりすると、今回挙げた課題が表面化してくるかもしれません。

おわりに

ここまで読んでくださりありがとうございます。

記事の頭で先輩が話していた

「TDDは開発スピードを保ちつつ、障害やバグの可能性を抑えることができるんだ。」(意訳)

を実際に経験することができ、さらには成功と言える結果で終えることができました。
安心感による開発生産性の向上やレビュワーの負担が減る、不具合修正に時間を取られない等のメリットから、むしろTDDした方が開発スピードが早くなったくらいです。

一方で前提となるスキルや知識が必要だったりと、いわゆる「銀の弾丸」ではないこともわかりました。

今後はプロジェクトの性質や条件を見極めつつ、積極的にTDDを取り入れていこうと思います。

「ウィルゲート Advent Calendar 2024(https://adventar.org/calendars/10272)」、翌日は野中さんによる「Grafanaマイグレーション完全ガイド」です。 お楽しみに!