理論上のTDDのみ


29

1年ちょっと前、幸運にも9か月の休憩をとることができました。その時に、C#のスキルを磨くことにしました。私は多くのプロジェクトに取り組み始め、TDDに従うことを余儀なくされました。

それはかなり啓発的なプロセスでした。

最初は大変でしたが、時間が経つにつれて、よりテスト可能なコードを作成する方法を学びました(実際には、よりソリッドなコードになる傾向があります)。

今、私は労働力に戻り、奇妙なことに気づいています。

私はTDDに従わないことを好みます。

TDDを使用すると速度が遅くなり、実際にクリーンなアプリケーションを設計するのが難しくなります。

代わりに、私はわずかに(大規模に)異なるアプローチを採用しました。

  1. 作業の垂直スライスを選択します
  2. 機能するプロトタイプを開発する
  3. すべてが整頓されるまでリファクタリングする
  4. 私が書いた美しく固くてテスト可能なコードに感謝します。

お気づきかもしれませんが、ステップ1は「テスト対象のパブリックサーフェスを定義する」わけではなく、ステップ2は「パブリックサーフェスからベジェスをテストする」わけではありません。また、どのステップにもテストが含まれていないことに気づいたかもしれません。私はテスト可能なコードを書いていますが、まだテストしていません...まだまだです。

ここで、実際にどのような種類のテストも行っていないことを明確にしたいと思います。私が書いているコードは動作します。手動でテストしているので機能します。

また、自動化されたすべてのテストを行っているわけでもないことを明確にしたいと思います。これは私のプロセスが異なるところです。そして、これが私がこの質問をする理由です。

理論的にはTDD。実際にはありません。

私のプロセスは少し進化しており、TDDと、非常に生産的で合理的に安全であると思われるテストとのバランスを取りました。次のようになります。

  1. テストを念頭に置いて作業の垂直スライスを実装しますが、テストは作成しません。
  2. そのスライスを修正する必要がある場合(1か月後など)
    1. 作業のスライスが正しいことを保証する単体テスト、統合テスト、動作テストなどを書く
    2. コードを修正する
  3. そのスライスを変更する必要がない場合、
    1. 何もしない

テストを書く負担をコードを書く前から変更する前に単純にシフトすることで、はるかに機能するコードを生成することができました。そして、テストの作成に取り掛かるときには、作成するテストの数ははるかに少なくなりますが、ほぼ同じくらいの範囲(高いROI)をカバーします。

私はこのプロセスが好きですが、うまくスケールしないかもしれないと心配しています。その成功は、開発者が物事を変える前にテストを書くことに熱心であることにかかっています。そして、それはかなり大きなリスクのようです。しかし、TDDのリスクはまったく同じです。

だから、私は[BT] DD地獄に行くのですか、これは実用的なコーディングとテストの一般的な形式ですか?

私はこのように働き続けたいです。このプロセスを長期的に機能させるにはどうすればよいですか?

注意:

私は自分のプロジェクトの唯一の開発者であり、要件の収集、設計、アーキテクチャ、テスト、展開などすべてに責任があります。これが私のプロセスが機能している理由だと思います。


2
スパイクのように見え、常に安定化を行うことなく安定化しますIf that slice doesn't need modificationlizkeogh.com/2012/06/24/beyond-test-driven-development
RubberChickenLeader

13
あなたは私が長い間疑っていたTDDについて何かを発見しています。テストファーストマントラは非常に優れた学習ツールですが、デザインではなく、単に良いデザインを奨励するだけです。最終的には、テスト可能なコードと単体テストが必要です。これらは、優れたコードカバレッジを提供し、ソフトウェアの要件を反映しています。賢明な設計原則を実践すれば、最初にテストを書かずにそれを見つけることができます。
ロバートハーベイ

5
うん、そして最初にテストを書くことはあなたのプロトタイピング作業を本質的に倍にします。
ロバートハーベイ

3
それは私がそれが「わずかに」あることについて嘘をついていたことを意味します。
メタファイト

