アルゴリズム問題へのTDDのようなアプローチ


10

より良い解決策を見つけようとしたので、私はCodi​​lityのアルゴリズムテストに失敗し、結局何もありませんでした。

では、TDDに似たアプローチを使用できるかどうかを考えさせられました。つまり、通常は同様の方法で徐々にソリューションを開発できるか?

ソートアルゴリズムを作成している場合、標準のBubblesortから2ウェイのバブルソートに移行できますが、Quicksortのようなより高度なものは「飛躍的進歩」ですが、少なくとも簡単に検証できるテストデータがあります。

そのようなテストのための他のヒント?次回私がすることの1つは、内部ループよりも多くのメソッド/関数を使用することです。たとえば、ソートではスワップが必要になることがよくあります。メソッドの場合、呼び出しコードを変更するだけで済みます。派生クラスとして、より高度なソリューションを用意することもできます。

「アルゴリズム」と「通常」の問題では、時間の複雑さが重要な問題を意味します。そのため、TDDのようにテストに合格する代わりに、「動作が向上する」ようにします。

「TDDに似ている」とは、

  1. 手動テストの時間を節約するために、比較的自動のテストを作成します。
  2. インクリメンタル開発。
  3. 回帰テスト、コードが壊れているかどうか、または機能がインクリメント間で変化したかどうかを検出する機能。

比較するとわかりやすいと思います

  1. シェルソートを直接書く
  2. バブルソートからクイックソートへのジャンプ(合計書き換え)
  3. 一方向のバブルソートからシェルソートに段階的に移動します(可能な場合)。

「TDDに似ている」とはどういう意味ですか?TDDを使用して並べ替え関数を開発し、ユニットテストを使用して、並べ替えアルゴリズムをより効率的なアルゴリズムに置き換えても機能が動作することを検証できることは明らかですが、別の質問があるようです。
Doc Brown

"段階的に" :-)-最後に追加された文の「代わりに...」を参照
Olav

2
確かに、まずは有効な(ただしあまり効率的ではない)ソリューションを使用して多くの問題を解決してから、改善することができます。これは決してアルゴリズムやプログラミングの問題に限定されるものではなく、TDDとあまり共通点がありません。これはあなたの質問に答えますか?
Doc Brown

@DocBrownいいえ-バブルソート/クイックソートの例を参照してください。TDDは、インクリメンタルアプローチが多くのタイプの問題に対して適切に機能するため、「適切に機能」します。アルゴリズムの問​​題は異なる場合があります。
Olav

つまり、「TDDがインクリメンタルアプローチであるのと同じように、アルゴリズム設計の質問をインクリメンタルに解決することは可能ですか」という意味であり、「TDDによって」ではないということですか。どうか明らかにしてください。
Doc Brown

回答:


9

残念ながらうまくいかなかったTDDを使って数独ソルバーを作成しようとしたRon Jeffriesの試みも参照してください。

アルゴリズムは、アルゴリズム設計の原則を十分に理解する必要があります。これらの原則により、Peter Norvigのように計画的に段階的に進めることが実際に可能です。

実際、重要な設計作業を必要とするアルゴリズムの場合、ほとんどの場合、作業は段階的に増加します。しかし、アルゴリズム設計者の目に小さな「増分」は、この特定のアルゴリズムファミリで同じ専門知識や知識を持っていなかった人にとって、(フレーズを借りる)飛躍的な進歩のように見えます。

これが、多くのアルゴリズムプログラミングの実践と組み合わせたCS理論の基本的な教育が同様に重要である理由です。特定の「技術」(アルゴリズムの小さなビルディングブロック)が存在することを知ることは、これらのインクリメンタルな飛躍的な進歩を遂げるための長い道のりです。


ただし、アルゴリズムの漸進的な進歩とTDDの間にはいくつかの重要な違いがあります。

違いの1つはJeffOによって言及されています。出力データの正確性を検証するテストは、同じアルゴリズムの異なる実装(または同じソリューションを提供しようとする異なるアルゴリズム)間のパフォーマンスを主張するテストとは異なります。

TDDでは、テストの形式で新しい要件を追加し、このテストは最初はパスしません(赤)。その後、要件が満たされます(緑色)。最後に、コードがリファクタリングされます。

アルゴリズムの開発では、要件は通常変更されません。結果の正当性検証テストは、最初に、またはアルゴリズムのドラフト(非常に信頼性は高いが遅い)の実装が完了した直後に作成されます。このデータの正当性テストはめったに変更されません。TDD riteの一部として失敗(赤)に変更しません。

