これらのメッセージは他の開発者向けです
これらのメッセージは、開発者がアプリケーションのデバッグを支援するために読むことが期待されています。これには2つの形式があります。
アクティブなデバッグ。あなたは実際にコードを書きながら、デバッガーを実行し、何が起こるかを理解しようとしています。これに関連して、役立つ例外は、何が問題なのかを簡単に理解できるようにするか、最終的に回避策を提案することでガイドします(これはオプションです)。
パッシブデバッグ。コードは実稼働環境で実行され、失敗します。例外はログに記録されますが、メッセージとスタックトレースのみを取得します。このコンテキストでは、有用な例外メッセージがバグを迅速に特定するのに役立ちます。
これらのメッセージはログに記録されることが多いため、機密情報(プライベートキーやパスワードなど、アプリのデバッグに役立つ場合でも)をそこに含めないでください。
たとえばIOSecurityException
、ファイルの書き込み時にスローされる例外のタイプは、問題についてあまり明確ではありません。ファイルにアクセスする権限がないためですか?それとも、私たちはそれを読むことはできますが、書くことはできませんか?または、ファイルが存在せず、そこにファイルを作成する権限がありませんか?または、ロックされている可能性があります(この場合、例外のタイプが異なることを願っていますが、実際にはタイプが不可解な場合もあります)。または、コードアクセスセキュリティにより、I / O操作を実行できない場合がありますか?
代わりに:
IOSecurityException:ファイルは見つかりましたが、その内容を読み取る権限が拒否されました。
より明示的です。ここでは、ディレクトリのアクセス許可が正しく設定されていることがすぐにわかります(そうでない場合、ファイルが存在することを知ることができません)が、ファイルレベルでのアクセス許可には問題があります。
これは、例外のタイプにない追加情報を提供できない場合、メッセージを空のままにできること も意味します。DivisionByZeroException
メッセージが冗長な良い例です。一方、ほとんどの言語でメッセージを指定せずに例外をスローできるという事実は、別の理由で行われます。デフォルトのメッセージがすでに利用可能であるか、必要に応じて後で生成されるためです(そして、この生成メッセージは例外タイプに囲まれています。例外タイプは、「OOPly」と言えば完全に意味があります。
技術的な(多くの場合パフォーマンス)理由で、一部のメッセージは本来よりもはるかに不可解であることに注意してください。.NETのNullReferenceException
:
オブジェクト参照がオブジェクトインスタンスに設定されていません。
役に立たないメッセージの優れた例です。役立つメッセージは次のとおりです。
でproduct
呼び出されproduct.Price
たときにオブジェクトのインスタンスに設定されていないオブジェクト参照。
これらのメッセージはエンドユーザー向けではありません!
エンドユーザーには例外メッセージは表示されません。決して。一部の開発者はこれらのメッセージをユーザーに表示しますが、これはユーザーエクスペリエンスの低下とフラストレーションにつながります。次のようなメッセージ:
オブジェクト参照がオブジェクトインスタンスに設定されていません。
エンドユーザーにとって絶対に何も意味しないので、どんな場合でも避けるべきです。
最悪のシナリオは、ユーザーに例外をスローしてアプリを終了するグローバルなtry / catchを持つことです。ユーザーを気にするアプリケーション:
そもそも例外を処理します。ほとんどのものは、ユーザーに影響を与えることなく処理できます。ネットワークがダウンしていますか?数秒待ってからもう一度試してみませんか?
ユーザーがアプリケーションを例外的なケースに導くことを防ぎます。ユーザーに2つの数字を入力し、最初の数字を2番目の数字で割るように頼んだ場合、数秒後に彼を責めるために、なぜユーザーに2番目の場合にゼロを入力させますか?テキストボックスを赤で強調表示し(数値がゼロ以外であることを伝える便利なツールヒントを使用)、フィールドが赤のままになるまで検証ボタンを無効にするとどうなりますか?
エラーではないフォームでアクションを実行するようにユーザーを招待します。ファイルにアクセスするための十分な権限がありませんか?ユーザーに管理権限を付与するように依頼するか、別のファイルを選択してください。
他に何も機能しない場合、ユーザーのフラストレーションを軽減し、何が間違っていたかを理解し、最終的に問題を解決し、将来的にエラーを防ぐのに役立つように特別に書かれた役立つフレンドリーなエラーを表示します(該当する場合)。
あなたの質問では、例外に2つのメッセージがあることを提案しました。1つは開発者向け、もう1つはエンドユーザー向けです。これはいくつかの小さなケースでは有効な提案ですが、ほとんどの例外は、ユーザーに意味のあるメッセージを生成することが不可能なレベルで生成されます。DivisionByZeroException
例外の発生を防ぐことができず、自分で処理できないと考えてください。分割が発生すると、フレームワークは(例外をスローするのはビジネスコードではなくフレームワークであるため)ユーザーにとって役立つメッセージとなるものを知っていますか?絶対違う:
ゼロによる除算が発生しました。[OK]
代わりに、例外をスローさせてから、ビジネスコンテキストを知っている上位レベルでそれをキャッチし、エンドユーザーを実際に支援するためにそれに応じて行動することができます。
フィールドD13は、フィールドE6の値と同じ値を持つことはできません。これらの値の減算が除数として使用されるためです。[OK]
または多分:
ATPサービスによって報告された値は、ローカルデータと矛盾しています。これは、ローカルデータが同期していないことが原因である可能性があります。配送情報を同期して再試行しますか?[はい・いいえ]
これらのメッセージは解析用ではありません
例外メッセージは、プログラムによって解析または使用されることも想定されていません。呼び出し元が追加情報を必要とする可能性があると思われる場合は、メッセージと一緒に例外に追加してください。メッセージは予告なく変更される場合があるため、これは重要です。タイプはインターフェースの一部ですが、メッセージはそうではありません。例外処理のためにタイプに依存しないでください。
例外メッセージを想像してください:
500ミリ秒待機した後、キャッシュサーバーへの接続がタイムアウトしました。タイムアウトを増やすか、パフォーマンス監視を確認して、サーバーのパフォーマンスの低下を特定します。キャッシュサーバーの平均待機時間は6ミリ秒でした。先月は4ミリ秒。先週と377ミリ秒。最後の1時間。
「500」、「6」、「4」、「377」の値を抽出します。解析を行うために使用するアプローチについて少し考えてから、読み続けてください。
アイデアはありますか?すばらしいです。
今、元の開発者はタイプミスを発見しました:
Connecting to the caching sever timed out after waiting [...]
する必要があります:
↓
Connecting to the caching server timed out after waiting [...]
さらに、開発者は月/週/ 1時間は特に関係ないと考えているため、追加の変更も行います。
キャッシュサーバーの平均待機時間は6ミリ秒でした。先月は5ミリ秒。過去24時間と377ミリ秒。最後の1時間。
構文解析ではどうなりますか?
解析する代わりに、例外プロパティ(データをシリアル化できるとすぐに、必要なものを含めることができます)を使用できます。
{
message: "Connecting to the caching [...]",
properties: {
"timeout": 500,
"statistics": [
{ "timespan": 1, "unit": "month", "average-timeout": 6 },
{ "timespan": 7, "unit": "day", "average-timeout": 4 },
{ "timespan": 1, "unit": "hour", "average-timeout": 377 },
]
}
}
現在、このデータを使用するのは簡単ですか?
時には(.NET内など)、メッセージをユーザーの言語に翻訳することさえできます(開発者はすべて英語で読むことができるため、IMHO、これらのメッセージの翻訳は完全に間違っています)。このようなメッセージの解析はほぼ不可能です。