web-dev-qa-db-ja.com

テスト駆動開発(および一般的にアジャイル)のこの制限は実際に関連していますか?

テスト駆動開発(TDD)では、次善のソリューションから始めて、テストケースを追加してリファクタリングすることにより、より良いソリューションを繰り返し作成します。ステップは小さいと想定されています。つまり、新しいソリューションはそれぞれ、以前のソリューションの近辺にあるようになります。

これは、勾配降下法や局所探索などの数学的局所最適化手法に似ています。そのような方法のよく知られている制限は、大域的な最適値、または許容可能な局所的な最適値を見つけることを保証しないことです。開始点が許容できるすべてのソリューションから悪いソリューションの大きな領域によって分離されている場合、そこに到達することは不可能であり、メソッドは失敗します。

より具体的に言うと、いくつかのテストケースを実装し、次のテストケースには完全に異なるアプローチが必要になるシナリオを考えています。以前の作業を破棄して、最初からやり直す必要があります。

この考え方は、TDDだけでなく、小さなステップで進むすべてのアジャイル手法にも実際に適用できます。 TDDとローカル最適化の間のこの提案されたアナロジーには重大な欠陥がありますか?

29
Frank Puffer

そのような方法のよく知られている制限は、大域的最適値、または許容可能な局所的最適値を見つけることを保証しないことです。

比較をより適切なものにするために:ある種の問題では、反復最適化アルゴリズムは良好な局所最適値を生成する可能性が高く、他の状況では失敗する可能性があります。

いくつかのテストケースを実装して、次のテストケースには完全に異なるアプローチが必要になるシナリオを考えています。以前の作業を破棄して、最初からやり直す必要があります。

これが実際に起こり得る状況を想像できます:間違ったアーキテクチャを選択すると、既存のすべてのテストを最初から再作成する必要があります。オペレーティングシステムAのプログラミング言語Xで最初の20個のテストケースの実装を開始するとします。残念ながら、要件21には、Xが利用できないオペレーティングシステムBでプログラム全体を実行する必要があることが含まれています。したがって、ほとんどの作業を破棄し、言語Yで再実装する必要があります(もちろん、コードを完全に破棄するのではなく、新しい言語とシステムに移植します)。

これは、TDDを使用する場合でも、事前に全体的な分析と設計を行うことをお勧めします。ただし、これは他の種類のアプローチにも当てはまるため、固有のTDD問題とは見なしません。そして、現実世界のプログラミングタスクの大部分では、標準アーキテクチャ(プログラミング言語X、オペレーティングシステムY、ハードウェアXYZ上のデータベースシステムZなど)を選択するだけで、TDDのような反復的または俊敏な方法論を比較的確実に実行できます。あなたを行き止まりに連れて行きません。

Robert Harveyの引用: "ユニットテストからアーキテクチャを拡張することはできません。" またはpdr: "TDDは、最高の最終設計を行うのに役立つだけでなく、より少ない試行でそこにあります。 "

だから実際にあなたが書いたもの

開始点がすべての許容可能なソリューションから悪いソリューションの大きな領域によって分離されている場合、そこに到達することは不可能であり、メソッドは失敗します。

真になるかもしれません-間違ったアーキテクチャを選択すると、そこから必要なソリューションに到達できない可能性があります。

一方、事前に全体的な計画を立てて適切なアーキテクチャを選択する場合、TDDを使用することは、「グローバルな最大値」(または少なくとも十分な最大値)に達することが期待できる領域で反復検索アルゴリズムを開始するようなものです。 )数サイクルで。

8
Doc Brown

TDDに極大値の問題があるとは思いません。あなたが書いたコードは、あなたが正しく気づいたようにかもしれないが、それがリファクタリング(機能を変更せずにコードを書き換える)が整っている理由です。基本的に、テストの増加に伴い、テストにより動作を変更せずに必要に応じて、オブジェクトモデルの重要な部分を書き換えることができます。テストは、システムについての状態の不変の真理であり、したがって、極大値と絶対最大値の両方で有効である必要があります。