ただし、この側面では、データ分析の要件(入力セットと期待される結果の両方)は人間の理解において大まかに定義されているだけなので、データ分析はアルゴリズム開発とは明らかに異なります。したがって、要件は技術レベルで頻繁に変化します。この急速な変化により、データ分析はアルゴリズム開発と一般的なソフトウェアアプリケーション開発の中間に位置します。ただし、アルゴリズムは多用されますが、要件もプログラマーの好みに合わせて「速すぎ」ます。

要件が変更された場合、通常は別のアルゴリズムが必要になります。

アルゴリズム開発では、パフォーマンス比較テストを失敗(赤)に変更(タイト)するのはばかげています。これは、パフォーマンスを向上させる可能性のあるアルゴリズムの変更についての洞察を与えません。

したがって、アルゴリズム開発では、正確性テストとパフォーマンステストの両方がTDDテストではありません。代わりに、どちらも回帰テストです。具体的には、正確さ回帰テストでは、正確性を損なうアルゴリズムへの変更を防ぐことができます。パフォーマンステストは、実行速度を低下させるアルゴリズムに変更を加えることを防ぎます。

「赤-緑-リファクタリング」の儀式がアルゴリズム開発の思考プロセスに厳密に必要でも、特に有益でもない場合を除いて個人的な作業スタイルとしてTDDを組み込むこともできます。

アルゴリズムの改善は実際には、現在のアルゴリズムのデータフロー図にランダムな(必ずしも必要ではない)順列を作成したり、以前の既知の実装間でそれらを混合および照合したりすることによって生じると主張します。


TDDは、テストセットに段階的追加できる複数の要件がある場合に使用されます。

または、アルゴリズムがデータ駆動型の場合、テストデータ/テストケースの各部分を段階的に追加できます。TDDも役立ちます。このため、「新しいテストデータを追加する-このデータを正しく処理するようにコードを改善する-リファクタリング」の「TDDのような」アプローチは、アルゴリズムの目的が人間で記述されるオープンエンドのデータ分析作業でも機能します。中心の言葉とその成功の尺度も人間が定義した用語で判断されます。

それは、1回の試行ですべて(数十または数百)の要件を満たすことを試みるよりも、それを圧倒的少なくする方法を教えることを意図しています。つまり、ソリューションの初期ドラフトを実装している間、特定の要件またはストレッチゴールを一時的に無視できると指示できる場合、TDDが有効になります。

TDDはコンピューターサイエンスの代わりにはなりません。これは、プログラマーが一度に多くの要件を満たす必要があるというショックを克服するのに役立つ心理的な松葉杖です。

しかし、正しい結果が得られる実装がすでに1つある場合、TDDはその目標が達成され、コードを(リファクタリングまたは別のプログラマーユーザーに)引き渡す準備ができていると見なします。ある意味では、コードが「十分に優れている」というシグナル(客観的にはすべての正当性テストに合格)を与えることにより、コードを時期尚早に最適化しないことをお勧めします。


TDDでは、「マイクロ要件」(または隠された品質)にも焦点が当てられています。たとえば、パラメーターの検証、アサーション、例外のスローと処理など。TDDは、ソフトウェア実行の通常の過程で頻繁に実行されない実行パスの正確さを保証するのに役立ちます。

特定のタイプのアルゴリズムコードには、これらのものも含まれています。これらはTDDに適しています。ただし、アルゴリズムの一般的なワークフローはTDDではないため、このようなテスト(パラメーターの検証、アサーション、例外のスローと処理)は、実装コードが(少なくとも部分的に)作成された後に作成される傾向があります。


あなたの投稿で最初に引用された2つの単語(「ボブおじさん」)はどういう意味ですか?
Robert Harvey

@RobertHarvey Uncle Bobによると、TDDはアルゴリズムの発見に使用できます。別の著名人によると、それは動作しません。ポジティブとネガティブの例についてバランスの取れた情報が得られるように、両方に言及する必要があると考えました(つまり、誰かが1つの例に言及するときはいつでも、1つは他の例にも言及する義務があります)。
rwong

OK。しかし、あなたは私の混乱を理解していますか?最初の段落は、「ボブおじさん」という言葉を発声している人物を引用しているようです。誰がそれを言っているのですか?
Robert Harvey

@RobertHarveyの注文に準拠しました。
rwong

2

