テストはなぜ開発を遅くするか、テストを書かない理由はある！ない？


# 背景

[スピード感重視なのでテストは書かない。テストはなぜ開発を遅くするか](https://qiita.com/aimof/items/d68bdb347283ee2dbccf)
の記事を拝読して、思うところがあったので、まとめてみる。

# 考察したい分類/内容

上述の記事の、以下の「まとめ」にはものすごく賛同できる。
> 「テストを書く」の齟齬を解消しよう。
> 「テストを書く」の意味は私とあなたで全く異なる。

齟齬が生じる一番大きな理由は、
各位の「前提事項」が全く異なるからだと考える。

一方で、途中の記事内容については、
前提となるプロジェクトの状態の考慮が少なすぎて、
人によっていろいろな解釈が生じてしまい、
賛同する人、しない人に分かれそうな印象であった。

「テストを書く理由」を主張する優れた人はいっぱいいる。
が、~~宗教的な信仰で神が居る前提で話が始まるように、~~
主張時に、**「テストを書く」の意味は私とあなたで全く異なる**
というどの点が異なるのかを相互に理解不足であるために、
「テストを書きたがらない人」と平行線のように交わらない。

本投稿では、どの点が異なると、
「テストを書く」ことへの意識が変わるのか、
プロジェクト/プロダクト/テストの性質を分類考察する。

例えば、テストを書かない人は、
こういう属性のプロジェクトの話をしているのかもしれない、
など想像をすることで、
**テストを書く人へも、書かない人へも、**
**双方の主張のミゾを多少埋められるかもしれない。**



# プロジェクトの性質による違い

* **超少人数の新規構築タイプ**
  * リアルタイムで仕様が変わる
  * 何らかのプロジェクト管理プロセスが不要なレベル
  * １～３人程度の少人数

* **中規模開発/アジャイル**
  * ほぼ全員コードが書ける/読める
  * ピザ２枚が分け合える人数

* **大規模開発/ウォーターフォール**
  * 複数のレイヤーで役割分担
  * 人数も多くスキルもバラバラ

⇒
大規模でもマイクロサービス化してアジャイルできるよね、
とか、分類していくとキリがないため、ざっくり３分類まで。

多くの人が最初に議論に挙げそうな観点はこの分類である。
しかし、「テストを書く」の意義を考える上では、
**実はちょっと扱いにくい分類**。

後述の分類に影響を与える場合が多いため、
この分類が「間接的に効いている」ため、
「テストを書く」議論がカオス化するのだと思う。

以降で、「テストを書く」の意義に
直接的に影響を与えている特性を検討してみよう。


# 既存コード有無（新規orメンテ）の違い

* **新規構築時**
  * テストを書く前提であれば、<br />
    後から書く意味はあまりないため、<br />
    テストファーストで構築していく、ことを想定する。<br />
  * この場合、テストを書くコストは低くなる<br />


* **メンテナンス時**（既にテストの無い実装がある）
  * テストファーストは実施出来ないため、<br />
    障害対応やメンテナンス時に、<br />
    少しずつテストコードを追加する、ことを想定する。
  * この場合、実質的にはリファクタリングを伴い、<br />
    最悪全リプレイスになってしまうため、<br />
    テストを書くコストは高くなる。<br />
    いやいや長い目で見ればそのコストは回収できる、<br />
    などの議論を呼ぶこともある。


# テスト対象/確認観点の違い（最重要）

* **BL(ビジネスロジック)やDB操作の単体テスト**
  * テストコードは作成しやすい。
  * 適切に機能分割されているという前提ならば、<br />
    テストコードを書くべき、と最も主張出来る箇所。


* **UIや、PL(プレゼンテーション・ロジック)の単体テスト**
  * テストコードを作成しても、<br />
    人間の目で見ないとあまり効果がない場合が多い。
  * 表示用のオブジェクト(HTMLのdom等)に想定通りの文字列が入っているか、<br />
    といった機械視点の確認まではテストコードで可能だが、<br />
    その表示上の位置、改行箇所が自然か？<br />
    的な確認は結局人がやることになり、議論が分かれるところ。


* **結合/連結テスト**
  * プロダクトの内容によって特性は大きく異なる。<br />
    最も議論が分かれるところ。<br />
  * UIの単体テストについても言えることだが、<br />
    例えば、「Selenium」などのブラウザ操作自動化ツールでの<br />
    「テストコード」について、議論に含めているのか除外しているのか、<br />
    人によって感覚が違うかもしれない。<br />
  * 「モック」や他の前提条件のエミュレートが、<br />
    どこまで容易/有効であるか、にも依存する。
  * 機種/バージョン/環境依存の確認をここで実施したい場合、<br />
    「テストコード」だけでなく「テストコード実行環境構築」<br />
    が重要になってくる点に注意。


* **総合/システム/運用テスト**
  * 実データの豊富なバリエーションや、<br />
    特殊な操作時の例外挙動、性能確認、<br />
    複数の機種/ブラウザバージョン/複数環境での確認、<br />
    UIのレスポンス/操作感の確認など目的は多岐にわたる。<br />
    外部システムをモック化してしまっては意味が薄いため、<br />
    そもそもテストコードを書くこと自体が難しく、<br />
    テストコードだけでOKとは出来ない。<br />
    ここは、テストコードを書く書かないの、議論の対象外と考える。<br />

⇒
必ずしも「工程」の話をしているわけではない。
そのテストは「**何のためにやるの？**」という話。
例えば、作っているプロダクトの性質として、
「BL」部分が最も複雑で、その品質を確保することが重要であれば、
テストを書くことの、コスト対効果が高くなる。
一方で、「BL」はたいした処理が無くて、結合/連結以降の
品質確保が最も困難であるプロジェクトの場合は、
テストを書くことの、コスト対効果が低い、ということになる。


# その他：影響しそうな要素

* **各担当者の「テストコード学習のコスト」**
  * 参加メンバーにどの程度のテスト知識があるか？
  * Java,Python,Ruby,JavaScript.Swiftなどなど、<br />
    複数の言語を使っていると学習コストは上昇
  * プロジェクトごとに使う言語が違うと学習コストは上昇
  * SI案件では、自社サービスに比べ学習は実施しにくい、など。


* **プロダクトで使用している技術の性質**
 * （開発チームにとって）新技術を使った開発か？
 * AIや分析案件、または性能が重要であるなど、<br />
    モノヅクリとしての性質がテストコードに向いているか？


* **プロダクトに求められている「品質」の意味**
  * 主要な処理が動けばOK？
  * 超レアケースも含めて一切のバグは許されない？
  * どのくらいの寿命やメンテナンス頻度を想定？
  * 例えば、あるゲームのチュートリアルを作る場合、<br />
    想定通りに動くことより、分かりやすくユーザが飽きないこと、<br />
    のほうが重要で、極端な話、実際のゲームと少し違う挙動でも良いし、<br />
    ゲーム本体が変わっても、必ずしもメンテする必要はない。


* **プロジェクトや企業の文化**
  * リファクタリングをどの程度許容するか？
  * （最近は居ないと信じたいが）コードのステップ数で<br />
    生産性を見ているなどの習慣があるか？
  * 何の観点で工数見積を実施するか？
  * カバレッジの評価に対する考え方
  * テストケース表やレポートが納品物扱いになっているかどうか？

⇒
これらは、テストを書く書かないという以外にも、
「テストすること自体」や「テストを学習すること」
に対して、価値観が異なる可能性がある。

# 結論

誤解を恐れずにステレオタイプな印象だけで言えば、
「テストを書く人」のほうが技術レベルが高い場合が多い。
また、テストファーストのプロジェクトの方がバグが少ない。

そのため、「テストを書かない人」（及びそのプロジェクト）を
「遅れている」扱いしがちであり、
**テストコード崇拝者**や**TDDの尖兵**は数多く居る。
（なんでも絶対書くべきだ、的な人）

彼らの主張が間違っているわけではない。
ただし、上記で挙げた分類や考察のように、
**テストを書くことで得られる費用対効果は、**
**プロダクトの特性、テスト対象によって、大きく異なる。**

一方、「テストを書くと遅くなる」と主張する人は、
テストコードの費用対効果が高い箇所に目をつぶり、
テストコードの費用対効果が低い箇所ばかり見ている可能性がある。
また、そもそもテストを書いたことがない、
書き方を知らないなど、知識不足もあるかもしれない。

**書く書かない、０か１か、みたいな二元論はやめて、**
自分のプロジェクトの特性をよく見極め、
最も効果の高いところにはテストを導入し、
効果の低いところまで無理強いはしない、
ようにすれば、もう少し**幸せな世界**があるのではないか？

テストを書くことで得られる効果を実感しやすく、
また、部分的ならば導入/学習コストも低くおさえられる。

なぜこのプロジェクトでは
テストコードを書くべき or 書かないべき、なのか、
盲目的に「書く」「書かない」と主張するのではなく、
**得られる効果と、書くためのコストを、**
**テストしたい要素ごとに考慮し、**
**個別特性に応じて考えていくべき**である。
良いと思った側に「改善」していくことが望ましい。

レガシープロジェクトに対しても、
例えば「共通ライブラリ」のコードに対しては、
テストコードを導入してみよう、などの進め方。

そうした考慮の時の考え方の一つとして、
今回挙げた分類/考察が何かの参考になれば幸いである。
**テストは目的ではなく手段。本来の優先度を考えて適した手段を採用したい**。

# おことわり

こういうポエム的な投稿をするのは全く本意ではない。
~~書いたそばから消したいくらい。~~
面白さに欠けている気がするし、
[ストローマン論法](
https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%88%E3%83%AD%E3%83%BC%E3%83%9E%E3%83%B3)のマトにしかならない。

> ex.「俺、雨の日って嫌いなんだよね」
> ⇒「お前は干ばつで穀物が育たなくてもいいって言うのか？」
> 日本人は普段は曖昧なクセに、議論は極端に攻撃的。

~~こんなツマラナイ記事を読む時間があるならば、
[こっちの記事](https://qiita.com/youwht/items/7a4a280e4c49107260ed)でしりとりの考察を
読んでいただいたほうが多分面白いし、楽しい。~~

あくまでもいち個人としての見解を延べただけであり、
０か１かでは無いと言っているように、
「ここに延べた内容が100%正しい異論は認めない」
などと主張する気は全く無い。
全部にテストを書きたい人は書けば良いし、
書きたくない人はずっと書かないでいいと思う。

# まとめ

**「テストを書く」の「費用対効果」は**
**プロダクトの特性、テスト対象によって、大きく異なる。**
**０か１かの二元論はやめて、テストしたい要素ごとに個別に考え、**
**お互いの考え方を尊重しましょう。**

---