あなたの同僚は「防御的プログラミング」や例外を誤解しているようです。
防御的プログラミング
防御的プログラミングとは、特定の種類のエラーから保護することです。
この場合x.parent == null
、メソッドは を使用する必要があるため、エラーになりますx.parent.SomeField
。parent
null の場合、 の値はSomeField
明らかに無効になります。無効な値を使用して計算またはタスクを実行すると、誤った予測不可能な結果が生じる可能性があります。
したがって、この可能性から保護する必要があります。NullPointerException
保護するための非常に良い方法は、 を発見した場合に を投げることx.parent == null
です。この例外により、 から無効な値を取得できなくなりますSomeField
。無効な値を使用して計算を行ったり、タスクを実行したりすることはできません。そして、エラーが適切に解決されるまで、現在のすべての作業を中止します。
例外はエラーではないことに注意してください。無効な値parent
は実際のエラーです。例外は、実際には保護メカニズムです。例外は防御的なプログラミング手法であり、避けるべきものではありません。
C# は既に例外をスローしているため、実際には何もする必要はありません。実際、「防御的プログラミングの名の下に」あなたの同僚の努力は、言語によって提供される組み込みの防御的プログラミングを実際に元に戻しています。
例外
多くのプログラマーが例外について過度に偏執的であることに気付きました。例外自体はエラーではなく、単にエラーを報告するだけです。
あなたの同僚は、「null チェックは、コードがアプリケーションを壊さないことを確認します」と言います。これは、例外がアプリケーションを壊すと彼が信じていることを示唆しています。通常、アプリケーション全体を「壊す」ことはありません。
例外処理が不十分なためにアプリケーションが一貫性のない状態になると、例外によってアプリケーションが破損する可能性があります。(ただし、エラーが隠されている場合、これはさらに可能性が高くなります。) また、例外がスレッドを「エスケープ」すると、アプリケーションが壊れる可能性があります。(メイン スレッドをエスケープするということは、明らかに、プログラムがかなり不当に終了したことを意味します。しかし、子スレッドをエスケープすることでさえ十分に悪いため、オペレーティング システムにとって最適なオプションはアプリケーションを GPF することです。)
ただし、例外は現在の操作を中断 (中止) します。そして、これは彼らがしなければならないことです。と呼ばれるメソッドをコーディングすると、DoSomething
which が呼び出されるためですDoStep1
。のエラーは、その仕事を適切に行うことができないことをDoStep1
意味します。に電話しても意味がありません。DoSomething
DoStep2
ただし、ある時点で特定のエラーを完全に解決できる場合は、必ずそうしてください。ただし、「完全に解決する」ことに重点が置かれていることに注意してください。これは単にエラーを隠すという意味ではありません。また、エラーをログに記録するだけでは、通常、エラーを解決するには不十分です。これは、別のメソッドがメソッドを呼び出して正しく使用した場合、「解決されたエラー」が呼び出し元のジョブを適切に実行する能力に悪影響を及ぼさないという点に到達することを意味します。(発信者が何であっても。)
おそらく、エラーを完全に解決する最も良い例は、アプリケーションのメイン処理ループにあります。その仕事は、キュー内のメッセージを待ち、次のメッセージをキューから取り出し、適切なコードを呼び出してメッセージを処理することです。例外が発生し、メイン メッセージ ループに戻る前に解決されなかった場合は、解決する必要があります。そうしないと、例外がメイン スレッドをエスケープし、アプリケーションが終了します。
多くの言語は、標準フレームワークでデフォルトの例外ハンドラー (プログラマーがオーバーライド/インターセプトするメカニズムを備えたもの) を提供します。デフォルトのハンドラーは通常、ユーザーにエラー メッセージを表示し、例外を飲み込みます。
なんで?貧弱な例外処理を実装していなければ、プログラムは一貫した状態になります。現在のメッセージは中止され、次のメッセージは何も問題がなかったかのように処理できます。もちろん、このハンドラーを次のようにオーバーライドできます。
- ログファイルに書き込みます。
- トラブルシューティングのためにコール スタック情報を送信します。
- 特定のクラスの例外を無視します。(たとえば
Abort
、おそらく以前にメッセージを表示したため、ユーザーに伝える必要さえないことを暗示している可能性があります。)
- 等
例外処理
最初に例外を発生させずにエラーを解決できる場合は、そうする方がクリーンです。ただし、エラーが最初に表示された時点で解決できない場合や、事前に検出できない場合があります。このような場合、エラーを報告するために例外を発生またはスローする必要があり、例外ハンドラー ( C# のcatchブロック) を実装して解決します。
注: 例外ハンドラー サーバーには 2 つの異なる目的があります。まず、エラー/例外が発生したため、特にクリーンアップ (またはロールバック コード)を実行する場所を提供します。次に、エラーを解決して例外を飲み込む場所を提供します。注意: 前者のケースでは、例外が解決されていないため、例外が再発生/スローされることが非常に重要です。
例外をスローして処理することについてのコメントで、あなたは次のように述べています。
これは別の誤解です。前の補足事項によると、次の場合にのみ例外処理が必要です。
- エラーを解決できます。その場合は完了です。
- または、ロールバック コードを実装する必要がある場所。
この懸念は、原因と結果の分析の欠陥によるものかもしれません。例外をスローしているという理由だけで、ロールバック コードは必要ありません。例外がスローされる理由は他にもたくさんあります。エラーが発生した場合、メソッドはクリーンアップを実行する必要があるため、ロールバック コードが必要です。つまり、いずれにしても例外処理コードが必要になります。これは、過剰な例外処理に対する最善の防御策は、エラーのクリーンアップの必要性を減らすように設計することであることを示唆しています。
したがって、過剰な例外処理を避けるために、「例外をスローしない」ことは避けてください。過剰な例外処理は良くないことに同意します (上記の設計上の考慮事項を参照してください)。しかし、エラーがあったことさえ知らなかったために、ロールバックすべきときにロールバックしないのは、はるかに悪いことです。