1
「そして、私がテストの作成に取り掛かるとき、私はそれらのはるかに少ない数を書きますが、ほぼ同じくらいの範囲をカバーします(より高いROI)」変更するか、TDDを使用した場合よりも少ないテストで同じ(テスト済みの)コードを何らかの方法でカバーしていると言っていますか?
ベンアーロンソン

回答:


6

プロセスを長期的に機能させるために、コードを作成するときにテストを作成します。

これはあなたのアプローチと矛盾するように見えるかもしれません。しかし、あなたは質問を投げかけたので、私はあなたに私の意見を与えます:

コードの前にテストを書く必要はありません。その純度を忘れてください。ただしその頃にテストを作成する必要があります。
コードが機能するようになったら、少し調整し、バグをいくつか見つけました(ここでは時間のタイムスケールについて話しています)。それで、コードが何をしているのかについて最大限の知識を得ることができます。これは、知識を獲得するテストを書く絶好の機会です。

これを後まで残すことは、知識が時間とともに(自然に)減少することを意味します。

また、あなたが去り、他の誰かがあなたを引き継いだとしても、何が何をするかを(テストを通して)文書化していないという直接的な技術的負債がないことを意味します。

とりわけ、「いつか」は来ないかもしれません。あなたはバスにぶつかるか、新しい冒険のためにバスに乗るかもしれません。

最後に、手動テストは拡張性がなく、エンドユーザーが使用するすべてのデバイスを対象としないことがよくあります。


私はあなたの提案されたアプローチが好きだと思うし、私はおそらく私ができるときにそれを適用するでしょう。私の仕事は非常に断片化されているので、「時間のタイムスケール」が常に可能であるとは限りません。残念ながら私もサポートしているので、火を消すために仕事をやめることがよくあります:)しかし、それは人生です。
メタファイト

問題は、明日は決して来ないということです。常に次の機能があります。そして、あなたは何をすることにしましたか。次の機能を作成するか、「完成した」もののテストを作成しますか?
アンディ

9

TDDは100%を実装するのは困難ですが、アプローチには欠陥があります

  1. 作業の垂直作業スライスを実装する

    1.1 1年が経過しました...

    1.2新しい開発者がプロ​​ジェクトの作業を開始します

  2. そのスライスに変更が必要な場合

    2.3「Clean Coding」スタイルのメソッド名とパラメータ「GetUnicorn(colourOfUnicorn)」を解析する

    2.4 XMLコメントを読む「ゴールドユニコーンを取得(ライディング用)(obvs)」

    2.5元の開発者を追い詰める

    2.6コードが何をすべきかを彼らが覚えていることを願っています

    2.7すべてを説明してもらう

  3. 単体テスト、統合テスト、動作テストなどを記述し、作業のスライスが正しいことを 願っています

  4. コードを修正する

修正が必要なときに単体テストが本当にその価値を示すことを特定するのは正しいと思います。


2
ねえ、私は自己文書化コードを書きます!私のクラスには1つの責任があるため、理解しやすいです。誰も私を追い詰める必要はありません:)
MetaFight

7
@MetaFightを使用すると、金色の生きているユニコーンの上に簡単に見つけることができます!
jonrsharpe

3
私は彼をゴールディコーンと呼びます。
メタファイト

もっと深刻なことに、はい、あなたはポイントを持っています。仕事の負荷が軽くなったときに返済できるように、「借金のテスト」の記事を記録することを検討しました。
メタファイト

4
コードがうまく書かれていてもバグがある場合、おそらく元の開発者がコードを読むことで何を達成するつもりだったかを理解するのはかなり簡単になり、新しい開発者必要なテストを追加できます。唯一の問題は、ほとんどの開発者が優れたコードを書いていると考えていることです。「良い」とは、プログラマーとしてのあなたの視点と経験に大きく依存します。そのため、これには緊張があり、管理する必要があります。
フィル

4

Daniel HollinrakeとEwanの両方に同意します。テストのみでif-if-modifyがこれまでのところうまく機能する最初の重要なポイントは次のとおりです。

I am the sole developer on my projects and I am responsible for everything

おそらく2番目の重要なポイントは次のとおりです。

you're producing nice clean code

