テストファーストプログラミングの欠点は何ですか?


47

最近は大流行です。「みんな」がそれをお勧めします。それ自体が疑わしいものです。

テストファースト(テスト駆動)開発を行うときに発見したいくつかの欠点は何ですか?私は知識のある開業医からの個人的な経験を探しています。私はインターネット上の他の場所にある百人の夢想家の仮説を読むことができます。

TDDが嫌いだからではなく、ソフトウェア開発プロセスを改善することが私の仕事であり、人々が遭遇する問題について学ぶことができれば、プロセスを改善できる可能性が高くなるからです。

回答:


41

かなりの数がありますが、不利な点をはるかに上回る利点があります。

急な学習曲線があります。

多くの開発者は、最初からテストファーストプログラミングで効率的に作業できることを期待しているようです。残念ながら、経験を積み、以前と同じ速度でプログラミングするには多くの時間がかかります。それを回避することはできません。

具体的に言うと、間違えるのは非常に簡単です。あなたは非常に簡単に(非常に善意で)維持するのが難しいか間違ったものをテストするテストの全体を書くことになります。ここで例を挙げるのは困難です。この種の問題は、経験を積んで解決するだけです。懸念事項を分離し、テストしやすいように設計するための十分な感覚が必要です。ここでの私の最善のアドバイスは、TDDをよく知っている人とペアプログラミングを行うことです。

事前にさらにコーディングを行います。

テストファーストは、テストをスキップできないことを意味し(これは良いことです)、前もってより多くのコードを書くことになります。これはより多くの時間を意味します。繰り返しますが、あなたはそれを回避することはできません。保守や拡張が容易で、一般的にバグが少ないコードで報われるが、それには時間がかかる。

経営者にとって厳しい販売になる可能性があります。

一般に、ソフトウェアマネージャーはタイムラインのみに関心があります。テストファーストプログラミングに切り替えて、1つの機能ではなく機能を完了するのに突然2週間かかる場合、彼らはそれを好まないでしょう。これは間違いなく戦う価値のある戦いであり、多くのマネージャーはそれを手に入れるのに十分な知識を持っていますが、厳しい売り手になる可能性があります。

仲間の開発者にとって厳しい販売になる可能性があります。

急な学習曲線があるため、すべての開発者がテスト優先プログラミングを好むわけではありません。実際、ほとんどの開発者は最初は気に入らないと思います。ペアプログラミングのようなことをして、彼らがスピードを上げるのを助けることができますが、それは難しい販売になる可能性があります。

最後に、利点は欠点よりも重要ですが、欠点を無視するだけでは役に立ちません。あなたが最初から何を扱っているかを知ることは、すべてではないにしても、いくつかの欠点について交渉するのに役立ちます。


これらは良い答えですが、#1についてより具体的にすることができますか?プログラミングの速度をどのように/どのように回復できたかを聞くことに特に興味があります.TDDを始めたときに知らなかったことを何を学びましたか?
アレックスファインマン

明確にするために更新
Jaco Pretorius

7
現在テストを行っている場合、開発に費やされる合計時間は大幅に変わらないはずです。単体テストの作成と保守にかかる時間を公開しているため、時間がかかっているように見えます。
ChrisF

1
@JeffOは「ミニバンを書くつもりです!」に精通しています。コーディングスクール?
アレックスファインマン

1
@tvanfosson-彼らは一度に2つのことを変えようとしているので-テストの開始とTDDの両方-これは問題があるかもしれません。また、時間の見積もりに加えられます-非常に正確に-マネージャーと顧客は前もっての増加のみを見るので、全体の時間が実際に(一度だけ)わかっていて、さらに少ないかもしれません。彼らがいくつかのテストを行っている場合、この増加は少なくなります。
ChrisF

35

テストファーストでは、次のコードを記述していることを前提としています。

  • 単体テストでテスト可能
  • 開発しているものには明らかなアプローチがあり、大規模なプロトタイピングや実験を必要としないこと
  • リファクタリングする必要があまりないこと、または数百または数千のテストケースを繰り返し書き直す時間があること
  • 何も封印されていません
  • すべてがモジュール式です
  • すべてが注射可能またはm笑可能
  • 組織がリソースシンクを正当化するために低欠陥に十分高い価値を置いていること
  • 単体テストレベルでテストすることには有益なものがあること

プロジェクトがこれらの要件を満たしていない場合、問題が発生します。TDDのプロモーターは、これらのラインに収まるように製品を再設計することを提案するために、これに対する良い答えを持ちません。それが不可能または望ましくない状況があります。

