アジャイル開発において「テストコードは当然」なのか？

https://qiita.com/aimof/items/d68bdb347283ee2dbccf
を見て、Web開発現場的にはちょっともやっとしたので、書いてみます。

# 言いたいことを３行でまとめると

- テストコードを書くことの有用性そのものは疑いようがない
- ただし、アジャイルやWebサービスの開発においては、 **「テストコードを書くことを当然」** としてしまう事は、開発スピードや品質面において選択肢を狭めてしまう可能性がある。
- テストコードを特別視せず、コードレビューやE2Eテストやユーザテストなど、有限の工数の中で、 **複数の手法がトレードオフにあること** を前提に、プロジェクトの品質管理を考えていくべき

# 前提条件

- スタートアップやWeb開発のように、厳密に定められた納期や開発スコープ、あるいはゴールがない新規・継続開発

# 筆者の属性

- Web系のToCやBtoBtoCサービスを中心に手がけています。
- いまは人材系の自社サービスの運用＋追加開発フェーズを担当。所謂１人体制なので、インフラ（AWS)、サーバーサイド(CakePHP)、フロントエンド(Vue.js)に簡易的なデザインまで全部一人で ~~やらされ~~ やってます。器用貧乏タイプ。
- 業務で扱った事のある開発言語はPHPやRuby、Go、JavaScript、Swift、C#など。どっちかといえば静的言語の方が好きです。
- テスト手法は古き良きエクセルテストも、XUnit系やBDD系のユニットテストも両方経験あり。
- ただし、業務において「基本的にテストコードを全部書く」系の開発チームは未経験です（その点においては、TDDに関する知識・経験はあまり足りてないと思います）
- テストコードを書く事自体は大好きです。がっーとテストコード書いて、最終的にざーっとALL GREENになると脳汁がブシャーってなります。
- アジャイル開発志向です。目指すべきゴールや優先順位が常に移り変わるWebサービス開発においては、アジャイル開発の思想が効力を発揮する、というスタンスです。

# 前提：アジャイル開発における品質とは

アジャイル開発における基本的な考え方に　「トレードオフスライダー」があります。

参考サイト：
*どういう意味で品質って言ってるの？システム開発の現場で品質おじさんと建設的に向かい合う方法*
http://everyday.mof-mof.co.jp/entry/2017/11/01/113924

上記に限らず、トレードオフスライダーに関しては、どのアジャイル/スクラム本にも載っている内容なので詳しい説明は省きますが、要旨をまとめると、以下になります

- すべての機能要件・非機能要件はトレードオフの関係にあり、事前に、あるいは必要になったタイミングで必ず優先順位をつけなくてはいけない
- 逆に言えば、特定の要件を絶対視してしまう事（＝フォース）はできるだけ避けるべきである。特に開発においていくつものフォースを作ってしまうことは、スケジュールの不安定化や非健全化、それに伴う品質の低下に繋がります。

この前提においては、 **「テストコードを書く」** という非機能要件も、そこに拘泥しすぎるとフォースになってしまうと考えられます。
プロジェクトの目的や、目指すものを並べてみて、その中で **「テストカバレッジを１００％にする」** はどのくらいの優先順位になるでしょうか？もし、もっとそれよりも優先するべきことがたくさんあるのであれば、「テストを必ず書く」ことに拘る必要はないかもしれませんし、大人数開発における品質担保や、長期開発における堅牢性を求めるのであれば、テストコードの優先度は高くなるでしょう。

また、テストコードに関しては、ALL or NOT で考える必要はありません。決済処理と行った絶対にミスが許されないところや、多くの画面で流用する共通部分など、コストパフォーマンスの高い部分に対して、まずは重点的にテストを書いてみる、というように、 **ここはテストを書いてここは（まだ）書かない**、 というような配分を決めることが、考え方としては現実的だと思っています。

# 考えたいこと１：テストコードだけがテストなのか

テスト手法といっても様々です。

- テストコードを用いたユニットテスト
- Seleniumやヘッドレスブラウザを使ったE2Eテスト
- サービスを知らない人に触ってもらう、ユーザーテスト
- テストシナリオを用いた手動テスト
- モンキーテスト

などなど、多岐にわたります。そしてこれらのテスト手法をすべて実施することが非現実的な事は明らかです。
その上で「テストコードを書く事」だけに対して、常にリソースを確保しなければならない、とする理由も、やはり無いと言わざるをえないでしょう。

- 新規画面の開発において、動く/動かない、といった要件でなく、使いやすい/使いにくい、見やすい/見にくい、という基準を判断する上では、人間が実際に動かしてみてのテストが必要不可欠です。
- 運用フェーズにおいて、継続的なリリース後に、「新規会員登録」や「購入画面」といった最重要画面が間違いなく動いていることをチェックするためには、デプロイにフックされたE2Eテストが力を発揮するでしょう。
- モンキーテストはバッドプラクティスとして扱われる事が多いですが、開発リソースが潤沢ではなく、営業やオペレーターなどの非技術者がプロジェクトメンバーにいる状況においては、エンジニアをできるだけ開発に注力させる為の実践的な手段だと言えるでしょう。

