web-dev-qa-db-ja.com

なぜアサーションを使用する必要があるのですか?

私は主張の考えを決して知りませんでした-なぜあなたはそれらを使うべきですか?

つまり、私がフォーミュラドライバーであり、すべての主張がセキュリティベルト、ヘルメットなどであったとしましょう。

(デバッグ中の)テストはすべて問題ありませんでしたが、今度はレース(リリース)を行いたいと思います!テスト中に問題がなかったので、すべてのセキュリティを削除する必要がありますか?

私は決してそれらを削除しません。アサートに相当するものを削除してもコードのプロファイルが作成されなかったか、アサートが完全に置き換えられたと主張する人のほとんどは、特に80/20の法則に関して、実際のパフォーマンス上の利点は見たことがありません。

だから、私はどういうわけかポイントを逃していますか、または誰かに私にアサートを使用する必要がある理由を教えてもらえますか?ちなみに、私はユニットテストを使用しています。

50
jan

まず、パフォーマンスの違いが大きくなる可能性があります。あるプロジェクトでは、私たちの主張は文字通り3倍の速度低下を引き起こしました。しかし、彼らは私たちがいくつかの本当に厄介なバグを発見するのを助けました。

それがまさにポイントです。

アサートは、バグを見つけるのに役立ちます。そして、それらはリリースビルドで削除されるため、パフォーマンスを気にすることなく、それらの多くを配置する余裕があります。失敗したアサーションに実際に対処するためにそこにいない場合、それらは無価値になるので、削除したほうがよいでしょう。

エラーをキャッチして例外をスローすることでさえ、実際には解決策ではありません。プログラムのロジックに欠陥があり、例外を処理してもプログラムが壊れています。

基本的に要約すると、「なぜ、処理できないエラーを検出する必要がないのか」です。

開発中にいくつかのエラーをキャッチする必要があります。テストをすり抜けて顧客が使用するリリースビルドに入ると、プログラムが壊れただけで、実行時のエラーチェックで修正されることはありません。

私は主張の考えを決して知りませんでした-なぜあなたはそれらを使うべきですか?

つまり、私がフォーミュラドライバーで、すべての主張がセキュリティベルトやヘルメットなどであったとしましょう。

はい、これはnotがアサートを使用する場合の良い例です。これらは、実行時に実際に問題が発生する可能性があり、チェックする必要があるものです。あなたのフォーミュラワンドライバーは、いくつかのセキュリティ予防策を忘れるかもしれません、そして、彼がそうするなら、誰かが傷つく前にすべてを止めたいです。

しかし、エンジンがインストールされていることを確認するためのチェックはどうですか?レース中にそれをチェックする必要がありますか

もちろん違います。エンジンなしでレースに出れば、めちゃくちゃになってしまい、エラーを見つけても何もできない。

代わりに、これは開発中にキャッチする必要があるか、まったくキャッチしないエラーです。デザイナーが車にエンジンを入れるのを忘れた場合、開発中にこのエラーを検出する必要があります。それは主張です。これは開発中の開発者に関係がありますが、その後はエラーが存在してはならず、存在する場合、私たちにできることは何もありません。

それが基本的に違いです。例外は、処理可能なエラーを処理することにより、ユーザーを支援するためにあります。

アサーションは、youを支援するためにあります。これは、最初から発生してはならないエラーを警告することで、製品の前に修正する必要がありますは発送できます。ユーザー入力に依存しないが、コードが想定どおりに動作することに依存するエラー。

4の平方根はneverが3に評価される必要があります。エラーは単に不可能です。それが発生した場合は、プログラムロジックが壊れています。どの程度のエラー処理を行うかは関係ありません。開発中にキャッチする必要があるか、まったくキャッチしない必要があります。例外処理を使用してこのエラーをチェックして処理した場合、例外はどうなりますか? 「プログラムは根本的に壊れています。使用しないでください」とユーザーに伝えますか?

開発者からのメールはそれを達成できたでしょう。なぜわざわざプログラムコードに組み込むのですか?これは、単に発生してはならない問題の例です。もしそうなら、私たちは戻ってプログラムを修正しなければなりません。他の形式のエラー処理は不可能です。

ただし、読み取り用にファイルを開くことができないなど、一部のエラーは可能性があります。それが起こるとそれは悪いことかもしれませんが、それが起こることを受け入れる必要がありますできます。したがって、もしそうなら、それを処理する必要があります。

アサートは、発生する可能性のないエラーをキャッチするためのものです。

45
jalf

