質問

データ アクセス層の奥深く、またはさらに上位 (たとえば、ADO.net 操作内など) で発生したエラーがエンド ユーザーにとって意味のあるものであることはほとんどありません。これらのエラーを単純に UI に表示して表示するだけでは、通常、エンド ユーザーはイライラするだけです。

私は最近、このようなエラーを報告するための基本的な手法を採用しました。これにより、エラーをキャッチし、少なくともエンドユーザーが何が失敗したかを理解できるように、少なくともユーザーフレンドリーなテキストを追加します。

これを行うために、各特定の関数 (たとえば、データ アクセス レイヤーのフェッチ関数) 内で例外をキャッチし、失敗しておそらく原因となった関数に関するユーザー フレンドリーなテキストを含む新しいエラーを発生させますが、その後、元のエラーを埋め込みます。新しい例外の「内部例外」として例外を追加します。

これは、必要に応じて各層で発生し、下位レベルの関数の各コンシューマーが独自のコンテキストをエラー メッセージに追加するため、UI に届くエラー メッセージはますますユーザー フレンドリーになります。

エラーが UI に到達すると (必要に応じて)、ネストされた例外を反復処理して、最初にどの操作が失敗したかをユーザーに伝えるエラー メッセージを表示しますが、実際に何が問題だったのかについての技術的な情報も提供します。

例えば

「要求された顧客名のリストを表示できませんでした。」

「要求した顧客のリストを取得することは、データベースのエラーのために失敗しました。」

「顧客のリストを取得するときにデータベースに接続するエラーがありました」

「ユーザーxxのログインに失敗しました」

私の質問は次のとおりです。これはひどく非効率的ですか (入れ子になったすべての例外)?これはベストプラクティスではないと思われるので、同じことを達成するには何をすべきでしょうか? それとも実際には、より良いものを達成しようと努めるべきでしょうか?

役に立ちましたか?

解決

それはほんの少し恐ろしいことです。

エンドユーザーにエラーを表示している場合、ユーザーはそれに対して対処できるはずです。「要求された顧客名のリストは表示できませんでした。」ケース、ユーザーは「なんて?」と思うだけだと思う​​でしょう。これらのすべてのケースでは、「何か悪いことが起こった」メッセージを表示するだけです。これらの例外をキャッチする必要さえありません。何か問題が発生した場合は、何らかのグローバル メソッド (application_error など) でそれを処理し、一般的なメッセージを表示させます。あなたまたはあなたのユーザーがエラーに対して何かできる場合は、エラーを捕らえて対処するか、ユーザーに通知してください。

ただし、処理できないエラーはすべてログに記録する必要があります。

