web-dev-qa-db-ja.com

「ログアンドスロー」がアンチパターンと見なされるのはなぜですか?

この質問は この記事 に関する議論によって引き起こされました。

例外をログに記録してから再スローする(もちろん元のスタックトレースを保持する)のは、他の方法で処理できない場合は悪い考えですか?

70
Manu

私は答えが主にそれを扱うことができないのになぜそれをつかまえるのであると思いますか?誰がそれを処理できるのか(または、それを処理する以外に選択の余地がない人)に、ログに値するものであると感じたら、それをログに記録してみませんか?

キャッチしてログを記録し、再スローする場合、アップストリームコードが既に例外を記録したことを知る方法がないため、同じ例外が2回記録される可能性があります。さらに悪いことに、すべてのアップストリームコードがこの同じパターンに従っている場合、例外を任意の回数ログに記録することがあります。これは、キャッチしてログに記録してから再度スローすることを決定するコードのレベルごとに1回です。

また、例外のスローとキャッチは比較的コストのかかる操作であるため、このすべてのキャッチと再スローはランタイムのパフォーマンスを向上させないと主張する人もいます。また、簡潔さや保守性の面でコードを支援することもありません。

94
aroth

ログアンドスローは、例外をキャッチして再スローするエンティティが、少なくとも最も望ましい方法ではなく、コールスタックに記録されない情報が含まれていると考える理由がある場合に適したパターンです。これが発生する可能性のあるいくつかの理由:

  1. 例外は、アプリケーション層の境界でキャッチおよびスローされ、特権情報が含まれる場合があります。データベース層が例外を許可するのは悪いでしょう。 「フィールド 'users'に重複キー 'fnord'を追加しようとすると、外側のアプリケーション層に到達します(これにより、ユーザーに公開される可能性があります)。それをキャッチし、安全にログに記録し、やや記述的でない例外を再スローするアプリケーションインターフェイス。
  2. 例外は、外部層がロギングなしで処理する可能性が高い例外かもしれませんが、内部層はロギングが有用であるかもしれないことを示唆する外部層が知らない何かを知っているかもしれません。おおまかな例として、1つのサーバーへの接続を試行し、それが機能しない場合は別のサーバーへの接続を試行するように中間アプリケーション層をプログラムすることができます。サーバーがメンテナンスのためにダウンしているときに、アプリケーションのログに「接続失敗」メッセージを大量に送信することは、特にアプリケーションの観点からはすべて正常に機能するため、役に立たない場合があります。接続の失敗に関する情報をサーバーに関連付けられたロギングリソースに転送すると、すべての接続試行のログとは対照的に、サーバーが上下したときのレポートを生成するためにログをフィルタリングできます。 。
43
supercat

最も簡単な理由は、通常、これを行う単一のトップレベルハンドラーがあるため、この例外処理でコードを汚染する必要がないためだと思います。

横断的関心事の議論は、基本的に、あなたに関係のないエラーを処理する時間の無駄だということです。適切なハンドラーが見つかるまで、エラーが呼び出しスタックをバブルアップさせる方がはるかに良いです。

私の意見では、例外をキャッチする必要があるのは、結果に対して何か役に立つことができるときだけです。単にログに記録するだけでは役に立ちません。これは、作業をさらに集中化できるためです。

16
Jeff Foster

IMOのログとスローは、最小サプライズの原則に対する明らかな違反です。

例外がコールスタックのさらに上で適切に処理される場合、エラーログエントリの価値はまったくない可能性があります。そして、エラーログエントリを見つけるのは混乱を招きます。

7
Bastian Voigt