質問

免責事項:私は素人が現在のプログラムに学習しています。プロジェクトの一部、また長い〜500行以上書かれたものではありませんでします。

私の質問は:守備のプログラミングはユアセルフ原則を繰り返してはいけない違反しませんか?防御的プログラミングの私の定義が正しいと仮定すると、それはあなたのコードに有害である、ではないでしょう(関数呼び出しではなく、反対の入力を検証しましたか)?

たとえば、これが悪います:

int foo(int bar)
{
    if (bar != /*condition*/)
    {
        //code, assert, return, etc.
    }
}

int main()
{
    int input = 10;
    foo(input); //doesn't the extra logic
    foo(input); //and potentially extra calls
    foo(input); //work against you?
}   

これに比べます:

int main()
{
    if (input == /*condition*/)
    {
        foo(input);
        foo(input);
        foo(input);
    }
}

ここでも、素人として、パフォーマンスが行くように、私は単純な論理文は限りあなたに対してカウントどのくらいかわからない、しかし確実に防御的プログラミングは、プログラムや魂のために良いではありません。

役に立ちましたか?

解決

これはすべての契約のに降りてくるインタフェースが用意されています。このため2つの異なるシナリオがあります。入力と出力は

入力 - それによって、私は基本的な機能へのパラメータの意味は - 原則として実装によってチェックする必要があります。

出力 - リターンの結果であること - 基本的には、少なくとも私の意見では、呼び出し側から信頼されなければならない。

。 一方の当事者が契約を破るならば何が起こる:

このすべては、この質問で鍛えていますか?たとえば、あなたがインターフェイスを持っていたと言うことができます:

class A {
  public:
    const char *get_stuff();
}

とその契約はヌル文字列が、それはこれを実行しても安全です(それは最悪で、空の文字列になります)が返されないことを指定します:

A a = ...
char buf[1000];
strcpy(buf, a.get_stuff());

なぜ?あなたは間違っていると呼び出し先がnullを返した場合さて、その後、プログラムがクラッシュします。それはの実際OK のです。いくつかのオブジェクトがその契約に違反した場合、一般的に結果を言えば、壊滅的である必要があります。

あなたが過度に防御的であることに直面するリスクはあなたが(より多くのバグを導入することができます)不要なコードの多くを書くことですか、あなたが実際に例外を飲み込むことにより、深刻な問題をマスクする可能性があることをそのあなたが本当にすべきではない。

コース状況は、これを変更することができます。

他のヒント

DRY原則に違反すると、そのように見えます:

int foo(int bar)
{
    if (bar != /*condition*/)
    {
        //code, assert, return, etc.
    }
}

int main()
{
    int input = 10;
    if (input == /*condition*/)
    {
       foo(input);
       foo(input);
       foo(input);
    }
}
あなたが見ることができるように、

、問題は、我々はプログラムの中で二度同じチェックを持っているので、条件が変化した場合、我々は二つの場所でそれを変更する必要があり、そしてチャンスは我々が奇妙な行動を起こし、そのうちの一つを忘れていることであるということです。 DRYは「二度同じコードを実行しない」という意味ではありませんが、

「二度同じコードを書いていません」

その盲目的に次のような原理が理想と間違いである最初の私の状態をみましょう。あなたは(たとえば、アプリケーションの安全性)、通常ははるかにDRY違反していることが重要である、達成したいものを達成する必要があります。原則の故意の違反はGOODプログラミングで最も頻繁に必要です。

例:私が行う重要な段階でのダブルチェック(例えばLoginService - 最初の一回LoginService.Loginを呼び出す前に入力を検証し、再度内部)が、時々私は私がすべてをすることを確認しました後に、後に再び外1を除去する傾向通常、ユニットテストを使用して、100%に動作します。それは異なります。

私はしかし、二重条件チェックをかけて働いた飽きないと思います。全く逆に、通常、複数の大きさに悪いですそれらを忘れて:)

私は、エラーの上に抄紙、より大きく、それは冗長なコードが含まれるような望ましくないいくつかのことを、ないので防御的プログラミングは、いわれのない非難の種類を取得し、と思います。

ほとんどの人々はそれがエラーに遭遇した場合、プログラムが高速に失敗することに同意しているように見えるが、そのミッションクリティカルなシステムは、好ましくは、失敗することはありません、代わりにエラー状態に直面して行く上で維持するために偉大な長さに行く必要があります。

それは矛盾した状態にありますとき、

その文に問題があります、もちろん、どのようにしてもミッションクリティカルなプログラムは、継続することができます。もちろんそれは、本当にすることはできません。

何がしたいことは起こって奇妙な何かがあります場合でも、正しいことを行うためにあらゆる合理的な一歩を踏み出すためのプログラムです。同時に、プログラムは、の大声の、それは、このような奇妙な状態に遭遇するたびに文句を言う必要があります。そして、それは回復不能なエラーが発生した場合には、それは通常、安全にシステムをシャットダウンするか、いずれかが利用可能な場合、いくつかのバックアップシステムを作動させる、むしろそれが正常に失敗する必要があり、HLT命令を発行することは避けてください。

あなたの簡略化した例では、はい、第二のフォーマットはおそらく望ましいます。

しかし、実際に大規模で複雑な、そしてより現実的なプログラムには適用されません。

あなたは決して知って、事前にどこかどのように「foo」が使用されますので、あなたが入力を検証することによってFOOを保護する必要があります。入力は、発信者によって検証された場合(例えば、あなたの例では、「メイン」)し、「メイン」検証ルールを知っているし、それらを適用する必要があります。

実世界のプログラミングでは、入力検証ルールはかなり複雑になることがあります。呼び出し側は、すべての検証ルールを知って作成し、それらを適切に適用することは適切ではありません。いくつかの呼び出し側は、どこか、検証ルールを忘れてしまった、または間違ったものをするつもりさ。だから、その優れたが、それが繰り返し呼び出されます場合でも、「foo」という内部検証を置くために。これは、「foo」というの詳細についてはあまり考え、抽象的、信頼できるインターフェイスとしてより多くのそれを使用する発信者を解放呼び出し先への発信者からの負担をシフトします。

あなたが本当に「foo」が同じ入力で複数回呼び出されますパターンを持っている場合、私は一度検証を行うラッパー関数を提案し、検証を側は、手順保護されていないバージョン:

void RepeatFoo(int bar, int repeatCount)
{
   /* Validate bar */
   if (bar != /*condition*/)
   {
       //code, assert, return, etc.
   }

   for(int i=0; i<repeatCount; ++i)
   {
       UnprotectedFoo(bar);
   }
}

void UnprotectedFoo(int bar)
{
    /* Note: no validation */

    /* do something with bar */
}

void Foo(int bar)
{
   /* Validate bar */
   /* either do the work, or call UnprotectedFoo */
}
アレックスが言ったように、

、それは例えば、私はほとんど常にプロセスにおけるログの各段階での入力を検証し、状況によって異なります。

他の場所では、あなたはすべてのことを必要としません。

しかし、あなたが与えた例では、私が原因」、あなたは複数の入力を持っていること、第二の例では、と仮定しているそれ以外の場合は、同じ機能にあなたを意味し、同じ入力に対して3回の呼び出しに冗長になるだろう「条件を3回書くことがあるでしょう。今では冗長である。

の入力は常にちょうど機能に含めるにチェックする必要がある場合。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top