TDDが単独のプログラマーに大きな生産性の向上をもたらすとは思いませんし、既にきれいなコードを書いているのであれば、コードの品質をそれほど改善しないかもしれません。

ただし、TDDは、特に他の何かを壊すことなくコードを変更するときが来ると、貧しい/経験のない/時代遅れのプログラマーのコードの品質を確実に改善します。さらに、コードを変更する人が、コードを最初に書いた人と同じ人ではない場合、または数か月が経過している場合です。

言い換えれば、TDDはコードの品質を向上させるための良い習慣であると思います(あなた自身を認識しているように)が、平均的または平凡なプログラマー(たとえば、異なる部門または別の会社)、単独で働くよりもはるかに一般的な状況です。


1
問題の一部はプログラマーが1人しかいないかもしれないが、コードベースは時間の経過とともに大きくなることが多く、小さいとき(テスト用)に機能したものが大きくなると機能しなくなることです。
マイケルデュラント

3

私にとって重要なことは次のように見えます

私は自分のプロジェクトの唯一の開発者であり、要件の収集、設計、アーキテクチャ、テスト、展開などすべてに責任があります。これが私のプロセスが機能している理由だと思います。

これはあなたのために働き、あなたはすてきなきれいなコードを生成しています(私は推測します!)。あなたがする必要があると私が言う唯一のことは、他の開発者が入って、変更を加えることに自信を持つことができるように、テストハーネスを作成することです。また、テストハーネスは、コードの動作の一貫性を保証します。

あなたのアプローチは私のものに似ていると思います。私は通常、自分のプロジェクトの唯一の開発者です。TDDに感謝することで、より小さな関数とよりクリーンなコードを作成できるようになりましたが、テストハーネスとしてコードを作成しながらテストを追加しました。そのようにして、コードが進化し、機能が変更されると、変更を加えることにかなり自信を持つことができます。

テストを記述する2番目の理由は、テストがドキュメントの形式であると感じていることです。関数が作成された理由の背後にある私の理由を説明できます。しかし、ここでは、行動駆動開発についてもっと考えています。


テストスイートは、他の開発者に渡すために4位に来ると思います-ユニットテストの束よりも要件ドキュメント、アーキテクチャ図、設計ドキュメントが問題を伝えるためにはるかに重要になるでしょう。
gbjbaanb

それは公平なポイントですが、悲しいことに、私の経験では、ドキュメントに取り組んできたほぼすべてのプロジェクトが存在する場合、それは古くなっているか不完全です。
ダニエルホリンレイク

1
ここでも同じです。そのため、開発者は物事を文書化することの重要性を認識し、テストの形でより多くのコードを書く必要はありません。コードコメントと要件チケットからより良いドキュメント生成(つまり、メソッドシグネチャの単なる書式設定ではない)を可能にするツールが必要な場合があります。
gbjbaanb

あなたのコメントに応じて、回答を少し編集しました。ありがとうございました。
ダニエルホリンレイク

1
@gbjbaanb手助けできれば、要件のドキュメント、アーキテクチャ図、設計ドキュメントを書くのを避けたいです。これは、それらが非常に早く古くなる傾向があるためです。私の場合、非常に少ない責任で多くの小さなアプリケーションを管理しているので、私はかなり幸運です。これにより、要件とアーキテクチャのドキュメントが少し過剰になります。また、プロジェクトは十分に小さく、全体的な設計が明確です。私は何をしています文書化し、しかし、それらを展開する方法、および自分の健康を監視するために、どのように、どのように相互作用するかのシステムです。
メタファイト

3

単体テストは、コードを維持する問題に取り組むことです。TDDなしではなくTDDでコードを書く方が速いと言う人もいますが、テストを書かなくても新しいコードを書くことができるのは驚くことではありません。

変更する直前にテストを書く練習で見られる問題:

急いで変更する必要があることが多い

必要なときにテストを書くだけで全体的な時間を節約できるかもしれませんが、すべての時間が同じというわけではありません。私が危機モードにいるとき、1時間を節約するためにテストを書くのに2時間費やします-それは完全に価値があります。

コードを書くと同時にテストを書く方が簡単です

