web-dev-qa-db-ja.com

大規模なリファクタリングを行うときに、TDDを行う人々はどのように作業の損失を処理しますか

しばらくの間、コードの単体テストを書くことを学ぶように努めてきました。

最初は真のTDDを開始しましたが、最初に失敗するテストを作成するまで、コードを記述しませんでした。

しかし、私は最近、多くのコードを含む解決すべき厄介な問題を抱えていました。テストを書いてからコードを書くのに数週間を費やした後、私は自分のアプローチ全体がうまく行かないという不幸な結論に達しました。

これは、コードを作成したばかりの時点では十分に悪い決定ですが、数百の単体テストも作成した場合、それをすべて捨てるのはさらに感情的に難しくなります。

概念実証のためにコードをまとめて、その後アプローチに満足したらテストを作成することができたときに、これらのテストを作成するために3〜4日間の労力を無駄にしたと思わずにはいられません。

TDDを実践する人々は、そのような状況をどのように適切に処理しますか?一部のケースでルールを曲げるケースはありますか、それともそのコードが役に立たないことが判明した場合でも、最初に常に怠惰にテストを記述しますか?

39
GazTheDestroyer

ここには2つの問題があると思います。 1つ目は、元のデザインが最善のアプローチではない可能性があることを事前に理解していなかったことです。これを事前に知っていれば、迅速な使い捨てプロトタイプまたは2つを開発し、可能な設計オプションを検討し、最も有望な方法を評価することを選択した可能性があります。プロトタイピングでは、本番品質のコードを記述する必要はなく、すべての隅々(またはまったく)を単体テストする必要はありません。これは、コードを磨くことではなく、学習に焦点を当てているためです。

現在、プロダクションコードの開発をすぐに開始するのではなく、プロトタイピングと実験が必要であることを理解することは、常に簡単であるとは限りません。取得したばかりの知識を武器に、次回のプロトタイピングの必要性を認識できるかもしれません。そうでないかもしれません。しかし、少なくとも、このオプションを検討する必要があることはわかっています。そして、それ自体が重要な知識です。

他の問題はあなたの知覚との私見です。私たちは皆間違いを犯します。振り返ってみると、私たちが違う方法で何をすべきだったかを簡単に確認できます。これは私たちが学ぶ方法です。プロトタイピングが重要である可能性があることを学習する代償として、ユニットテストへの投資を書き留め、それを乗り越えてください。同じ間違いを2度起こさないように努力するだけです:-)

35
Péter Török

TDDのポイントは、この問題を正確に回避するために、コードの小さな増分小さな関数の場合を記述することを強制することです。 1つのドメインで何週間もコードを作成していて、アーキテクチャを再考したときに、作成したすべての単一のユーティリティメソッドが役に立たなくなった場合、そもそもメソッドが大きすぎることはほぼ間違いありません。 (はい、これは現在rghtを正確に慰めているわけではないことを知っています...)

9
Kilian Foth

ブルックス氏は、「1つは捨てる計画です。とにかく、そうするつもりです」と語った。あなたはまさにそれをしているように私には思えます。とはいえ、コードの大きなスワスではなく、コードのユニットをテストするユニットテストを作成する必要があります。これらはより機能的なテストなので、内部実装よりも優れているはずです。

たとえば、PDE(偏微分方程式)ソルバーを記述したい場合、数学的に解けるものを解こうとするいくつかのテストを記述します。これらは私の最初の「ユニット」テストです-読み取り:機能テストはxUnitフレームワークの一部として実行されます。これらは、PDEを解くために使用するアルゴリズムによっては変わりません。私が気にするのは結果です。 2番目の単体テストは、アルゴリズムのコーディングに使用される関数に焦点を当てるので、アルゴリズムに固有のものになります(Runge-Kuttaなど)。 Runge-Kuttaが適切でないことがわかった場合でも、トップレベルのテスト(Runge-Kuttaが適切でないことを示したテストを含む)を引き続き行うことができます。したがって、2番目の反復には、最初の反復と同じ多くのテストがあります。

あなたの問題はおそらくデザインの問題であり、必ずしもコードの問題ではありません。しかし、詳細がなければ、言うのは難しい。

TDDを実践する人々は、そのような状況をどのように適切に処理しますか?
  1. プロトタイプを作成するタイミングとコーディングするタイミングを検討する
  2. 単体テストはTDDと同じではないことを理解する
  3. 機能単位ではなく、機能/ストーリーを検証するためのTDDテストを作成する