実際には、テストファーストテストが実際にプログラムの正しい機能について何かを証明していると考える人々に大きな問題があります。多くの場合、これは真実ではありませんが、真実である場合でも、完全性の完全な姿からはほど遠いです。人々は何百ものテストに合格しており、TDD以前は数百のテストケースしか実行していなかったため、テストの安全性は低いと考えています。私の経験では、TDDは、開発者にも偽のセキュリティがあり、すべてのテストを変更して大きなリダクターを作成する苦痛が開発者を面白い回避策に導く可能性があるため、さらに多くの統合テストが必要であることを意味します。

例:

私の個人的な最良の例は、asp.netのセキュリティコードを書くときです。マシン構成から敵対的な環境で実行することを意図している場合、それらはgac'ed、署名、およびシールされ、IISのgodオブジェクトに対して実行されるため、非常に正確にモックすることは非常に困難です。パフォーマンスとメモリ使用の制約を追加すると、残りの領域でプレースホルダーオブジェクトを使用する柔軟性がすぐに失われます。

抽象化が最適化されず、リソース制限が低いため、あらゆる種類のマイクロコントローラーまたは他の低リソース環境コードでは、実際にオブジェクト指向スタイルの設計を行うことができない場合があります。同じことは、多くの場合、高性能ルーチンでも言えます。


反例がありますか?ユニットテスト方式でテスト可能なものを書くのはいつですか?なぜモック可能またはインジェクション可能なコードを作成しないのですか(それ自体がトピックであるレガシーコードを除く)。
アレックスファインマン

例のセクションを追加するために編集
Bill

4
同意した。TDDの動作は、使用しているマシンに関する一連の仮定に依存しているようです。私のプロジェクトの約50%には当てはまらないようです。
ポールネイサン

私は完全に同意します...素晴らしい答え
Khelben

2
これはこのゲームのあらゆるもののようです-多くの状況に適切で、他の状況には不適切です。ソフトウェア開発のあらゆる分野でOne True Pathを提唱する人に注意してください。
アランB 14年

25

私が見た最大の欠点は、TDD自体ではなく、開業医にあります。彼らはすべてをテストしなければならない独断的で熱狂的なアプローチを取ります。時々(つまり何度も)、それは必要ありません。また、実用的でない場合があります(つまり、組織をTDDに導入する)。

優れたエンジニアはトレードオフを見つけ、テストファーストをいつ/どこで/どのように適用するかの適切なバランスを適用します。また、実際のコードの代わりに(2〜3倍以上)テストの開発により多くの時間を費やし続けている場合、問題が発生しています。

言い換えれば、TDD(またはその点についてはソフトウェア開発のあらゆるもの)を使用して、実用的かつ合理的になります。


それは、おそらく、マイケルフェザーズのレガシーコードの「新しい」定義(つまり、「テストのないコード」)の由来なのでしょうか。
フィルW. 14年

その定義は私には役に立たないでしょう:)私にとって、本番環境で実行され、変更の対象となるコードは、コードやテストの品質に関係なく、レガシーコードです。通常、「レガシーコード」と「不良コード」または「廃止されたコード」を関連付けます。実際には、本番環境で使用されていない開発中のコードに不良コードと廃止コードがすでに存在する場合です。私たちの目的は、コードが最初からレガシーであり、今後数十年にわたって使用され続けるような品質と有用性を持つことです。
luis.espinal

6

2009年8月上旬にTDDを始め、2009年9月/ 10月に会社全体にTDDに切り替えるように説得しました。現在、開発チーム全体が完全に変換されており、テストされていないコードをレポにコミットすることは悪いことと見なされ、スローされます。それは私たちにとって素晴らしい仕事であり、カウボーイコーディングに戻ることは想像できません。

ただし、かなり顕著な2つの問題があります。

テストスイートを維持する必要があります

TDDに真剣に取り組むと、多くのテストを書くことになります。さらに、テストの適切な粒度が何であるかを理解するには、ある程度の時間と経験が必要です(やり過ぎは、やりすぎと同じくらい悪いです)。これらのテストもコードであり、bitrotの影響を受けやすくなっています。これは、それらを他のすべてのものとして維持する必要があることを意味します:依存するライブラリをアップグレードするときに更新し、時々リファクタリングします...コードに大きな変更を加えると、多くのテストが突然古くなったり、明白な間違いさえ。運がよければ、それらを単純に削除することもできますが、多くの場合、有用なビットを抽出して新しいアーキテクチャに適応させることになります。

抽象化のテストは時々漏れる