Andrew Koenigは、以前は 出荷コードでの例外とアサーションの使用に関する優れた哲学的議論 を持っていました。結局、プログラムが取り返しのつかないほど壊れた状態にあるとき、野生のことをするのを防いでいます。

したがって、プログラムが内部状態に反論の余地のない何かを発見した場合、呼び出し側に何も問題がないように見せかける機会を与えるよりも、すぐに終了する方がよいと私は信じています。

必要に応じて、例外は、例外をキャッチした後で何か賢明なことができる状況のために予約する必要があると思います。不可能だと思っていた状態を発見したとき、その後どうなるかについてはあまり語りません。

35
cdleary

コードコンプリート2から:「発生すると予想される条件にはエラー処理を使用し、発生してはならない条件にはアサーションを使用してください。」

よく引用される例は、除算の前に分母のゼロをチェックすることです。

本番コードからアサーションを取り除くことが期待されています。彼らはあなたが間違いを見つけるのを助けるために開発中にそこにいます。

ユニットテストはアサーションの代わりにはなりません。

17
Nosredna

デバッグが容易になるためです。

デバッグの時間のかかる部分は、最初に気付いた症状からコードのエラーまで問題を追跡することです。適切に記述されたアサーションにより、気付く症状が実際のコードの問題にはるかに近くなります。

非常に単純な例は、配列の最後を超えてインデックスを作成し、最終的にクラッシュを引き起こすメモリ破損を引き起こすバグです。クラッシュから問題のインデックス操作までさかのぼるには、長い時間がかかる場合があります。ただし、インデックスをチェックするインデックス操作の横にアサーションがある場合、プログラムはエラーのすぐ横で失敗するため、問題をすばやく見つけることができます。

7
David Norman

それは物議を醸す主題です。私のような多くの人々は、実際にはそれらを本番コードに残しておくことを好みます。とにかくプログラムが雑草に入る場合は、そこにアサーションを入れて、顧客が少なくとも行番号とファイル名(またはアサーションを実行するように構成した情報やアクション)を提供できるようにすることもできます。アサーションを省略した場合、すべての顧客が「クラッシュした」と報告する可能性があります。

これは、おそらく、アサートチェック、または少なくともプロファイルによってパフォーマンスの問題が発生するかどうかを確認するために、コストのかかる操作を行うべきではないことを意味します。

4
Brian Neal

彼らはあなたがあなたの仮定をテストすることを可能にします。たとえば、速度を計算したいとします。あなたはおそらくあなたの計算が光速よりも遅いと断言したいと思うでしょう。

アサーションは開発用であり、混乱しないようにします。

3
geowa4

あなたの投稿から、アサーションを使用するという考えに反対しているのではなく、デバッグでアサーションを使用し、本番環境でアサーションをアクティブにしないという考えに反対しているようです。

これは、デバッグ時にプロセスを壊滅的に失敗させたい、つまり例外をスローして終了して、エラーに対処できるようにするためです。本番環境では、これがシステム全体に影響を与える可能性があり、エラー状態が発生するのはごく少数の場合のみです。したがって、本番環境では、おそらくエラーをログに記録しますが、プロセスは実行し続けます。

アサーションを使用すると、デバッグとリリースの間の動作を変更できます。

アサーションを本番コードで消音するだけではいけないことに同意します。テスト環境では多くのエラーが公開されないため、本番環境でアサーションが失敗するタイミングを知ることが重要です。

2
Larry Watanabe

リファクタリング中のアサーションは非常に貴重だと思います。 alogrihm1()をalgorithm2()に置き換える場合は、両方を使用して、結果が等しいことをアサートできます。その後、アルゴリズムを段階的に廃止することができます1()

アサートは、迅速に行うことができるいくつかの変更にも適していますが、システムの状態のコンテキストではあまり確信が持てません。仮定に対してアサーションを設定すると、問題がある場合はすぐに指摘するのに役立ちます。

リリースでマクロなどを使用してアサートを削除する必要があるかどうかは議論の余地がありますが、これは私がこれまで取り組んできたプロジェクトで行われていることです。

2
psquare

完全なコードでは、次のようなセクションがあります。他に何もなければifを書くたびに何かを逃しているかもしれません。

このコードのようです

int i = 1
i = i++ 

