test
テスト
初心者
開発プロセス
新人プログラマ応援

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

背景

スピード感重視なのでテストは書かない。テストはなぜ開発を遅くするか
の記事を拝読して、思うところがあったので、まとめてみる。

考察したい分類/内容

上述の記事の、以下の「まとめ」にはものすごく賛同できる。

「テストを書く」の齟齬を解消しよう。
「テストを書く」の意味は私とあなたで全く異なる。

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

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

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

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

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

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

  • 超少人数の新規構築タイプ

    • リアルタイムで仕様が変わる
    • 何らかのプロジェクト管理プロセスが不要なレベル
    • 1~3人程度の少人数
  • 中規模開発/アジャイル

    • ほぼ全員コードが書ける/読める
    • ピザ2枚が分け合える人数
  • 大規模開発/ウォーターフォール

    • 複数のレイヤーで役割分担
    • 人数も多くスキルもバラバラ


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

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

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

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

既存コード有無(新規orメンテ)の違い

  • 新規構築時

    • テストを書く前提であれば、
      後から書く意味はあまりないため、
      テストファーストで構築していく、ことを想定する。
    • この場合、テストを書くコストは低くなる
  • メンテナンス時(既にテストの無い実装がある)

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

テスト対象/確認観点の違い(最重要)

  • BL(ビジネスロジック)やDB操作の単体テスト

    • テストコードは作成しやすい。
    • 適切に機能分割されているという前提ならば、
      テストコードを書くべき、と最も主張出来る箇所。
  • UIや、PL(プレゼンテーション・ロジック)の単体テスト

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

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

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


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

その他:影響しそうな要素

  • 各担当者の「テストコード学習のコスト」

    • 参加メンバーにどの程度のテスト知識があるか?
    • Java,Python,Ruby,JavaScript.Swiftなどなど、
      複数の言語を使っていると学習コストは上昇
    • プロジェクトごとに使う言語が違うと学習コストは上昇
    • SI案件では、自社サービスに比べ学習は実施しにくい、など。
  • プロダクトで使用している技術の性質

    • (開発チームにとって)新技術を使った開発か?
    • AIや分析案件、または性能が重要であるなど、
      モノヅクリとしての性質がテストコードに向いているか?
  • プロダクトに求められている「品質」の意味

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

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


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

結論

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

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

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

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

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

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

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

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

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

おことわり

こういうポエム的な投稿をするのは全く本意ではない。
書いたそばから消したいくらい。
面白さに欠けている気がするし、
ストローマン論法のマトにしかならない。

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

こんなツマラナイ記事を読む時間があるならば、
こっちの記事でしりとりの考察を
読んでいただいたほうが多分面白いし、楽しい。

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

まとめ

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