Djangoを使用しています。Djangoには、非常に優れたテストフレームワークがあります。ただし、現実と少し対立する仮定を立てることもあります。たとえば、一部のミドルウェアはテストに違反する場合があります。または、一部のテストでは、キャッシングバックエンドについて想定します。また、「実際の」データベース(SQLite3ではない)を使用している場合、テスト用のデータベースの準備には多くの時間がかかります。もちろん、ローカルで行うテストにはSQLite3とメモリ内dbを使用できます(使用する必要があります)が、使用するデータベースに応じてコードの動作が異なる場合があります。現実的なセットアップで実行される継続的統合サーバーのセットアップは必須です。

(一部の人々は、データベースなどのすべてのものをモックする必要があると言うでしょう、またはテストは「純粋」ではありませんが、それはイデオロギーを話すだけです。モッキングコードでエラーを犯した場合あなたのテストスイートは価値がないでしょう。)

これはすべて、私が説明した問題は、TDDが非常に高度な場合にのみ顕著になり始めるということです...


3
+1。「維持する必要があります」:再利用可能なコードをテストする場合、インターフェイスと動作は通常安定している必要があるため、これは問題ではありません。このため、通常は再利用可能なライブラリに対してのみTDDを実行します。
ディミトリC.

4

私にとって、TDDのようにテストを広範囲に適用しようとすると、テストに深い心理的な問題があります。テストが問題をキャッチすると信じているため、コードが存在する場合、だらしなくコーディングします。しかし、セーフティネットを提供するテストがない場合は、慎重にコーディングします。結果は常にテストよりも優れています。

たぶんそれは私だけです。しかし、私はどこかであらゆる種類の安全ベルとホイッスルを備えた車がよりクラッシュする傾向があることも読んだことがあります(ドライバーは安全機能があることを知っているため)。TDDは一部の個人と互換性がない場合があります。


テスト可能なコードを書くと、通常は遅くなり、自分がコーディングしているものについてもっと考えるようになるので、それは私には奇妙に思えます。実際、最近はテストなしで少し神経質なコーディングをしています。
マットH

1
異なる人々が実際に異なる反応をすることを示しています。私はTDDをバッシングしているわけではありません-明らかに、かなりの数の人がTDDを便利だと思っていますが、実際のところ、それはすべての人のためではありません。
ジョナスプラッカ

2
100%に同意します。自動化されたテストなしでコードをより良くより速く記述します。もちろん、テストしないのはばかげているでしょう。自動化は悪い選択だと思います(少なくとも私にとっては)。手動テストは、テストスイートを維持するよりも速く安全であることがわかりますが、経験豊富な開発者でもあるため、テストの対象と場所と理由を非常によく理解しているため、コードの追加とリファクタリングは回帰なし。
ベン・リー

1
私が作業しているチームとプロジェクトはどちらもアーキテクチャ全体を十分に理解できるほど小さいことを指摘する必要があります-大規模なチームまたは非常に大規模なプロジェクトでは、自動テストがより有用であると考えられます。そうすれば、退行を防ぐためにテストすべき場所を嗅ぐことができる開発者は一人もいません。
ベン・リー

リファクタリング手順を省略していますか?
rjnilsson 14年

2

テストファーストが本当に邪魔になる状況の1つは、適切な実装を作成する前に、いくつかのアイデアをすばやく試して、それが機能するかどうかを確認したい場合です。

私のアプローチは通常:

  1. 実行するものを実装します(概念実証)。
  2. 動作する場合は、テストの追加、設計の改善、リファクタリングにより統合します。

ステップ2に到達しない場合があります。

この場合、TDDの使用には、私にとっての利点よりも多くの欠点があることがわかりました。

  • 概念実証の実装中にテストを書くと、作業が遅くなり、思考の流れが中断されます。アイデアを理解したいのですが、最初の大まかな実装の詳細をテストする時間を無駄にしたくありません。
  • 私のアイデアが価値があるかどうかを調べるのに時間がかかる場合があります。
  • アイデアが役に立たないことが判明した場合、コードとうまく書かれたユニットテストの両方を捨てなければなりません。

そのため、新しいアイデアを模索する必要があるときは、TDDを使用せず、新しいコードがどこかで取得されていると感じたときにのみユニットテストを導入します。


1
プロトタイプコードと使用可能なコードを混同しているようです。プロトタイプコードはテストコードです。テストする必要はなく、それに対して実行するテストを作成しないでください。不足しているステップは1.〜2.です。「テストを記述して統合する」と言います。問題は、統合するものではなく、書くものがあることです。プランプロトタイプのコードを書き換えるには、それを再利用する予定はありません。それを再利用すると、妥協の余地が多く残ります。書き換えは、探索段階と「品質コード」段階の分割を形式化します。
utnapistim 14年