TDDに関連する問題に関心がある場合は、私がよく考える3つの異なる問題に言及できます。

  1. completeness問題:システムを完全に説明するには、いくつのテストが必要ですか? 「事例によるコーディング」はシステムを説明する完全な方法ですか?

  2. hardening問題:インターフェイスへのテストが何であれ、変更​​できないインターフェイスが必要です。テストは不変の真理を表します。残念ながら、これらの真理は、私たちが作成するほとんどのコードではまったく知られていません。

  3. テストダメージ問題:アサーションをテスト可能にするために、次善のコードを書く必要があるかもしれません(例えば、パフォーマンスが低い)。どのようにしてテストを記述すれば、コードは可能な限り優れたものになりますか?


コメントに対処するために編集:これは、リファクタリングを介して「double」関数の極大値を除外する例です

テスト1:入力が0の場合、ゼロを返します

実装:

function double(x) {
  return 0; // simplest possible code that passes tests
}

リファクタリング:不要

テスト2:入力が1の場合、2を返す

実装:

function double(x) {
  return x==0?0:2; // local maximum
}

リファクタリング:不要

テスト3:入力が2の場合、4を返す

実装:

function double(x) {
  return x==0?0:x==2?4:2; // needs refactoring
}

リファクタリング:

function double(x) {
  return x*2; // new maximum
}
19
Sklivvz

彼の回答 では、@ Sklivvzは問題が存在しないと説得力のある方法で主張しました。

私はそれが問題ではないことを主張したいと思います。一般に反復方法論、特にアジャイル、特にTDDの基本的な前提(および存在理由)は、グローバル最適だけでなくローカル最適も同様ではないということです。知られている。つまり、言い換えれば、それが問題であったとしても、とにかく反復的な方法でそれを行う方法はありません。あなたが基本的な前提を受け入れると仮定します。

13
Jörg W Mittag

あなたが数学的な用語で説明しているのは、私たちが自分を隅に描くことです。この発生はTDDに限定されることはほとんどありません。ウォーターフォールでは、数か月にわたって要件を収集して注ぐことができます。グローバルマックスがそこに到達するためだけに表示され、次の丘のすぐ上でより良いアイデアがあることを理解できると期待しています。

違いは、現時点では完璧であるとは決して期待していなかったアジャイル環境にあるため、古いアイデアを捨てて新しいアイデアに移行する準備ができています。

TDDに固有の機能として、TDDで機能を追加するときにこれが発生しないようにする方法があります。 Transformation Priority Premise です。 TDDにリファクタリングする正式な方法がある場合、これは機能を追加する正式な方法です。

13
candied_orange

TDDとアジャイルプラクティスは、最適なソリューションを生成することを約束できますか? (または「良い」解決策ですか?)

正確ではありません。しかし、それは彼らの目的ではありません。

これらの方法は、ある状態から別の状態への「安全な通過」を提供するだけであり、変更には時間がかかり、困難であり、リスクがあることを認めます。また、両方のプラクティスのポイントは、アプリケーションとコードの両方が実行可能であり、要件をより迅速かつより定期的に満たすことが証明されていることを確認することです。

...[TDD]は、要件を満たすことが証明されていないソフトウェアを追加できるソフトウェア開発とは反対です...ケントベックTDDはシンプルなデザインを奨励し、自信を刺激すると2003年に述べた、技術を開発または「再発見」したことで評価されました。Wikipedia

TDDは、コードの各「チャンク」が要件を満たすことを保証することに焦点を当てています。特に、不十分なコーディングによって要件を推進するのではなく、コードが既存の要件を確実に満たすのに役立ちます。ただし、実装が「最適」であるという保証はありません。

アジャイルプロセスについて:

作業ソフトウェアは進行状況の主要な測定基準です...各反復の最後に、利害関係者と顧客代表は進行状況を確認し、投資収益率を最適化するために優先順位を再評価します( Wikipedia

敏捷性は最適なものを探しているわけではありませんソリューション;ちょうどworkingソリューション-最適化の目的[〜#〜] roi [〜#〜]laterではなく、実用的なソリューションsoonerを約束します。 「最適な」ものではありません。

しかしquestionが間違っているため、問題ありません。

ソフトウェア開発における最適は、あいまいで動くターゲットです。要件は通常流動的であり、上司の上司でいっぱいの会議室であなたの恥ずかしいことに現れるだけの秘密に満ちています。そして、ソリューションのアーキテクチャとコーディングの「本質的な良さ」は、同僚と管理上の大君の意見の分かれた主観的な意見によって評価されます-誰も実際には良いソフトウェアについて何も知らないかもしれません。

少なくとも、TDDとアジャイルのプラクティスでは、困難を認め、次の2つのことを最適化しようとしますある客観的で測定可能:機能するv。機能しないおよび早いv。後で。

また、客観的な指標として「実用的」と「より早く」があるとしても、それらを最適化する能力は主にチームのスキルと経験次第です。


could努力の結果として解釈されるものoptimalソリューションには次のようなものが含まれます。

等..

thoseのそれぞれが実際に最適なソリューションを生成するかどうかは、尋ねるべきもう1つの素晴らしい質問です。

8
svidgen

これまで誰も追加していないことの1つは、あなたが説明している「TDD開発」は非常に抽象的な非現実的なものであることです。それは、アルゴリズムを最適化している数学的なアプリケーションのようなものかもしれませんが、ほとんどのコーダーが取り組んでいるビジネスアプリケーションではあまり起こりません。

現実の世界では、テストは基本的にビジネスルールを実行および検証しています。

例-顧客が30歳で、妻と2人の子供がいる非喫煙者の場合、プレミアムカテゴリは「x」などです。

プレミアム計算エンジンが非常に長い間正しくなるまで、そしてアプリケーションが稼働している間はほとんど間違いなく、プレミアム計算エンジンを繰り返し変更することはありません;)。

実際に作成したのはセーフティネットで、特定のカテゴリの顧客に新しい計算方法が追加されたときに、古いルールがすべて突然破られて間違った答えを出さないようにします。デバッグの最初のステップが、バグを修正するコードを書く前にエラーを再現するテスト(または一連のテスト)を作成することである場合、セーフティネットはさらに役立ちます。その後、1年後、誰かが誤って元のバグを再作成した場合、コードがチェックインされる前にユニットテストが失敗します。はい、TDDで許可されていることの1つは、自信を持って大規模なリファクタリングと整頓を行うことができることです。しかし、それはあなたの仕事の大部分であってはなりません。

4
mcottle

邪魔にならないと思います。ほとんどのチームには、ホワイトボードに書いても、最適なソリューションを思いつくことができる人はいません。 TDD/Agileが邪魔になりません。

多くのプロジェクトは最適なソリューションを必要とせず、必要な時間、エネルギー、集中力を必要とするプロジェクトがこの分野で行われます。私たちが構築する傾向がある他のすべてのものと同様に、まず、それを機能させます。次に、それを速くします。パフォーマンスがそれほど重要な場合は、ある種のプロトタイプを使用してこれを実行し、多くの反復によって得られた知恵を使用して全体を再構築できます。

いくつかのテストケースを実装し、次のテストケースには完全に異なるアプローチが必要になるシナリオを考えています。以前の作業を破棄して、最初からやり直す必要があります。

これは発生する可能性がありますが、発生する可能性が高いのは、アプリケーションの複雑な部分を変更する恐れです。テストがないと、この領域でより大きな恐怖感が生まれます。 TDDとテストスイートの利点の1つは、変更する必要があるという考えでこのシステムを構築したことです。最初からこの一体型の最適化されたソリューションを思いついた場合、変更するのが非常に難しい場合があります。

また、これを最適化不足の懸念のコンテキストに入れてください。パフォーマンスに非常に重点を置いていたため、必要のないものを最適化し、柔軟性のないソリューションを作成することに時間を費やすしかありません。

3
JeffO

「局所最適」のような数学的概念をソフトウェア設計に適用することは、誤解を招く可能性があります。このような用語を使用すると、ソフトウェア開発は実際よりもはるかに定量的かつ科学的になります。コードに「最適」が存在していても、それを測定する方法がないため、到達したかどうかを知る方法がありません。

アジャイルの動きは、ソフトウェアの開発が数学的な方法で計画および予測できるという信念に対する反応でした。良くも悪くも、ソフトウェア開発は科学というよりクラフトのようなものです。

0
JacquesB