console / stdoutへの出力は優れたデバッグ戦略ですか?


10

次のような関数があるとします。

public void myStart()
{
    for (int i = 0; i<10; i++) myFunction(i); 
}


private int myFunction(int a)
{

    a = foo(a);
    a = bar(a);
    return a; 
}

private int foo(int a)
{
    //do something here

    //something gnarly here

    //etc
    return aValue;
}

private int bar(int a)
{
    // do something here
    //return aValue;
}

なんらかの理由でコードが機能しなくなりました。おそらくそれはエラーをスローしている、おそらくそれは間違った値を返している、おそらくそれは無限ループで動かなくなっているでしょう。

最初の年のプログラマーは、最初にコンソール/標準出力に出力します(デバッガーの使用を学ぶ前にHello Worldを出力する方法を学びました)。

たとえば、このコードをデバッグするには、次のようにします。

private int myFunction(int a)
{
    print("before foo: a=" + a); 
    a = foo(a);
    print("before bar: a=" + a);
    a = bar(a);

    return a; 
}

private int foo(int a)
{
    //do something here
    print ("foo step1: a=" + a); 

    //something gnarly here
    print ("foo step2: a=" + a + " someOtherValue="+ someOtherValue + " array.length= " + someArray.length()); 
    //etc
    return aValue;
}

private int bar(int a)
{
    // do something here
    //return aValue;
}

コードを実行すると、大きなコンソール出力が表示され、問題が発生している場所を追跡できます。

もちろん、別の方法として、ブレークポイントを設定し、各ポイントでコードをステップ実行します。

コンソールに出力する主な利点の1つは、開発者がクリックなどの手順を踏むことなく、値の流れを一度に確認できることです。

しかし、不利な点は、コードがこれらのすべての印刷ステートメントで処理され、削除する必要があることです。

(おそらく、特定の値のみをログに出力するようにデバッガーに指示することは可能ですか?ブレークポイントは、実際にコードを変更せずに簡単に追加または削除できます。)

私はまだ主要なデバッグ方法としてコンソール印刷を使用していますが、これが他の何かと比較してどれほど一般的/効果的であるか疑問に思っています。


1
デバッガーの使用方法を学び、適切なロギングフレームワークを使用する必要があります。コンソールに出力するよりもずっと便利です(常に存在するわけではありません)。

7
デバッガーの使用方法を学ぶことは重要ですが、printfデバッグが利用可能な唯一のデバッグ方法である場合に遭遇する可能性のある多くの状況があります。
whatsisname 2014年

回答:


25

印刷ステートメントとデバッガーは相互に排他的ではありません。それらは、バグを見つけて特定するために利用できる、単なる異なるツールです。デバッガーに触れない方法を主張する人もいれば、作成したコードのどこにも単一のロギング/印刷ステートメントがない人もいます。私のアドバイスは、あなたはそれらのグループのどちらにも参加したくないということです。

代わりに、ロギングの使い方とデバッガの使い方を学びます。経験があれば、(ほとんどそれを考える必要はありませんが)適切なツールを選び、正確かつ効率的に仕事を終えることができます。経験がない場合は、どちらかを選択することもあり、変数を調べたり、ログファイルを調べたりするのに少し時間がかかる場合もありますが、それはすべて学習プロセスの一部です。

だから、あなたの特定の質問に答えるために。はい。印刷を使用して実行をトレースすることは、広く使用されている優れたデバッグ戦略です。しかしながら...

印刷ステートメントを使用する代わりに、ロギングフレームワークの使用を検討してください。ロギングフレームワークにはロギングレベルの概念があるため、ログメッセージの束全体を追加できますが、それぞれにレベルを選択できます。アプリケーションが通常の条件下で実行されている場合、レベルはERRORまたはWARNINGになるため、重要なものだけが報告されます。ただし、コードをトレースして実行フローを理解する必要がある場合は、ロガーをINFOまたはDEBUGに変更できます。これで、コード内に既にあるすべての「印刷」ステートメントが追加情報を報告します。

ロギングフレームワークの使用...

  1. 完了後、すべてのプリントを削除する必要はありません。
  2. あなたがコードに残したプリントは、あなたや他の開発者が将来同じコードをデバッグするのを助けることができます
  3. 削除したプリントを追加するために毎回コードを再構築する必要がなく、フィールドでこのコードをデバッグできます。
  4. ログメッセージは、コンソールだけでなく、どこにでもリダイレクトできます。彼らはファイル、syslog、DB、ソケットなどに行くことができます...