一般的なプログラマーは、私が後のコードで否定的である場合に何が起こるかについて決して考えません。コードがオーバーフローを生成する可能性がわずかにあり、Javaのような言語はmaxintからminintにジャンプし、非常に大きな負の数を取得します。これは通常あなたが言うすべてのケースです。ええと、これは決して起こりませんが、それが起こった場合、あなたのプログラムは何をしているのでしょうか? elseステートメントをプログラムしないのではなく、このようにして、プログラムが何をしているのかわからなくなった瞬間にプログラムが完全にクラッシュするはずです。本番コードでは、ユーザーに通知するなどのクラッシュとは異なるものが必要です。メンテナと終了します。

アサーションのもう1つの用途は、契約主導の設計です。インターフェイスでコントラクトを指定し、プログラム内の場所に応じて入力をアサートしますが、はるかにインポートすると、出力2をアサートします。

本番コードで無効化されたアサーションがアサーションをかなり役に立たないものにすることに同意します。そして、Java vmの場合、デフォルトのアサーションがオフになるのは私の意見では危険です。

1
Janusz

アサートは、リリース中に不要な開発中の状態をチェックするためにのみ使用する必要があります。

これは、開発でアサーションを使用する方法の非常に簡単な例です。

A(char* p)
{
    if(p == NULL)
        throw exception;

    B(p);
    C(p);

}

B(char* p)
{
    assert(p != NULL);
    D(p);
    do stuff;
}

C(char* p)
{
    assert(p != NULL);
    D(p);
    do stuff;
}

D(char* p)
{
    assert(p != NULL);
    do stuff;
}

"if(p == NULL)throw exception;"を呼び出す代わりに5回、一度呼び出すだけで、B()、C()、およびD()を入力したときにNULLではないことがすでにわかっています。そうしないと、「コードを変更した」ため、アサーションは開発フェーズで終了します。 「ユーザーの入力」のためではありません。

これにより、リリースバージョンでコードの実行が大幅に高速化されます。これは、「-DNDEBUG」を指定してgccを呼び出すだけで、すべてのアサーションがコンパイルされず、実行可能ファイルからすべての「不要なチェック」が削除されるためです。

1

私が取り組んだ多くのプロジェクトでは、デバッグとリリースで異なる動作をするカスタムマクロを使用してアサーションが行われました。

デバッグでは、条件がfalseの場合、デバッガーはコードのその時点で開始されます。

リリースでは、エラーはログファイルに書き込まれ、ユーザーに警告が表示され、システムは未保存のデータを保存しようとします。不明な状態であるため、これは失敗する可能性がありますが、試す価値はあります。

1
Pete Kirkham

「不可欠なカルバンとホッブス」pの引用に抵抗することはできません。 180:

このような急な坂を下る前に、常にそりに安全チェックをする必要があります。
正しい。
シートベルト ?無し。
信号?無し。
ブレーキ?無し。
ステアリング?無し。
WHEEEEEE

0
denis

アサーションを有効にするとパフォーマンスが明らかに影響を受けるコードを記述しました。たとえば、グラフィックコードによってタイトループで使用される数学関数の事前条件と事後条件を確認します(平方根関数は結果を二乗し、入力と比較します)。確かに、それは数パーセントのオーダーですが、私はそれらの数ポイントを必要とするコードを書きました。

さらに重要なことに、アサーションによってコードのサイズに数十パーセントの違いが生じるコードを作成しました。メモリフットプリントが問題になる場合、リリースコードでのアサートはおそらく許容できない贅沢です。

0
Steve Jessop

アサーションは、プログラマーがAPI /関数/クラス/その他を使用する方法でエラーを予測するために使用する必要があります。これらのバグは、デバッグ時に迅速に修正する必要があります。

それ以外の場合は、例外をスローします。

0
balajeerc

主に開発中のテストに使用します。たとえば、 これが私のutf-8ライブラリのスモークテストです ライブラリコードに変更を加えるたびにテストを実行し、バグが発生するとアサートがトリガーされます。もちろん、本格的な単体テストフレームワークを使用することもできますが、私の目的では、アサーションは問題ありません。

0

このようなことをするときはアサーションを使用する必要があります

a = set()
a.add('hello')
assert 'hello' in a

または

a = 1;
assert a == 1; // if ram corruption happened and flipped the bit, this is the time to assert

例外については、プログラムで処理するものです。

while True:
  try:
    data = open('sample.file').read()
    break // successfully read
  except IOError:
    // disk read fail from time to time.. so retry
    pass

ほとんどの場合、不可能なケースに対処したくないため、アサートが発生したときにアプリケーションを再起動する方が安全です。ただし、予期されるケースが発生した場合(予期されるエラー(ほとんどの場合、ブラックボックスクライアント、ネットワーク呼び出しなど))、例外を使用する必要があります。

0
vtlinh