ユニットテストとテスト駆動開発の融合は、多くの苦痛と悲惨さの源です。もう一度確認しましょう。

  • 単体テストは、実装での個々のモジュールと機能の検証に関係しています。 UTでは、コードカバレッジメトリックや非常に迅速に実行されるテストなどに重点が置かれます。
  • テスト駆動開発requirementsの各機能/ストーリーの検証に関係しています。 TDDでは、最初にテストを作成するなどの重点が置かれ、作成されたコードが意図したスコープを超えないようにし、品質のためにリファクタリングします。

要約すると、単体テストには実装の焦点があり、TDDには要件の焦点があります。 同じものではありません。

5
Steven A. Lowe

TDDは反復プロセスであることを覚えておいてください。小さなテストを作成し(ほとんどの場合、数行で十分です)、それを実行します。テストは失敗し、メインソースで直接動作し、テストに合格するようにテストされた機能を実装する必要があります。もう一度やり直してください。

あなたが気づいたように、これはうまくいかないので、あなたは一度にすべてのテストを書こうとするべきではありません。これにより、使用しないテストを作成して時間を無駄にするリスクを軽減できます。

5
BenR

私はあなたがそれを自分で言ったと思います:すべての単体テストを書き始める前に、あなたはあなたのアプローチについて確信がありませんでした。

私が使用した実際のTDDプロジェクト(実際にはそれほど多くなく、2年間の作業をカバーするのは3つだけです)を理論的に学習したものと比較して学んだことは、自動テスト!=ユニットテスト(もちろん、相互に排他的)。

言い換えると、TDDのTにUを付ける必要はありません...自動化されていますが、自動化された機能テストよりも(クラスやメソッドのテストのような)単体テストではありません。同じレベルです。現在取り組んでいるアーキテクチャとしての機能の粒度あなたはハイレベルから始め、いくつかのテストと機能的な全体像のみ、そして最終的に何千ものUTで終わり、すべてのクラスが美しいアーキテクチャで明確に定義されています...

ユニットテストは、チームで作業するときに、コードの変更によってバグが無限に繰り返されるのを防ぐために非常に役立ちます。しかし、プロジェクトに取り掛かるときは、少なくとも各ユーザーストーリーに対してグローバルに機能するPOCを用意する前に、それほど正確なものは何も書きませんでした。

多分それは私の個人的なやり方だと思います。プロジェクトのパターンや構造を最初から決定する十分な経験がないので、最初から何百ものUTを作成することに時間を費やすことはありません...

より一般的には、すべてを壊してすべてを捨てるという考えは常にそこにあります。私たちがツールやメソッドを使用するのと同じくらい「継続的」ですが、エントロピーと戦うための唯一の方法は、最初からやり直すことです。しかし、目標は、それが発生した場合、実装した自動化された単体テストによって、プロジェクトが存在しない場合よりもプロジェクトのコストが削減されることです。

4
GFK

テスト駆動開発とは、開発をドライブすることです。作成したテストは、現在作成しているコードの正確性を主張し、最初の行から開発速度を上げるのに役立ちます。

テストは負担であり、後で段階的に開発するためだけのものであると信じているようです。この考え方はTDDと一致していません。

多分あなたはそれを静的型付けと比較することができます:静的型情報を使用せずにコードを書くことができますが、静的型をコードに追加すると、コードの特定のプロパティを表明し、代わりに心を解放して重要な構造に焦点を当てることができるため、速度と有効性。

3
Dibbeke

主要なリファクタリングを行うことの問題は、あなたが噛むことができる以上に噛み切ったことに気づくように導くことができる、そして時々従うということです。巨大なリファクタリングは間違いです。そもそもシステム設計に欠陥がある場合、難しい決定を下す必要がある前に、リファクタリングを実行するだけで済みます。システムをそのままにして回避するか、再設計していくつかの大きな変更を加えることを計画します。

ただし、別の方法があります。コードをリファクタリングすることの本当の利点は、物事をより簡単に、より読みやすくし、さらに保守を容易にすることです。確信が持てない問題に近づいたら、変更を急上昇させ、問題の詳細を知るためにそれがどこにつながる可能性があるかを調べ、急上昇を捨て、急上昇の内容に基づいて新しいリファクタリングを適用しますあなたに教えた。問題は、ステップが小さく、リファクタリングの努力が最初にテストを書く能力を超えない場合にのみ、確実にコードを確実に改善できることです。テストを作成してから、コードを作成し、ソリューションを明確にするためにもう少しコードを作成するという誘惑に駆られますが、変更によってさらに多くのテストが変更されることにすぐに気付くため、一度に1つだけ変更するように注意する必要があります。