単体テストを適切に作成するには、テストしているコードを理解する必要があります。私はよく理解のための演習として単体テストを使用しますが、既存のコードを理解するには時間がかかるため、既存のコードの単体テストには時間がかかる場合があります。それとは対照的に、コードを書くときにテストを書くと、コードをすでに理解しているので、コードを書いたばかりなので、はるかに速く見つけることができます!


マイケルフェザーズのレガシーコードの定義は、テストのないコードです。彼の定義に同意するかどうかに関係なく、既存のコードを変更するコストのかなりの部分が、期待どおりに動作することを保証していることは明らかです。

単体テストを書くと、正しい動作が何であるかを理解してエンコードすることにより、そのコストを相殺します。また、「将来の私たち」が動作がまだ正しいことを確認する簡単な方法を提供します。


2

これは良い質問です。FWIWを2セントで投入します。

約一年前、私は、Salesforceに必ずしも書き込みテストあなたを強制的に染み付いメカニズム持っていたプラットフォームでコーディングされたあなたがコード化された前にではなく、一般的には、書き込みテストにあなたを強制します。

それが機能する方法は、システムがテストを書くことを強制し、テストされたコードの行数をパーセンテージに計算することでした。実稼働インスタンス全体のすべてのコードがテスト済みの75%を下回った場合、Salesforceは動作しません。

この結果、Salesforceで何かをするたびにテストを作成または更新する必要がありました。これはSalesforceの市場シェアに大きな影響を与えると確信していますが、開発者の生活の観点からすると、お尻に大きな痛みがありました

あなただけの小さなチケットを介して取得しようとし、その後、テストされた多くの時間をして来て、あなただけという特徴のために、あなたの開発時間を倍に知っている作品を。

その後、TDDの厄介な概念が、私たちの部門を駆け抜けて、データベースにまで及びました。私たちのアーキテクトは、徹底したテストをIT部門のあらゆる側面に押し出したいと考えていました。お尻のわずかな痛み、お尻のさらに大きな痛みに会います。

当時、TDDは私にはあまり意味がありませんでしたが、今でもまだ意味がありません。私が現在の役割で書いた機能の多くは、あなたが言及したのと同様のメカニズムで機能します。つまり、機能するまで洗練された垂直スライスです。私がその古い役割をしていたとき、今でも実際にコードを書くまでコードが何をするのかわからないことが多いので、私が書くコードを動かすためのテストを書くことができるという考えです。 。は私には意味がなく、面倒で、ほとんど時間の無駄です。

それはすべて、テストは素晴らしいものであり、世界ですべてを正しくする魔法のようなものです。彼らはあなたのコードを正しいものにし、あなたのアプリがあなたが思うように動作することを保証し、一般的にすべてがよりスムーズになります。問題は、コーディングする前にテストを書くのか、コーディングした後にテストを書くのかではなく、テストにどれだけの時間をかけるかということです。少なくとも私のソフトウェア開発経験では、それが本当の問題です。テストには時間とお金がかかり、競合する利益の枠組み内でテストを行う必要があります。

それで、一般的に私はあなたに同意します:実際のTDDは少し厄介で面倒です。その時点で、現在の状況で何が最も効果的かを念頭に置く必要があります。重要なコードを書いている場合は、一般的にテストされていることを確認してください。時間があれば、TDDを試して、プロセスに何かが追加されるかどうかを確認してください。


2
私たちは、TDDを正しくすることから離れた1世代の言語だと感じています。現在、TDDはxUnitフレームワークを備えたほとんどの言語に「ボルトオン」されていると思います。ある時点で、コーディングが行われる方法に組み込まれるようになります-個別ではありません。クラスを定義すると、テスト自体の一部のサブセット(クラス/メソッド自体によって簡単に決定できるもの)とともに、すべてのテストのスタブがすぐに生成されます。
カルフール

3
@Calphool我々はしている実際の言語にいくつか簡単にテスト可能なものを統合します!これを静的型付けと呼びます。Rustは、さらに多くのバグをテストするために、借用チェックでさらにそれを取ります。しかし、ほとんどのテストはその正確なクラスに固有です(「ボタンをクリックすると、ウィジェットが赤に変わります」)-コンパイラー/ IDEは、おそらくそれをテストしようとしていることをどのように知るでしょうか?
user253751