自戒も込めてになりますが、**エンジニアはやはり、設計・コーディングという自分の担当作業の中で、完璧なものを作ろうとする傾向** があるように思います、これは逆に言えば、 **非技術者やユーザーの手に渡ってからフィードバック期間を相対的に短くしがち** だということです。（これを見ている技術者の方で、外部ユーザーのユーザーテストを開発スケジュールに盛り込んだことのある人はどれくらいいるでしょうか？？少なくても私はできていません）

# 考えたいこと２：バグって絶対にあってはいけないもの？

もちろん、バグを忌み嫌うのはエンジニアの習性であり基本方針です。ただ、「ビジネス視点」や「ユーザー視点」という２つの観点が絡んでくると、やはり優先順位の問題と言えるかと思います。エッジケースをいくつか上げます。


## 2-1. ユーザー視点から見て

###   「１００人に1人が遭遇するエラー画面」と、「新規登録で5％が離脱する不親切なUI」のどちらを優先する？

アホみたいな例ですが、現場だと意外とあり得るトレードオフです。　特にToCの領域においては、SEOや広告から流入してきたユーザーをいかにサービス上のコンバージョンに繋げるか、というのは死活問題です。

もっと具体的に言えば、 **バグやUIの不備は、目標とするコンバージョンやKPIに対しての影響度において数値化し、相対化されるべき** です。今回の極端な例で言えば、後者のほうが圧倒的に、サービスの成長に対して与える影響度が大きいため、エラー画面よりも早く対応すべき事象、という判断を下すことになります。

## 2-2. ビジネス視点から見て
### リリース予定日だが、バグが残っている。いったんリリース？それとも１ヶ月遅らせる？

このパターンは、開発者であれば ~~ほぼ毎度~~ しばしば遭遇するのではないでしょうか。
結論から言うと、 **ビジネス視点から見れば、「リリース時期が遅れる」ことの影響度はかなり大きく、優先順位が高い事象である** と言えるでしょう。 大抵の場合においてはWebサービスはストック型ビジネスなので、１ヶ月の遅れは、長期的なサービスの成長計画においては後々の大きな影響を及ぼします。（古い時代の例えですが、就職浪人をして１年就職が遅れることによる機会損失の量は、初任給１年分ではなく、定年前の高い年収１年間分である、というのに似ています）。
さらに言えば、広告の効果測定であったり、ToB顧客の獲得など、「一定のユーザー数がいる」状況において打てる施策は大幅に広がります。そういった状況において、 **「多少粗があったとしても、まずは動くものを優先して作る」**という優先順位は、サービスの目標達成において大きな意味を持ちえます。


# まとめ
何度も繰り返しますが、 **テストコードは有用です。** エンジニアである以上「できるだけテストは書きたい」という向上心は捨ててはいけないと思いますし、特定の実装においてテストコードが必要になったときは、サッと書けるくらいの環境整備をしておくべきだと思っています。

一方で **今回のような前提条件においては、TDDやテストファースト、という開発スタイルはあまり有効でない、** と言わざるをえないと思います。もちろん、TDDというパラダイムが現代の開発において、多くの影響を与えていることは明らかです。しかし、これまで述べてきたように、多種多様な判断軸を持ち、開発途中での柔軟な方針変更を是とするアジャイル開発においては、 **「必ずテストを書く」という方針は、重すぎる制約でありフォースである** 、というのが私の結論です。

対して求められる考え方は、サービスに求められる品質管理と、それに対するテスト計画においても、そのプロジェクトにとっての **適切な優先順位をつけて、しっかりと考えて相対化、リソース配分すること** 、そして原理原則にとらわれず、 **実績として効率が悪いと感じたら柔軟に方向転換をするだけの勇気を持つこと** だと思います。

ただし、これはあくまで前提条件があっての話です。潤沢にリソースがあり、大規模な業務システムのように、モジュール単位での堅牢性や、属人性の排除に対する訴求が大きいプロジェクトにおいては、TDDあるいはテストファーストという手法は、有力な選択肢になるでしょう。

# 次回予告？
この記事ではNon-Coding領域での開発手法(アジャイル)をベースにしてテストコードの是非について書きましたが、例えば動的言語の特性や最近のWebの設計トレンドなどを踏まえると、また別の考えが出てくると思います。機会があったら書きたいと思っています。

また、テストコードの効用の中で、「他人から見たコードの可読性」「リファクタリングの容易さ」といった非機能要件的なメリットについても本稿の中ではあまり扱えてないので、そのあたりも・・・。