3
@utnapistim:プロトタイプコードを使用可能なコードと混同することはありません。むしろ、TDD熱狂者はそれらを混同し、プロトタイプコードにもTDDを使用することを提案します。むしろ、彼らはプロトタイプコードがまったくないことを前提としています。また、プロトタイプから実際の実装に移行するときに、多くの場合書き直す必要があることに同意します。プロトタイプコードの一部を再利用できる場合もありますが、書き直す準備が必要です。あなたは本当にケースからケースを決定する必要があります。
ジョルジオ14年

3
@utnapistim:luis.espinalの回答も参照してください:「私が見た最大の欠点は、TDD自体ではなく、実践者です。すべてをテストする必要がある独断的で熱心なアプローチを取っています。」
ジョルジオ14年

1

TDDの欠点またはコスト

注:TDDにはさまざまな種類があります。ユニット、BDD、ATDD、またはその他のバリアントに関係なく、多くの困難が残っています

副作用

モックであろうと、フィクスチャであろうと機能テストであろうと、外部の状態やシステムへの依存性は、テストの最も複雑さ、テスト方法の混乱、そして間違いを犯す最大のリスクの原因になります。私が見たいくつかの問題:

  • モッキング:呼び出しの順序をアサートすることを忘れる
  • モック:モックは実際の呼び出しまたは応答と一致しません
  • フィクスチャ:テストは非現実的なデータに依存し、他の問題を隠します
  • フィクスチャ:本番環境で不可能な状態をテストする
  • 機能:依存システムが一時的に利用できないため、誤ったビルドが壊れる
  • 機能:テストの速度が非常に遅い

コーディングに対するアプローチを変更する必要がありますが、一部では劇的な変更になります。

コーディングの仕方は人によって大きく異なります。TDDでは、特定の動作をアサートするテストから開始して、テストがパスするように実装する必要があります。私は見たことがあり、そのプログラミングがTDDを助長しないプログラマーでした。開発アプローチの変更に最初に慣れ始めたとき、約2か月かかりました。

テストに関心があるものとテストに関心がないものを理解するには時間がかかります。

すべてのチームは、テストのどこに線を引きたいかについて明確に決定する必要があります。彼らがテストしたいものと評価していないもの。多くの場合、良いテストの書き方と、実際にテストに関心があることを学ぶのは苦痛なプロセスです。その間、スタイルとアプローチの両方に一貫性があるまで、コードは流動的な状態のままです。

単体テスト固有:大規模なリファクタリング

数万の単体テストを含む重要なコードベースの大規模または基本的なリファクタリングでは、すべてのテストを更新するために膨大なコストが発生します。これは、リファクタリングを行うことに関連するコストが理由で単純に行うことが正しい場合でも、リファクタリングの実行に対するプッシュバックで現れることがよくあります。


0

私の例えは、Scalextricトラックの障壁です。それらを装着すると、はるかに慎重になります。

人々はまた、彼らのテストについて少々のスペースを学んでいます-彼らはうまく動作するので、彼らはコードが完全にテストされていると信じていますが、それはテストプロセスの始まりに過ぎません。

私の考えでは、TDDはBDDへの足がかりです。実行される多数のテストは、テストが何を行うかを知らずに開発者をサポートするのに実際には役立ちません。BDDを使用すると、テストの出力は英語で行われ、テストが文書化され、システムの理解が深まります。


-1

TDDの利点は、コードを理解していない人々からコードを守ることを余儀なくされることです。はい、これには多くの場合あなた自身が含まれます。しかし、コードに保護する価値がない場合はどうなりますか?そもそもそこにあるべきではないコードがたくさんあります!そのため、TDDの問題は、不適切なコードを記述する開発者の場合です。TDDはおそらく彼らが良いコードを書くのを助けません。恐ろしいテストも同様に書くでしょう。したがって、彼らの場合、TDDは混乱を増すだけです。ひどく書かれたテストや冗長なテストは、他の形式の悪いコードよりも楽しいものではありません。


1
あなた自身が自分のコードを理解していない場合、何十億もの可能なテストケースの中のほんの一握りが、コードが間違っているのを防ぐことができるでしょうか?
マイケルショー14年

2
あなたはそれを書いたときにそれを理解したが、途中でそれを忘れたので?
ヨハン14年

+1 TDDは、ビジネス要件を誤解している開発者を保護しません。BDDの出番これは...ある
ロビーディー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.