Exception.Messageを読むべき人はいますか?


27

例外を設計するとき、ユーザーまたは開発者が理解する必要があるメッセージを作成する必要がありますか?実際に例外メッセージの読者はだれですか?

例外メッセージはまったく役に立たないと思うし、いつも書くのに苦労しています。慣例により、例外のタイプは既に何かが機能しなかった理由と、カスタムプロパティがファイル名、インデックス、キーなどの情報をさらに追加する理由を既に示しているはずです。自動生成されたメッセージでも実行でき、含まれる必要があるのは、追加のプロパティのリストを含む例外の名前だけです。これは、手書きのテキストとまったく同じように便利です。

メッセージをまったく書き込まずに、コードでハードコーディングするのではなく、おそらく異なる言語で意味のあるメッセージを作成する特別な例外レンダラーを用意する方が良いと思いませんか?


これらの質問のいずれかが私の質問に対する答えを提供するかどうか尋ねられました:

私は両方を読みましたが、彼らの答えに満足していませんでした。彼らは一般的にユーザーについて話し、宛先ではなくメッセージ自体の内容に焦点を当て、エンドユーザーと開発者の少なくとも2人が存在することがわかりました。例外メッセージを書くとき、私はどちらに話すべきかわかりません。

有名なメッセージは、例外タイプの名前を異なる単語で繰り返しているだけなので、実際の価値はまったくないと思います。完全に自動生成できます。

私にとって例外メッセージは、読者の差別化に欠けています。完璧なエンドユーザー用と開発者のための1:例外は、メッセージの少なくとも2つのバージョンを提供する必要があります。単なるメッセージと呼ぶのは一般的すぎます。その後、開発者のメッセージは英語で記述する必要がありますが、エンドユーザーのメッセージは他の言語に翻訳する必要がある場合があります。このすべてを1つのメッセージだけで実現することは不可能であるため、例外は、先ほど述べたように、さまざまな言語で利用できるエンドユーザーメッセージに識別子を提供する必要があります。

リンクされている他のすべての質問を読むと、例外メッセージは実際には開発者ではなくエンドユーザーが読むことを意図しているという印象を受けます... 1つのメッセージはケーキを食べて食べるようなものです。


4
ここで思い浮かぶプログラマーについて、他に2つの質問があります。彼らは重複されているかどうか、私にはわからないんだけど、私はあなたがそれらを読んでください、おそらく彼らはあなたの懸念の一部あるいはすべてを解決すると思う:良い例外メッセージを書くためにどのようにして、なぜ多くの例外メッセージが役立つ詳細情報が含まれていません?
トーマスオーエンズ

2
@ThomasOwens私は両方を読みましたが、例外メッセージの特定の受信者には対応していません。彼らは一般的にユーザーについて話しますが、彼は誰ですか?問題の原因を分析する必要があるのは、プログラミングや開発者について現在考えているソフトウェアのユーザーですか?メッセージを書くときに誰に対処すればよいかわかりません。
t3chb0t

2
ここでの良い答えは、これらの質問のいずれかまたは両方に言及していると思いますが、それらは重複とはほど遠いものです。
モニカとの軽さのレース

1
いったいなぜこれが複製として閉じられたのか?それが他の質問(そうではない)の複製であったとしても、この質問の方が明らかに良い答えを持っているので、重複としてマークされているのは他の質問であるべきです。
ベンアーロンソン

2
あなたはその例外のメッセージがユーザーのためにしている前提としない限り、私はまだ本当に多くの重複が表示されていない@MichaelT
ベン・アーロンソン

回答:


46

これらのメッセージは他の開発者向けです

これらのメッセージは、開発者がアプリケーションのデバッグを支援するために読むこと期待されています。これには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、これらのメッセージの翻訳は完全に間違っています)。このようなメッセージの解析はほぼ不可能です。


2
エンドユーザーについての良い点。また、セキュリティ上の理由から、エンドユーザーには例外メッセージが表示されないようにする必要があります。エラーの正確な性質を非素人ユーザーに知っていると、悪用される可能性があります。エンドユーザーは、自分が何をしていたのかというコンテキストでのみエラーを知る必要があります。
ニール

1
@ニール:それは少し理論的すぎる。実際には、ユーザーからログを隠すことの利点は、オンラインロギングの複雑さよりも重要です。ユーザーフレンドリーな側面を数えていません。新しいWindows VMにVisual Studioをインストールするとします。突然、インストールが失敗します。ログにアクセスして自分で(Stack Exchangeとブログの助けを借りて)問題を診断するか、Microsoftが問題を解決してホットフィックスを公開するまで待ちますか?
Arseni Mourzenko