1
@immibis:おそらく型チェックをさらに拡張することによって。おそらく、「ウィジェットが赤くなる」という概念は、何らかの方法でコードから推測できるファーストクラスの概念になります。私は答えを持っていると主張していません。TDDはまだまだ言語進化に完全に統合されていないほど十分に新しいと感じています。
カルフール

1
Salesforceのテストは特にすべて間違っています。テストを実施する必要がありますが、品質テストを作成するのはとてつもなく困難です。理論的には素晴らしいように聞こえますが、実際には、開発者はスプーンで目をそらしたいと思うようになります。

1

あなたのアプローチはお勧めできませんでした。

私があなたのアプローチを使用すると、たとえば次のようになります(家はアプリケーションです):

  1. 私は、ある程度の知識がある初心者または初心者として、家族のために家を建て始めます。
  2. 私は子供部屋、客室などの要件を知っており、「プロトタイプ」の家を建て始めました。
  3. 数回後に「プロトタイプ」の家が完成します。
  4. 構造が手動で十分に安定しているかどうかを調べ始めます。それで私はたくさんの重りを拾い上げて、それを一階の別の部屋に持っていきます。家族と一緒に部屋に座っているとき、天井が壊れないようにするため。しかし、それは壊れ、リファクタリングを開始します。最初にすべての塊をきれいにします。新しいものをビルドし、十分に安定するまで手動でもう一度テストするよりも。
  5. 家族と一緒に引っ越すよりも。すべてが順調。
  6. ガが後になって、私のいとこと両親が私たちを訪ねに来ます。しかし、彼らが私たちの家に入る前に、建築家と土木技師にお金を払って、1階の部屋に座ったときに天井が壊れないようにする必要があります。
  7. 建築家と土木技師は、最初から何も持っていないため、多くの仕事をしています。だから彼らは私の家に行って、私がそれをどのように建てるかを見る必要があります。
  8. そして再び、それは十分に安定していません。そのため、1階の地面をリファクタリングする必要があります。
  9. しかし、その後はすべてがうまくいき、すべてが安全に私の家に入ることができます。

したがって、あなたのアプローチは、私があなたのアプローチで家を建てる前に多くの時間と多くの知識を要します。それとも時間がかかります!また、要件が変更されたときに他のコードのテストを作成できるようにするのは、かなり紳士ではありません。

そのため、「プロトタイプ」をプログラミングせずにリファクタリングを開始するよりも優れたアプローチがあります。プロトタイプをプログラミングする代わりに、次のようにアプリケーションのUMLでデザインを作成します。

  1. ユースケース図を作成します。draw.ioを使用して開始できます。
  2. ユースケースに基づいてEPKダイアグラムを作成して、動作を決定するよりも。(アプリケーションの動作)コード化されたプロトタイプをリファクタリングするよりもリファクタリングが高速です。特に初心者の場合。
  3. クラス図を作成します。(アプリケーションの構造)
  4. 動作の実装で問題が発生する可能性がある場所を特定します。
  5. この動作を実装する方法を決定するために、10行または20行のコードを含む単純なプロトタイプを作成します。初心者に適しています。または、チュートリアルを見て、他のサンプルアプリケーションのソースコードを調べてください。彼らがそれを解決した方法。
  6. コーディングを開始するより。UseCaseの成功したテストを最初に実行します。これはさまざまな方法で実行できます。最初に、テストとそのUseCaseに必要なすべての構造を作成します。Enterprise Architektを使用すると、構造を生成できます。ダイアグラムに基づきます。または、テストの配線中に構造を作成します。したがって、コンパイルエラーは表示されません。ここで言及するのは、アプリケーションの動作のみをテストする必要があるということです。使用しているユースケース。
  7. UseCaseの動作を実装するより。
  8. UseCasesが成功した後、例外の書き込みテストを開始します。そして、テストが有効なときに緑の色を見ると、いつでもいい感じです;)
  9. これで完了です。