したがって、答えはリファクタリングを主要なものにしないことです。赤ちゃんのステップ。最初にメソッドを抽出し、次に重複の除去を検討します。次に、クラスの抽出に進みます。小さなステップごとに、一度に1つの小さな変更を加えます。コードを抽出する場合は、最初にテストを記述します。コードを削除する場合は、コードを削除してテストを実行し、壊れたテストのいずれかが今後必要になるかどうかを判断します。小さな赤ちゃんが一度に一歩。時間がかかるようですが、実際にはリファクタリング時間を大幅に短縮します。

しかし、現実には、すべてのスパイクが努力の潜在的な無駄であるように見えます。コードの変更がうまくいかない場合があり、VCからコードを復元していることがわかります。これは私たちが日々行うことの現実にすぎません。しかし、失敗したすべてのスパイクは、何かを教えてくれれば無駄にはなりません。失敗するすべてのリファクタリング作業は、あまりにも早くやりすぎているか、アプローチが間違っている可能性があることを教えてくれます。それから何かを学ぶなら、それも時間の無駄ではありません。このことをすればするほど、学ぶことが多くなり、効率的になります。私のアドバイスは、今のところそれを身に着け、より少ないことでより多くのことを学ぶことです。そして、これが、あなたがどこにもあなたを導く前にどれだけスパイクを取るべきかを特定するまで、物事がおそらく必要な方法であることを受け入れることです。

2
S.Robins

3日後にアプローチがうまくいかなかった理由がわかりません。アーキテクチャの不確実性に応じて、テスト戦略の変更を検討できます。

  • パフォーマンスについて不確かな場合は、パフォーマンスをアサートするいくつかの統合テストから始めることをお勧めしますか?

  • APIの複雑さが調査対象である場合は、実際の最小限の単体テストを記述して、それを実行するための最良の方法を理解してください。何も実装せず、クラスにハードコードされた値を返すか、NotImplementedExceptionsをスローさせるだけです。

1
Boris Callens

私にとって、ユニットテストは、インターフェイスを「実際の」使用下に置く機会でもあります(まあ、ユニットテストと同じくらいリアルです)。

テストのセットアップを余儀なくされた場合は、デザインを実行する必要があります。これは、物事を正気に保つのに役立ちます(何かが非常に複雑で、そのためのテストを書くことが負担である場合、それをどのように使用するのでしょうか?)。

これはデザインの変更を回避するのではなく、それらの必要性を明らかにします。はい、完全な書き換えは面倒です。それを回避する(しようとする)ために、おそらくPython(c ++での最終的な開発)で)通常(1つ以上)のプロトタイプをセットアップします。

確かに、あなたはいつもこれらすべてのグッズの時間を持っているわけではありません。それらは正確に[〜#〜]大きい[〜#〜]までの時間が必要な場合ですあなたの目標を達成します...そして/またはすべてを制御下に保ちます。

0
Francesco

クリエイティブデベロッパーサーカスへようこそ


最初にコーディングするためのすべての「法的/合理的」な方法を尊重する代わりに、
試してみてください直感何よりも重要で新しい場合、および必要なサンプルがない場合:

-精神的および想像力ではなく、すでに知っていることから、あなたの本能で書いてください。
-やめて。
-虫眼鏡を使って、書いたすべての単語を検査します。「テキスト」は文字列に近いので「テキスト」と書きますが、「動詞」、「形容詞」などのより正確なものが必要です。もう一度読んで調整してください新しい感覚の方法
...または、あなたは未来について考えているコードを書きましたか?それを除く
-正解です。他のタスク(スポーツ、文化、その他の業務外のもの)を行い、戻ってもう一度読んでください。
-すべてうまく適合し、UMLに渡します
-正解です。他のタスクを実行して、戻ってもう一度読んでください。
-すべてうまく適合し、TDDに渡されます
-これですべてが正しくなりました。
-ベンチマークを試して、最適化することを指摘してください。

表示されるもの:
-すべてのルールを尊重するコードを記述しました
-あなたは経験、仕事の新しい方法、
-何か心の中で変化します。新しい設定を恐れることは決してありません。

そして今、上記のようなUMLが表示された場合、次のように言うことができます
「ボス、これはTDDから始めます...」
それは別の新しいものですか?
「上司、私がコーディングする方法を決定する前に何かを試すでしょう。

PARISよろしく
クロード

0
cl-r