4
「オブジェクト参照...」というメッセージが役に立たないことは誰もが知っていると思います。ただし、関連する質問は、必要なメッセージを生成するジッターを生成するマシンコードを指定することです。 この演習を行うと、すべての例外的でないケースに多大なパフォーマンスコストがかかることなく、メッセージを簡単に生成できないことがすぐにわかります。不注意な開発者の仕事を非常にわずかに簡単にする利点は、エンドユーザーへのパフォーマンスヒットによって支払われません。
エリックリッパー

7
セキュリティ例外について:例外の情報が少ないほど良い。私のお気に入りの逸話は、.NET 1.0のベータ版以前では、「ファイルC:\ foo.txtの名前を特定する権限がありません」のような例外メッセージが表示される可能性があることです。すばらしい例外メッセージをありがとう!
エリックリッパー

2
エンドユーザーに詳細なエラーメッセージを表示しないことに同意しません。私に起こった多くの私は私のゲーム/ソフトウェアを起動してから私を防止不可解なエラーメッセージが出た回数を、私はそれをグーグルとき、私は簡単な回避策があります見つけます。そのエラーメッセージがなければ、回避策を見つける方法はありません。「詳細」ボタンの下にある詳細を非表示にした方がいいかもしれません。
BlueRaja-ダニーPflughoeft

2

これに対する答えは例外に完全に依存します。

尋ねる最も重要な質問は、「誰が問題を解決できるか」です。ファイルを開いているときにファイルシステムエラーが原因で例外が発生する場合は、そのメッセージをエンドユーザーに提供するのが合理的です。メッセージには、エラーの修正方法に関する詳細が含まれている場合があります。私は、DLLをロードするプラグインシステムを持っていた私の仕事の1つの決定的なケースを考えることができます。ユーザーがコマンドラインでタイプミスをして間違ったプラグインをロードした場合、基になるシステムエラーメッセージには実際に問題を修正するための有用な情報が含まれていました。

ただし、ほとんどの場合、キャッチされていない例外はユーザーが修正できません。それらのほとんどは、コードの変更を伴います。これらの場合、メッセージの消費者は明らかに開発者です。

例外を適切に処理し、よりわかりやすい例外をスローする機会があるため、キャッチされた例外のケースはより複雑です。私が書いたスクリプト言語の1つは例外をスローしましたが、そのメッセージは開発者向けのメッセージでした。しかし、スタックが解けると、スクリプト言語内からユーザーが読み取り可能なスタックトレースを追加しました。私のユーザーはめったにメッセージを理解できませんでしたが、スクリプトのスタックトレースを見て、95%の時間で何が起こったかを把握することができました。残りの5%については、彼らが私に電話をかけたとき、スタックトレースだけでなく、何が間違っているのかを把握するのに役立つ開発者向けのメッセージがありました。

全体として、例外メッセージを未知のコンテンツとして扱います。実装についてさらに詳しい上流の誰かが、私のソフトウェアに例外を与えました。時々、エンドユーザーにとって未知のコンテンツが役立つと思うこともありますが、そうでないこともあります。


1
「ファイルを開いているときにファイルシステムエラーが原因で例外が発生した場合、そのメッセージをエンドユーザーに提供するのが理にかなっている場合があります」:ただし、ファイルシステムエラーをスローした場合、コンテキストはわかりません:ユーザーのアクションか、まったく関係のないもの(ユーザーが気付かないうちにアプリが何らかの構成のバックアップを作成するなど)の可能性があります。これは、エラーメッセージを表示するtry / catchブロックがあることを意味します。これは、例外メッセージを直接表示することとは大きく異なります
アルセニムルゼンコ

@MainMaコンテキストを明示的に知っていないかもしれませんが、たくさんのヒントがあります。たとえば、ファイルを開いている最中に例外が「IOError:permission denied」である場合、ユーザーが2と2を組み合わせて問題のファイルを見つけ出す合理的な可能性があります。私のお気に入りのエディターはこれを行います-例外テキストをダイアログボックスに出力するだけで、毛羽立ちはありません。一方、アプリケーションをロードしていて、大量のイメージをロードしているときに「許可が拒否された」場合、ユーザーが情報を使用して何かを実行できると想定するのはあまり合理的ではありません。
コートアンモン-復帰モニカ

あなたの主張を主張して、私はユーザーにNullReferenceExceptionを示すことの価値を見たことはありませんが、そのメッセージを表示するという単なる行為は、あなたのソフトウェアが回復する手がかりを持っていなかったことを示しています!その例外メッセージは、エンドユーザーにとって決して有用ではありません。
コートアンモン-復活モニカ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.