確かにこのアプローチにはUMLの知識も必要ですが、すぐに習得できます。また、IDEで行うよりも、クラスの名前を変更したり、ダイグラム内の矢印を移動したりする方が常に高速です。しかし、テストフレームワークの使用を学習することは、最初はより疲れるでしょう。ここでは、オープンソースプロジェクトのテストを実行し、それらがどのように機能するかを確認します。しかし、テスト駆動型のアプリケーションを作成すると、次のアプリケーションははるかに高速になります。そして、すべてがうまく機能していることを知るのは良い気持ちだと思います。

初心者には非常に時間がかかり、結局は良くないので、私はアプローチにただ投票します。構造と動作の間の境界線をきれいにするために、ドメイン駆動設計を使用し、2つのパッケージ(1つは名前がストラクチャ、もう1つは名前が指定されたパッケージ)で非常にドメインを配置できます。また、テスト用。簡単な例は、Javaで書かれたこの例をチェックしてください。


1

私が書いているコードは動作します。手動でテストしているため、機能します。

少し変更した後、条件のあらゆる可能な分岐を手動でテストしましたか?手動テストのフィードバックループにかかる時間。自動テストで得られるフィードバックループにどれだけ近いか。

自動化されたテスト(最初のテストであるかどうかは関係ありません)は、コードのフィードバックループを高速化することにより、高速化を実現します。

6か月後に何らかの条件を手動でテストすることを忘れないでください-テストするすべての重要な条件を文書化するとは言わないでください

  • 作業の垂直スライスを選択します

  • 機能するプロトタイプを開発する

  • すべてが整頓されるまでリファクタリングする

また、リファクタリング中に、リファクタリングの影響を受けるすべてのロジックを手動でテストしましたか?リファクタリングの変更をテストするにはどれくらい時間がかかりますか?リファクタリングによってコードが壊れる場合、ブレークの理由を見つけるのにどれくらい時間がかかりますか?

  • 私が書いた美しく固くてテスト可能なコードに感謝します。

あなたが楽しんだ美しくきれいなコードは非常に主観的です。あなたのコードはクリーンで合理的です。コードが本当に読みやすく、理解可能で、テスト可能であるかどうかを確認する最良の方法は、他の開発者が行ったテストとコードレビューです。

あなたがあなたの方法を非常に生産的であると感じたのは、あなたがコードで作業する開発者のみであり、このプロジェクトで作業を始めたばかりだからだと思います(このプロジェクトは何歳で作業していますか?
書いたものはすべて覚えていて、起こりうる問題の理由を認識することができます。プロジェクトを2〜3年後に始めてからテストの作成を開始すると確信しています。何も忘れないようにしたいからです。


0

間違いを犯さなければ、テストは本当に必要ありません。ほとんどの開発者は間違いを犯しますが、間違いを犯さず、将来間違いを犯さないと確信している場合(そして、あなたがプロジェクトで唯一の人である場合)、テストを書く時間を無駄にする理由は本当にありません。

ただし、コードを変更するときにテストを作成することを提案しているため、ソリューションは中途半端ですが、同時に、メソッドはテストのコードの部分を決定するときに間違いを犯さないと想定しています。これは、変更が影響する可能性のある領域を常に完全に理解している場合にのみ機能します。多くの一般的な開発者(もちろんあなたではない!)が変更を経験していると思います。

もちろん、優れたアーキテクチャ、SOLIDの原則などにより、このような事態を防ぐことができますが、ほとんどの開発者は完璧ではないため、システム全体のテストが重要です。


もちろん、優れたアーキテクチャ、SOLID原則などは、このような事態を防ぐはずです-いいえ。複雑なシステムには、他の部分に影響する部分があります。たとえば、Rubberduckで Antlr文法を変更すると、意図した変更部分を簡単に完全に機能させることができますが、他の45個の機能が壊れます。徹底的なテストがなければ、知る方法はありません。また、毎回すべてのケースを手動でテストしたいと思うのは正気でなくてはなりません。リゾルバーで何かを変更して987テストが壊れた場合、何か間違ったことをして、それが何を影響したかを知っています。
マチューギンドン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.