あなたの問題については、2つのテストがあります。

  1. アルゴリズムが依然として正確であることを確認するためのテスト。たとえば、正しくソートされていますか?
  2. パフォーマンス比較テスト-パフォーマンスが向上しています。これはトリッキーになる可能性があるため、同じマシン、同じデータでテストを実行し、他のリソースの使用を制限するのに役立ちます。専用機がお手伝いします。

何をテストするか、または完全なテストカバレッジは議論の余地がありますが、微調整する必要があるアプリケーションの複雑な部分(多くの変更を加える)は、自動テストの完璧な候補だと思います。アプリケーションのこれらの部分は、通常、非常に早期に特定されます。この部分でTDDアプローチを使用することには意味があります。

複雑な問題を解決できることは、さまざまなアプローチを試そうとしないことによって妨げられるべきではありません。自動テストがあると、この領域で役立つはずです。少なくともあなたはそれが悪化していないことを知っているでしょう。


1

そのため、TDDのようにテストに合格する代わりに、「動作が向上する」ようにします。

ちょっと。

ランタイムと複雑さをテストできます。実行時テストは、システムリソースの競合を許容するために、少し寛容である必要があります。ただし、多くの言語では、メソッドをオーバーライドまたは挿入して、実際の関数呼び出しをカウントすることもできます。また、現在のアルゴリズムが次善のものであると確信している場合は、単純な実装よりもsort()呼び出しcompare()回数が少ないことを要求するだけのテストを導入できます。

または、sort()2つのセットを比較しcompare()、ターゲットの複雑度(または、不整合が予想される場合はその前後)に応じて、呼び出しでそれらをスケーリングできるようにすることができます。

また、一連のサイズが厳密に比較以上のものを必要としないことを理論的に証明できる場合、すでに機能しているものを...の呼び出しに制限するのが妥当かもしれませんNN*log(N)sort()N*log(N)compare()

しかしながら ...

パフォーマンスまたは複雑さの要件を満たすことは、基盤となる実装が{AlgorithmX}であることを保証するものではありません。そして、私はこれは通常は大丈夫だと主張します。重要な複雑さ、パフォーマンス、リソース要件などの要件を実装が満たしている場合は、どのアルゴリズムを使用しても問題ありません。

ただし、特定のアルゴリズムが使用されていることを確認したい場合は、面倒で、さらに深くする必要があります。のようなもの

  • ことを確実にすることを正確に呼び出しの期待数compare()およびswap()(または何でも)が作られています
  • すべての主要な関数/メソッドをラップし、予測可能なデータセットを使用して、呼び出しが期待どおりの順序で発生するようにします。
  • Nステップごとの作業状態を調べて、期待どおりに変更されたことを確認します

ただし、繰り返しになりますが、特に{AlgorithmX}を使用する場合は、{AlgorithmX}が実際に使用されたかどうかよりも、テストすることが重要な{AlgorithmX}の機能がおそらく重要です...


また、TDDは、ソフトウェア開発における調査、思考、または計画の必要性を否定するものではありません。また、自動テストスイートでグーグルやホワイトボードを簡単に主張できない場合でも、ブレーンストーミングや実験の必要性を否定することはありません


操作の数に限界を主張する可能性に関する優れた点。私はそれが(モック、スタブ、スパイ)の力であると主張します。TDDで使用でき、他の種類のテストでも使用できます。
rwong

テストシナリオのコードの前にテストを書くことにはあまり意味がありません。これは通常、機能基準が満たされた後の最後の基準です。場合によっては、最初に乱数を実行し、その後に最悪のケースを実行することもありますが、それでも、テストの作成には、いくつかの巧妙な印刷に比べて長い時間がかかります。(統計によっては、おそらくいくつかの汎用コードを書くことができますが、テスト中にはできません)現実の世界では、特定の場合にパフォーマンスが突然低下するかどうかを知りたいと思います。
Olav

codility.com/programmers/task/stone_wallを見ると、Nを超える複雑さがあるかどうかがわかります。ただし、非常に長いスパンで作業する必要がある特殊な場合を除きます。
Olav

@Olav "テストの作成は、いくつかの賢い印刷出力と比較して長い時間がかかります" ... 1度に実行する ...うーん.. 多分、しかし非常に議論の余地があります。ビルドごとに繰り返し行うには?... 絶対にありません。
svidgen 2017年

@Olav「現実の世界では、特定の場合にパフォーマンスが突然低下するかどうかを知りたいと思います。」ライブサービスでは、特定の方法だけでなく、New Relicなどを使用して全体的なパフォーマンスを監視します。そして理想的には、テストは、パフォーマンスクリティカルなモジュールとメソッドが展開前に期待応えられない場合に通知します。
svidgen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.