更新:私が最後に尋ねたところ、「おそらくデバッガに特定の値のみをログに出力するように指示することは可能ですか?」使用するデバッガーに応じて。最新のデバッガーの多くでは、ブレークポイントに達したときに呼び出すアクションを定義できます。一部では(VSとWinDbgでこれを実行しました)、「これを印刷して再開する」を指定することが可能です。Visual Studioは「ブレークポイント」ではなく「トレースポイント」と呼びます


最初の段落の+1。デバッガーとログは、2つの非常に異なる問題を解決します。
Blrfl 2014年

1
しかし、ログステートメントをコードに残しておくと、コードが見苦しくなります。
dwjohnston 2014年

1
残すログステートメントの種類によって異なります。「logger.error( "WHAT")」を見つけて削除しました。それ以外は、ロギングコードを他のコードと同じように扱います。それをフォーマットし、見栄えを良くし、有益なものにします。ええ、1行おきにprintステートメントを散りばめるのは少なすぎるので、それに頼らざるを得なかったことがあります。しかし、一般的に、ファイル全体に10〜20のログステートメントがあること(ファイル/クラスは適切なサイズであり、巨大ではない)はまったく問題ありません。
DXM 2014年

いくつかのログステートメントを残しておくと便利な場合があります。たとえば、運用システムがある場合、使用されているさまざまな重要な変数をログに記録したい場合があります。そのため、エラー発生した場合、運用で何が起こったかをすぐに確認できます。環境。ただし、開発のコンテキストでは、面倒なようです。たとえば、解析関数を作成していて、正規表現が正しくない場合-何が起こっているかを確認するために一連のログステートメントを入力し、最終的にそれを整理します。私はそれがそれらを残すために今後付加価値を考えていない。
dwjohnston

1
@Izkata:それはすべて、特定のバグの詳細と、コードがすでにログに記録している量に依存します。私が理解しようとしている点は、ロギングステートメントを持ち、それらをさまざまなレベルで持つことには常に価値があるということです。ERR-> WARN ...-> DEBUG。非常に具体的なものについてさらに必要な場合は、必ず印刷ステートメントを追加してください。しかし、ロギングステートメントとして「印刷」を使用する人への私の答えは、常にフレームワークに切り替えて、それを使い始めるでしょう。
DXM 2014年

3

ログ/印刷とデバッガーは、異なる長所と短所を持つ補完的な手法です。両方を使用するのが最善です。しかし全体として、ほとんどの場合、デバッガーが優れたツールであり、最初に使用する必要があります。ロギング/印刷は、実際に優れているものにのみ使用されます。

デバッガーの利点:

  • 事前に出力したい値だけでなく、プログラム全体の状態を調べることができます。これにより、フィードバックサイクルが1秒未満に短縮され、デバッグプロセスが大幅にスピードアップします。バグに到達するまでに時間がかかる場合は特に重要です。
  • 呼び出し元を確認したり、スタックトレースの値を調べたりすることもできます。
  • コンパイル済みのバイナリコードまたはバイトコードしかないため、簡単に変更できないコードをデバッグすることができます(ある程度、言語/プラットフォームに依存します)。

ロギング/印刷の利点:

  • 特別なデバッグビルドや構成は必要ありません。それは常に機能します。
  • 再現が難しく、まれにしか発生しないエラーの分析に使用できます
  • デバッガーによって引き起こされた一時停止がバグを簡単に消すことができるタイミング依存エラーを分析するために使用できます。
  • 自由に分析できる永続的な情報を提供します。プログラムフローの異なるポイントで、出力間を行き来することができます。

ロギングのもう1つの利点は、コードを通過する際に問題が発生したときにのみ問題が発生し、実際にそこに到達したときのバックトレースを使用できることです。ほとんどのデバッガーには[戻る]ボタンがありませんが、上位レベルの関数が呼び出されたときの値をログに記録すると機能し、少なくとも小さな再現可能なケースに近づくことがよくあります。
Christopher Creutzig 2014年

1

たとえば、ある方法で標準出力に出力することは、コードをデバッグするのに適した方法です。

  • 特にエラーを完全に理解していない場合、コードのさまざまなレベルで何が起こっているかを確認するために、多くの印刷ステートメントを使用します

  • または、エラーには、コードの正確にどの部分が問題を引き起こしているかを示す詳細情報が含まれていない可能性があります。

ただし、デバッグツールに慣れる必要があります。使用する言語やプラットフォームに応じてさまざまなものがあります。

また、別の方法はロギングです。Androidアプリケーションで作業するときは常にエラーをログに記録します。例外処理を使用すると、発生している例外のスタックトレースまたはエラーメッセージを簡単に記録できます。


3
この投稿は読みにくいです(テキストの壁)。より良い形に編集していただけませんか?
2014年

少し読みやすくしました。以前は申し訳ありません!
Plaix 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.