私はTDDについて複雑な気持ちを持っています。私はテストを信じていますが、テストが私の開発努力を促進するという考えには問題があります。
現在の要件を満たすインターフェイス用に記述されたいくつかのテストを満たすようにコーディングする場合、保守可能なコードの構築、クリーンな設計、および健全なアーキテクチャから焦点を移す可能性があります。
テストではなく、駆動に問題があります。何かご意見は?
私はTDDについて複雑な気持ちを持っています。私はテストを信じていますが、テストが私の開発努力を促進するという考えには問題があります。
現在の要件を満たすインターフェイス用に記述されたいくつかのテストを満たすようにコーディングする場合、保守可能なコードの構築、クリーンな設計、および健全なアーキテクチャから焦点を移す可能性があります。
テストではなく、駆動に問題があります。何かご意見は?
いいえ。
正しく行われた場合、テスト駆動開発は設計ツールです。
私自身のブログエントリにリンクしてくださったことをお許しください。ここでは、開発者がテストを単なるテストとして扱ったという理由だけで失敗したテスト駆動開発の落とし穴について説明しています。
以前のプロジェクトでは、開発者はプロジェクト全体に依存関係を強制する非常に有害なシングルトンパターンを使用していましたが、要件が変更されたときにすべてが壊れました。
TDDは、アプローチとして扱われるべきだったのに、タスクとして扱われました。[...]
TDDがテストではなく、設計に関するものであることを認識できませんでした。単体テストでのシングルトンの乱用が横行していることから、これが明らかになりました。テスト作成者が「WTFはこれらのシングルトン=値です。私のテストでステートメントを実行していますか?」、テストライターはシングルトンをテストに伝播しました。330回。
残念な結果として、ビルドサーバーで実施されたテストは、それが何であれ、合格するようになりました。
テスト駆動開発を正しく行うことで、開発者は、密結合、DRYの違反(繰り返さないでください)、SRP(単一責任原則)の違反などの設計上の落とし穴を十分に認識できるようになります。
テストに合格するためにテストに合格コードを書く場合、すでに失敗しています。テストを書くのは難しいことを、あなたに尋ねさせる道標として扱う必要があります。なぜこれがこのように行われるのですか?他のコードに依存せずにこのコードをテストできないのはなぜですか?このコードを再利用できないのはなぜですか?このコードを単独で使用すると壊れてしまうのはなぜですか?
さらに、設計が本当にクリーンで、コードが本当に保守可能である場合、テストを作成するのは簡単ではないのはなぜですか?
TDD 設計または先行設計のいずれかをやりすぎるリスクは常にあります。したがって、答えは依存するということです。私のテストが作成に役立つ要件のベースとなるユーザー ストーリー/受け入れテストから始めることを好みます。それを確立して初めて、TDD スタイルの詳細な単体テストを書き始めます。唯一の設計と思考が TDD を介して行われる場合、ボトムアップ アプローチのリスクが大きすぎます。これにより、単体では優れたユニットとクラスが得られる可能性がありますが、それらをタスクを満たすユーザー ストーリーに統合しようとすると、すべてが間違っていたことに驚くかもしれません。これに関するさらなるインスピレーションについては、 att BDDを参照してください。
これに関する大きな「議論」が Robert C. Martin と James Coplien の間で記録されており、前者は TDD の支持者であり、後者はシステムの設計を台無しにすると述べています。これは、Robert が TDD と設計について語ったことです。
「'99 年頃から、アジャイル コミュニティには、アーキテクチャは無関係だという感覚がありました。アーキテクチャを行う必要はありません。必要なのは、多くのテストを作成し、多くのストーリーを作成し、迅速な反復を行うことだけです。コードは魔法のように自動的に組み立てられますが、これは常にばかげたことでした. アジャイルの最初の支持者のほとんどは、それがばかげたことであることに同意すると思います."
James Coplien は、TDD から設計を実行するだけでは大きなリスクがあると述べています。
「多くのプロジェクトでよく目にすることの 1 つは、プロジェクトが 3 回目のスプリントで南下し、それ以上進むことができずにクラッシュして燃え尽きてしまうことです。それは、構造的に追い詰められているためです。リファクタリングはクラス カテゴリ全体、クラス階層全体で行う必要があり、同じ機能を持つという保証はもはや得られないため、この問題を解決するにはリファクタリングしてください。」
また、彼は銀行口座がどのように見えるかを示す素晴らしい例を挙げています:
「ケントと一度話したときのことを覚えています。彼が TDD を提案していた初期の頃です。これは YAGNI の意味であり、おそらく機能する可能性のある最も単純なことを行っていました。彼は次のように言いました。銀行口座、普通預金口座。普通預金口座とは何ですか? これは数値であり、その数値に足したり、その数値から引いたりすることができます. では、普通預金口座とは電卓です. 電卓を作ってみましょう.それがうまくいく可能性がある最も単純なことであり、他のすべてはそれの進化です。
実際の銀行システムを実行する場合、普通預金口座はオブジェクトでさえなく、そこから適切なアーキテクチャへの道をリファクタリングするつもりはありません。普通預金口座とは、データベース トランザクション、預金、利子の収集、その他のお金の移動の監査証跡を反復処理するプロセスです。普通預金口座がどこかの銀行の棚に置かれているお金のようなものではありません。それはユーザーの視点ですが、銀行システムの基盤には、サポートするためにこれらの比較的複雑な構造があることを知っておく必要があります。税務担当者、アクチュアリー、その他すべての人々に、段階的にアプローチすることはできません。もちろん、銀行業界は40年後にこれに到達したためです。あなたは自分自身に40年を与えたいですか?アジャイルではありません。」
ここで興味深いのは、TDD の支持者と反対者の両方が、事前に設計する必要があると言っているということです。
時間があれば、ビデオを見てください。非常に影響力のある 2 人の専門家による素晴らしいディスカッションで、わずか 22 分です。
私はpjzに完全に同意します。ソフトウェアを設計する正しい方法はありません。次の単体テスト以外に何も考えずにTDDを極端にすると、自分自身で物事が難しくなる可能性があります。ダイアグラムとドキュメントに数か月を費やして壮大なソフトウェアプロジェクトに着手したが、コードはなかった人のための同上。
適度。コードの構造を視覚化するのに役立つ簡単な図を作成したいという衝動を感じたら、それを試してみてください。2ページが必要な場合は、コードの記述を開始する時期かもしれません。そして、あなたがあなたのテストを書く前にそれをしたいのなら、それで何。目標は、特定のソフトウェア開発の原則に完全に準拠することではなく、機能する高品質のソフトウェアです。あなたとあなたのチームのために働くことをしてください。改善できる領域を見つけます。繰り返します。
私はその件に関してあなたに完全に同意します。実際には、TDDはコードベースに非常に悪い影響を与えることが多いと思います(くだらない設計、手続き型コード、カプセル化なし、テストコードが散らばっているプロダクションコード、どこにでもあるインターフェイス、すべてが多くのテストに緊密に結合されているため、プロダクションコードをリファクタリングするのは難しいなど)。 )。
ジム・コリアンは、このトピックについてしばらくの間、まさにこのトピックについて話し合っています。
TDDの最近の研究(SiniaaltoとAbrahamsson)は、従来のテスト最後の開発に勝る利点がない可能性があり、場合によってはコードが劣化し、他の驚くべき(彼らの言葉)効果があることを示しています。私が最も心配しているのは、それがアーキテクチャを劣化させることです。-ジムのブログ
また、ロバートC.マーチンとジェームズコプリエンの間でInfoQについての議論があり、そこで彼らはこの主題に触れています。
私の考え方は、最初にコードをどのように見せたいかを書くことです。ターゲットコードのサンプルを入手したら(現時点では何もしません)、テストスキャフォールドをその上に配置できるかどうかを確認します。それができない場合は、なぜできないのかを理解してください。ほとんどの場合、設計上の決定が不十分(99%)であることが原因ですが、そうでない場合(1%)は、次のことを試してください。
ターゲットコードとテストスキャフォールディングを取得した後。コードを実装します。今、あなたはあなたがあなた自身のテストに合格するときにあなたの進歩がどれほどうまくいくかを知るという利点さえあります(それは素晴らしい動機です!)
個人的な経験から、テストが不要になる可能性がある唯一のケースは、初期のプロトタイプを作成している場合です。その時点では、コードを正確に設計またはテストするのに十分な問題をまだ理解していないためです。
ソフトウェアを完成させるには、次の3つのステップがあります。
テストはあなたを#1にします。テストに合格したからといって、コードが完成するわけではありません。テスト/コードの作成を開始する前に、プロジェクト構造(ユーティリティ、一般的にアクセスされるオブジェクト、レイヤー、フレームワーク)の概念を理解しておくことが望ましいです。テストに合格するためのコードを記述したら、コードを再評価して、アプリケーションのさまざまな側面にリファクタリングできる部分を確認する必要があります。Yuoはこれを自信を持って行うことができます。これは、テストがまだ合格している限り、コードが機能している(または少なくとも要件を満たしている)ことを知っているためです。
プロジェクトの開始時に、構造について考えてください。プロジェクトが進むにつれ、コードの評価と再評価を続けて、設計を維持するか、意味がなくなった場合は設計を変更します。見積もりを行う際には、これらすべての項目を考慮に入れる必要があります。そうしないと、TDDであるかどうかにかかわらず、スパゲッティコードになってしまいます。
私は TDD と単体テストには比較的慣れていませんが、これを使用した 2 つのサイド プロジェクトでは、設計の代替ではなく、設計の補助であることがわかりました。コンポーネント/サブコンポーネントを個別にテストおよび検証できる機能により、迅速な変更を行い、新しい設計アイデアを試すことが容易になりました.
私が TDD で経験した違いは信頼性です。後でではなく、設計プロセスの最初に、より小さなレベルのコンポーネントでコンポーネントのインターフェースを作成するプロセスは、信頼できるコンポーネントが早期に機能することを意味します。難しい問題に取り組むために。
また、やむを得ず戻ってきて細かな部分を維持する必要がある場合は、それに費やす時間を短縮できるため、やりたい仕事に戻ることができます。
ほとんどの場合、TDD が一種の設計ツールを提供することに同意します。私にとって最も重要な部分は、リスクを大幅に軽減しながら、より多くの変更を加える機能を組み込む方法です (コードを削除して機能を追加できる洞察の瞬間がある場合)。
そうは言っても、私が最近契約したよりアルゴリズム的な仕事のいくつかは、設計思想の慎重なバランスなしにTDDの下で少し苦しんでいます. より安全なリファクタリングに関する上記のステートメントは依然として大きな利点でしたが、一部のアルゴリズムでは、TDD は (それでも有用ではありますが) 理想的なソリューションに到達するには不十分です。簡単な例として並べ替えを考えてみましょう。TDD は、バブル ソートのような次善の (N^2) アルゴリズム (およびクイック ソートへのリファクタリングを可能にする一連の合格テスト) に簡単に導く可能性があります。TDD はツールであり、非常に優れたツールですが、多くのものと同様に、解決する問題のコンテキストに応じて適切に使用する必要があります。
それは常にバランスです:
- TDD が多すぎると、機能するコードになってしまいますが、作業は面倒です。
- 「保守可能なコード、クリーンなデザイン、健全なアーキテクチャ」が多すぎると、アーキテクチャの宇宙飛行士が自分自身をコーディング麻痺に陥らせることになります
すべてにおいて中庸。