Microsoft例外処理ブロック-オーバーエンジニアリングの完璧な例ではありませんか?
-
03-07-2019 - |
質問
Microsoftがアプリケーションブロックを導入して以来、例外処理アプリケーションブロック。私は最近自分自身をよく見て、次のように基本的な機能を要約します(もしそれが何をするのか既に知っているなら次のブロックを飛ばしてください):
例外処理アプリケーションブロックは、次の主要な例外処理タスク:
- 例外の記録
- 例外の置換
- 例外のラッピング
- 例外の伝播
- など
ライブラリは、try catchブロックを次のように変更することでそれを行います。
try { // Run code. } catch(DataAccessException ex) { bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy"); if (rethrow) { throw; } }
ポリシー名のapp.configでの指定に基づいて(参照ドキュメントの場合はこちら)、HandleExceptionは...
- 完全に新しい例外をスローします(元の例外を置き換えます)
- 元の例外を新しいものにラップしてスローする
- 例外を飲み込む(つまり、何もしない)
- 元の例外を再スローします
さらに、事前に他の処理を実行するように構成することもできます(たとえば、例外をログに記録します)。
ここに私の問題があります:例外を置き換える、ラップする、飲み込む、または再スローするかどうかを設定可能にすることのメリットを完全に理解できません。私の経験では、例外処理の振る舞いを変更する場合、通常は周囲のコードまたは呼び出しコードを変更する必要があるため、この決定はコードの作成時に行う必要があります。
たとえば、特定のポイントでスローされた特定の例外を再スローするのではなく飲み込むように再構成すると、コードが正しく動作しなくなる可能性があります(例外が発生したときに実行してはいけないcatchブロックの後にコードがある場合があります発生します)。例外処理で考えられる他のすべての変更についても同様です(たとえば、replace-> rethrow、swallow-> wrap)。
つまり、私にとって一番重要なのは、例外処理ブロックが実際には存在しない問題を解決するということです。例外のログと通知のビットは問題ありませんが、他のすべてのものはオーバーエンジニアリングの完璧な例ではありませんか?
解決
制御フローに例外を使用する場合は、ポリシーベースの例外処理を避けてください。
ただし、回復不能として処理する例外(バックグラウンドタスクの失敗、ソケットの切断、ファイルの削除など)の場合は、設定可能なポリシーベースの例外処理が必要になる場合があります。
たとえば、APIを開発している場合、API内のすべての関数に標準の例外( ArgumentException
など)と独自のライブラリ固有の例外のみをスローさせることができます。内部の非標準例外の場合の例外( MyLibraryException
など)。このタイプの場合、重要なことは、何かが正しく機能しなかったことです。あなたは例外を分解して、何が悪いのかを理解していません。 何か何かがうまくいかなかったという事実と、今何かをすることになっているという事実を単に認めているだけです。
その一部の構成は、実際に何をするかは重要ではないため、構成可能でなければなりません。ユーザーにメッセージボックスを表示しますか?モーダルまたは非モーダル?例外を記録しますか?例外をどのように記録しますか?ロギングWebサービスを呼び出しますか?ログファイルに追加しますか? Windowsイベントログに書き込みますか?データベースにエントリを挿入しますか? 2つのデータベースにエントリを挿入しますか?アプリケーションの残りの部分にとっては、実際には問題ではありません。例外の処理方法の選択は、アプリケーションの他の部分と完全に直交しています。
(余談ですが、これは設定可能なポリシーベースの例外処理にアプローチする方法ではありません。例外ロガーインターセプターをコンテナーに登録するなど、AOPスタイルをより重視します。)
他のヒント
回復可能な状態を持たない関数を開発しているときに、この問題が発生します。このポリシー駆動の例外処理は実際に有用であり、このプロジェクトに参加している他のすべての開発者が実際に回復不能な例外の標準に準拠していると確信しています。
上記のポスターに同意します。制御フローにそれらを使用している場合、ポリシーベースの例外を避けたい場合があります。
「例外処理ブロックは、実際には存在しない問題を解決する」という声明に同意する必要があります。リリース以来ブロックを使用しましたが、実際に使用して多くを得ていると感じることはめったにありません。まあ、おそらく頭痛の種。 :)
開始する前に、 WCFでの例外シールドが好きであることを認めますサービス境界機能。ただし、それはごく最近追加されたものであり、コーディングは不要です。属性と構成のみであり、ブロックの通常の販売方法ではありません。これは、Microsoftが http://msdn.microsoft.com/enで表示する方法です。 -us / library / cc309250.aspx
私の目には、上記はフロー制御です。
try
{
// Run code.
}
catch(DataAccessException ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy");
if (rethrow)
{
throw;
}
}
フロー制御の側面と上記のコードを組み合わせると、間違いなく間違ったコードに見える間違っている。 (if(再スロー)コンストラクトがあまり抽象化を提供しないことに注意してください。)これにより、ポリシー定義に不慣れな開発者にとって保守がより困難になる可能性があります。構成ファイルの postHandlingAction
が変更された場合(ある時点で発生する可能性があります)、おそらくテストされていない予期しない方法でアプリケーションが動作していることがわかります。
おそらく、ブロックがフロー制御を処理せず、単にハンドラーを連鎖させることができれば、好ましくないとは思わないでしょう。
しかし、おそらくそうではありません。私は実際にこれまでに頼まれたことを思い出しません:
- 例外を処理するときに新しい機能を追加します(たとえば、イベントログへのログ記録に加えて、電子メールも送信します。実際に、既に自分で例外を記録している場合、ログブロックはそれを単独で実行できます。) )
- " policy"全体で例外処理の動作(飲み込み、再スロー、または新規スロー)を変更します。
それが起こらないと言っているわけではありません(誰かが物語を持っていると確信しています!);例外処理アプリケーションブロックは、プログラムの理解と保守を難しくし、通常はブロックが提供する機能よりも重要だと感じています。
これがエンジニアリングを超えているとは思わない。実際には。例外が中央ハンドラーを通過できるという事実は、私の仕事の中で良いことです。私はすべての例外を食べる開発者がいました-それがトップにバブルしてエンドユーザーの前に警告するものを置かないように、またはキャッチされないときに真剣にサービス/デーモンを台無しにしないように処理しました。
ポリシーを使用すると、再起動することなく、またはアプリ全体に不必要にログロジックを振りかけることなく、いつでもログを開始できます。アプリをオフラインにせずに例外などを監視できるようになりました。
私に聞いたらスマートプログラミング...
簡単に言うと、リリースコードとデバッグコードで異なる例外処理が必要な場合に便利です。
私の意見では、Exception Handlingブロックを使用することの本当の価値の1つは、catchブロックの1行のコードから始まります。
bool rethrow = ExceptionPolicy.HandleException(ex、" Data Access Policy");
1行のコード-どのくらい簡単に取得できますか? 1行のコードの背後で、設定されたポリシーにより、ソースコードを再コンパイルすることなく、ポリシーへの割り当て/更新が簡単に実行されます。
前述のように、例外ポリシーは実際に多くのアクションを実行できます-ポリシーで定義されているものは何でも。 catchブロック内に示されているように、1行のコードの背後に複雑さを隠すことで、本当の価値が見られます。
私は複雑だと言いますが、過剰に設計されていません。したがって、設定を簡単に変更できる柔軟性と、同じソースコードの1行を保持することで、例外の処理/ロギングの方法を変更する必要がある場合、メンテナンス中に大きな配当が見られると思います。