ちなみに、発生したエラーに関する情報を表示すると、セキュリティ上の脆弱性が発生する可能性があります。攻撃者があなたのシステムについて知らないほど、システムをハッキングする方法を見つける可能性は低くなります(「SQL ステートメントの構文エラー:」のようなメッセージを思い出してください。* From Users Where username='a'; を選択します。drp データベース;--'..." が期待されます:「drp」ではなく「drop」です。彼らはもうこのようなサイトを作成しません)。

他のヒント

新しい例外をスローするのは技術的にコストがかかりますが、「コストがかかる」というのは相対的なものであるため、これについては大きな議論はしません。そのような例外を 1 分間に 100 個スローしている場合、コストはおそらくわかりません。このような例外を 1 秒あたり 1000 個スローしている場合、パフォーマンスが低下する可能性が非常に高いです (したがって、ここで議論する価値はあまりありません。パフォーマンスはあなたの要求です)。

なぜこのアプローチが使用されるのかを尋ねる必要があると思います。意味のある例外情報を追加できるというのは本当ですか? 例外がスローされる可能性があるレベル、およびスローされる場合、情報は次のようになりますか?

  • 実際にあなたが何か 欲しい ユーザーと共有するには?
  • ユーザーが解釈、理解、理解できるもの 使用?
  • 作成された時点ではその有用性が知られていなかった可能性がある低レベルのコンポーネントの後での再利用を妨げないような方法で書かれていますか?

ユーザーとの情報共有について質問するのは、あなたの例では、人工スタックがデータベースでの認証に問題があったことをユーザーに通知することから始まるからです。潜在的なハッカーにとって、これは作戦の内容を明らかにする良い情報となります。

カスタム例外スタック全体を返すことに関しては、ほとんどの (正直な) ユーザーにとって役立つものではないと思います。たとえば、顧客名のリストを取得するのに問題がある場合、データベースの認証に問題があったことを (ユーザーとして) 知るのに役立ちますか?統合認証を使用していて、各ユーザーがアカウントを持っていて、システム管理者に連絡してアカウントに権限がない理由を確認できる場合を除き、おそらくそうではありません。

まず、スローされたフレームワーク例外と、ユーザーに提供したい例外メッセージの間に意味上の違いがあるかどうかを判断することから始めます。存在する場合は、最下位レベルでカスタム例外 (この例では「ログインに失敗しました」) を使用してください。その後の手順では、実際に例外が表示されるまで、実際にはカスタム例外は必要ありません。関心のある例外はすでに生成されています (ログインは失敗しました)。コール スタックのすべてのレベルでそのメッセージをラップし続けることは、コール スタックをユーザーに公開すること以外の本当の目的はありません。これらの「中間」ステップでは、try/catch ブロックが適切に配置されていると仮定すると、単純な「log and throw」戦略が適切に機能します。

しかし実際には、この戦略には別の潜在的な欠陥があります。開発者には、実装されたカスタム例外標準を維持する責任が課せられます。低レベルの型を作成するときに呼び出し階層のすべての順列を知ることはおそらく不可能なので (その「クライアント」はまだ作成されていない可能性もあります)、すべての開発者 (または 1 人の開発者でさえ) がラップしてカスタマイズすることを覚えている可能性は低いと思われます。すべてのコード ブロックのエラー状態。

私は、ボトムアップで作業するのではなく、通常、プロセスのできるだけ遅い段階で、スローされた例外の表示を心配します (つまり、可能な限り呼び出しスタックの「先頭」に近いもの)。通常、私はアプリケーションの低レベルでスローされた例外内のメッセージを置き換えようとはしません。特に、これらの低レベルのメンバーの使用法は、呼び出しが深くなるほど抽象的になる傾向があるためです。私は、ビジネス層以下で例外を捕捉して記録し、プレゼンテーション層でわかりやすい方法で例外を表示することに対処する傾向があります。

例外処理のベスト プラクティスに関する適切な記事をいくつか紹介します。

http://www.codeproject.com/KB/architecture/Exceptionbestpractices.aspx

http://aspalliance.com/1119

うーん、冗長になってしまいました…あらかじめお詫びを申し上げます。

はい、例外にはコストがかかるため、キャッチして再スローしたり、より有用な例外をスローしたりするにはコストがかかります。

でも、ちょっと待ってください!使用しているフレームワーク コードまたはライブラリが例外をスローした場合、事態はすでに解決されつつあります。例外の後にエラー メッセージがどのくらい早く伝達されるかについて、機能以外の要件はありますか?私はそれを疑う。それは本当に大したことですか?予期せぬ「例外的」なことが起こりました。重要なのは、賢明で役立つ情報をユーザーに提供することです。

あなたがやっていることは正しい方向に進んでいると思います。

もちろんそれは恐ろしく非効率です。ただし、エンド ユーザーに表示するのに十分なほど重要な例外が発生した時点では、それを気にする必要はありません。

私が働いている場所では、例外をキャッチする理由がいくつかあります。私たちがそれを行うのは次の場合だけです...

  1. 私たちはそれについて何かをすることができます - たとえば、これが時々起こる可能性があることを知っており、それが起こったときにコードで修正できます(非常にまれですが)。

  2. それがどこで発生したかを知りたいのです (その後、例外を再スローするだけです)。

  3. わかりやすいメッセージを追加したい場合は、元の例外をアプリケーション例外から派生した新しい例外でラップし、それにわかりやすいメッセージを追加して、その時点から変更せずにバブルアップさせます。

あなたの例では、おそらく「ログオンエラーが発生した」を表示するだけでしょう。 ANBDは、実際のエラーを記録し、ユーザーが必要に応じて例外にドリルする理由を提供しながら、そのままにしておきます。(おそらくエラー フォーム上のボタン)。

  1. 例外を完全に抑制して続行したいと考えています。言うまでもなく、これは予期される例外タイプに対してのみ、また例外を生成する条件を検出する他に方法がない場合にのみ実行されます。

一般に、例外に対処する場合、パフォーマンスと効率はほとんど心配しません。ユーザーが問題から回復できるように何かを行うことをもっと心配する必要があります。特定のレコードをデータベースに書き込むときに問題が発生した場合は、変更をロールバックするか、少なくとも行情報をダンプして、ユーザーが行情報を失わないようにしてください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top