例外メッセージには有用な詳細が含まれている必要があります について、ある程度の合意があるようです。
システムコンポーネントからの多くの一般的な例外に有用な詳細が含まれていないのはなぜですか?
いくつかの例:
List
インデックスアクセスArgumentOutOfRangeException
はしない試みたインデックス値が無効であることを通知しません許容範囲を教えてくれます。したがって、私にとっては、ほとんどの場合、例外メッセージには、役立つのに十分な詳細情報が含まれていないようです。私の期待は外れていますか?私はこれに気付いても例外を間違って使用していますか?あるいは、私の印象が間違っているかもしれません:例外doの大部分は、実際に役立つ詳細を提供していますか?
例外の概念はソフトウェアエンジニアリングの分野ではまだ十分に成熟していないため、例外には有用な詳細が含まれていません。そのため、多くのプログラマーは例外を完全に理解していないため、適切に処理しません。
はい、IndexOutOfRangeException
には、範囲外だった正確なインデックスと、それがスローされたときに有効だった範囲が含まれている必要があり、.NETランタイムの作成者に代わって軽視されるそうではありません。はい、Oracleのtable or view not found
例外には、検出されなかったテーブルまたはビューの名前が含まれている必要があります。また、例外の責任がある人のために、例外が軽視されることはありません。
ほとんどの場合、この混乱は、例外には人間が読めるメッセージを含める必要があるという誤った元の考えに起因します。これは、例外がすべてについての理解の欠如に起因するため、悪循環です。
例外には人間が読めるメッセージが含まれるべきだと人々が考えているため、例外によって伝えられる情報もすべて人間が読めるメッセージにフォーマットする必要があると信じており、人間が読めるすべてのメッセージを書くのは退屈です。コードを構築する、またはそうすることは、メッセージを見るかもしれないどんな覗き見する目にも不適切な量の情報を漏らす可能性があることを恐れています。 (他の回答で言及されているセキュリティの問題。)
しかし、問題の真実は、例外が人間が読めるメッセージを含まない必要があるため、心配するべきではないということです。例外とは、プログラマーだけが見て、対処する必要があるものです。障害情報をユーザーに提示する必要がある場合、それは非常に高いレベルで、洗練された方法で、統計的に言えば英語ではありそうもないユーザーの言語で行われる必要があります。
したがって、プログラマーにとって、例外の「メッセージ」は例外のクラス名であり、例外に関連するその他の情報はすべて例外オブジェクトの(最終/読み取り専用)メンバー変数にコピーされます。好ましくは、考えられるすべての小さなものです。この方法では、メッセージを生成する必要はありません(または生成する必要があります)。したがって、詮索好きな目はそれを見ることができません。
以下のコメントでThomas Owensが表明した懸念に対処するため:
はい、もちろん、あるレベルでは、あなたが例外に関するログメッセージを作成します。しかし、あなたが言っていることにすでに問題があることがわかります。一方で、スタックトレースのない例外ログメッセージは役に立たない一方で、ユーザーに例外スタックトレース全体を表示させたくありません。繰り返しになりますが、ここでの問題は、私たちの視点が従来の慣習によって歪められていることです。ログファイルは伝統的にプレーンテキストでしたが、私たちの規律が初期の段階では問題なかったかもしれませんが、おそらくそれ以上ではありません。セキュリティ上の懸念がある場合、ログファイルはバイナリまたは暗号化されている必要があります。
バイナリテキストかプレーンテキストかに関係なく、ログファイルは、アプリケーションがデバッグ情報をシリアル化するストリームと考える必要があります。このようなストリームはプログラマーの目だけのためのものであり、例外のデバッグ情報を生成するタスクは、例外をデバッグログストリームにシリアル化するのと同じくらい単純でなければなりません。このように、ログを見ると、例外クラス名がわかります(これは、すでに述べたように、すべての実用的な目的で「メッセージ」です)、関連するすべてを記述する例外メンバー変数のそれぞれ- and-practical-to-include-in-log、および全体のスタックトレース。人間が読める例外メッセージのフォーマットが、このプロセスから著しく欠落していることに注意してください。
追伸.
このテーマに関する私の考えのいくつかのより多くはこの答えで見つけることができます: 良い例外メッセージを書く方法
P.P.S.
多くの人がバイナリログファイルについての私の提案に気を取られているように思われるので、ここで提案している内容がnotであることをさらに明確にするために、もう一度答えを修正しました。ファイルはバイナリである必要がありますが、ログファイルはバイナリである必要があります。
システムコンポーネントからの多くの一般的な例外に有用な詳細が含まれていないのはなぜですか?
私の経験では、例外に有用な情報が含まれていない理由はいくつかあります。この種の理由はシステムコンポーネントにも当てはまると思いますが、よくわかりません。
私の期待は外れていますか?私はこれに気付いても例外を間違って使用していますか?
ちょっと?つまり、例外にはNiceメッセージが必要ですが、それらもexceptionsです。コーディング時に例外的な条件を回避するためのコードの設計、または例外的な条件を処理するためのコードの記述(メッセージを無視)を対話式のフィードバックメカニズムとして使用しないでください。これらをデバッグ目的で使用することは避けられませんが、ほとんどの状況ではそれを最小限に抑える必要があります。この問題に気づいたことで、あなたはそれらを防ぐのに十分な仕事をしていないことを心配しています。
私はC#の経験、特にC++の経験はあまりありませんが、私はこれを伝えることができます。開発者が作成した例外のうち10回のうち9回は、これまでに発見された一般的な例外よりも有用です。
理想的には、一般的な例外は、エラーが発生した理由を正確に示し、簡単に修正できるでしょう-しかし現実的には、さまざまな種類の例外をスローできる複数のクラスを持つ大規模なアプリケーションでは、 同じ例外の種類。デフォルトのメッセージに依存するよりも、エラーを返すために独自の出力を書き込む方が常に価値があります。
多くの人が指摘しているように、一部のアプリケーションは、セキュリティ上の理由から、または回避するために、ユーザーに表示させたくないエラーメッセージをスローしないwantでないため、このようにする必要があります。それらを混乱させます。
代わりに、デザインでアプリケーションにスローされる可能性のあるエラーの種類を予測し(常にエラーが発生します)、問題を特定するのに役立つエラーキャッチングメッセージを作成する必要があります。
これは常に役立つとは限りません-どのエラーメッセージが役立つかを常に予測できるわけではないためですが、長期的には、自分のアプリケーションをよりよく理解するための最初のステップです。
問題は、「システムコンポーネント」(別名標準ライブラリクラス)によってスローされる多くの例外に、有用な詳細が含まれていない理由を具体的に尋ねていることです。
残念ながら、ほとんどの開発者は標準ライブラリにコアコンポーネントを記述せず、詳細な設計ドキュメントやその他の設計根拠を必ずしも公開していません。言い換えれば、私たちは確かに知ることは決してないかもしれません。
ただし、詳細な例外情報が望ましくない、または重要でない理由については、2つの重要な点に注意してください。
例外は、なんらかの方法でコードを呼び出すことによって使用できます。標準ライブラリは、例外の使用方法に制約を課すことができません。具体的には、ユーザーに表示されます。範囲外の配列インデックスを検討してください。これは、攻撃者に役立つ情報を提供する可能性があります。言語デザイナーは、アプリケーションがスローされた例外をどのように使用するか、またはそれがどのタイプのアプリケーションであるか(Webアプリやデスクトップなど)さえわからないため、情報を除外する方がセキュリティの観点から安全です。
例外すべきではないユーザーに表示される。代わりに、わかりやすいエラーメッセージを表示し、攻撃者がアクセスできない場所に例外を記録します(該当する場合)。エラーが特定されたら、開発者はコードをデバッグし、スタックフレームとロジックパスを検査する必要があります。この時点で、開発者は、例外が期待するよりも多くの情報を持っています。
まず、diagメッセージに正確なコード行とサブコマンドを4秒で表示する情報が含まれている場合でも、ユーザーがそれを書き留めたり、サポート担当者に伝えたりすることはない可能性があります。そして、あなたは「それは違反について何かを言いました...私はそれが複雑に見えたのを知りません!」と言われるでしょう。
私はソフトウェアを作成して他のソフトウェアの結果を30年以上サポートしてきましたが、個人的には、例外メッセージの現在の品質は、最終結果がどのようにしてモデルに適合したかに関係なく、セキュリティとは実質的に何の関係もありません宇宙は、私たちの業界の非常に多くがもともと独学であり、コミュニケーションに教訓を取り入れたことはないという事実とはるかに関係しています。新しいコーダーを何年もの間、何が悪いのかを理解する必要があったメンテナンスポジションに追いやった場合、少なくとも何らかの形の精度の重要性を理解するでしょう。
最近、再構築されているアプリケーションで、戻りコードが3つのグループのいずれかに分類されることが決定されました。
(100は何らかの理由で除外されました)
特定のワークフローでは、私たちの考えが再利用されたか、ジェネリックコードが致命的なエラーに対してジェネリックリターン(> 199)を使用するため、ワークフローで100の致命的なエラーが発生する可能性があります。メッセージにわずかに異なるデータがあると、ファイルが見つからないなどのエラーはすべて同じコードを使用し、メッセージと区別できます。
コードが請負業者から戻ってきたとき、事実上すべての単一致命的エラーが戻りコード101であったときの驚きは信じられないでしょう。
最初に作成されたとき、それらは誰も戻らないプレースホルダーであるはずだったので、あなたの質問に対する答えはメッセージがとても意味がないということだと私が考えたすべてのもの。結局のところ、人々はメッセージのせいではなく問題を修正する方法を見つけましたが、それらを無視してください。
その時以来、独学の人々は例外が何を含むべきかについての良い例を決して持っていませんでした。さらに多くのユーザーがメッセージを読まないようにし、サポートに引き継がないようにしてください(使用済みのユーザーによって切り取られて貼り付けられ、その後編集されてから送信される前に編集されるエラーメッセージが表示されますたくさんの情報のように思えて、私はそれをすべて欲しがることができなかったので、ランダムにそれらの束を削除しました。
そして、それがより多くの作業であり、フラッシュを追加しない場合、それだけの価値がない場合、あまりにも多くの(すべてではないがあまりにも多くの)次世代のコーダーでそれに直面しましょう。
最後の注意:エラーメッセージにエラー/戻りコードが含まれている場合、実行されたモジュールのどこかに「if condition return code-value」のような行があり、条件によって戻りコードの理由がわかるように見える発生した。これは単純な論理的アプローチのように見えますが、私の人生では、WindowsのアップグレードがCODE 80241013または他の非常に一意の識別子で失敗したときに何が起こったかをMicrosoftに通知するように試みてください。ちょっと悲しいですね。
少し異なる答えを与えるには:問題のコードはおそらく仕様どおりに行われています:
(レビュー/テストで拒否されるのを恐れて)最小限の時間と最小限の手間で、仕様に正確に準拠するように圧力をかけると、完全に準拠していて役に立たないライブラリ例外のレシピが得られます。
例外には、言語および実装固有のコストがあります。
たとえば、C++例外は、スローコールフレームとキャッチコールフレームの間のすべての生きているデータを破棄するために必要であり、それは高価です。したがって、プログラマは例外をあまり使用したくありません。
Ocamlでは、例外のスローはC setjmp
とほぼ同じです(そのコストは通過した呼び出しフレームの数に依存しません)。そのため、開発者は(例外ではなく、非常に一般的な、ケース)。対照的に、C++の例外は十分に重いため、Ocamlの場合のように例外をあまり使用しないでしょう。
典型的な例は、かなり深い再帰の中で「停止」できるいくつかの再帰的な検索または探索です(たとえば、ツリーで葉を見つける、または統合関数)。一部の言語では、その条件をすべての呼び出し元に伝達する方がより高速(非常に慣用的)です。他の言語では、例外をスローする方が速いです。
したがって、言語(およびそれを使用する開発者の習慣)に応じて、例外は多くの有用な詳細を伝えることができます。または、逆に、迅速な非ローカルジャンプとして使用して、非常に有用なデータのみを伝えることができます。
例外にはできる限り多くの情報を含めるか、少なくとも一般的ではないことに同意します。テーブルが見つからない場合、テーブル名はNiceになります。
しかし、例外を受け取ったコード内の場所で何をしようとしていたのかについては、もっと知っています。コントロール外のライブラリで問題が発生した場合、状況を修正するために多くのことを実際に行うことができないことがよくありますが、問題が発生した状況に関するはるかに役立つ情報を追加できます。
テーブルが見つからない場合、見つからないテーブルはSTUDENTSと呼ばれていると言われても、そのようなテーブルがなく、その文字列がコードのどこにもないため、あまり役に立ちません。
ただし、例外をキャッチして、実行しようとしたSQLステートメントで再スローすると、名前フィールドが Robert ');であるレコードを挿入しようとしたことが判明するため、より良い結果が得られます。 DROP TABLE STUDENTS; (常にxkcdがあります!)
そのため、有益ではない例外に対処するには、try-catch-rethrowを実行して、実行しようとしていたことに固有の詳細情報を取得します。
これが質問の理由に関するより多くの回答となるように、おそらく、ライブラリの作成者からの焦点が例外メッセージの改善に焦点を当てられていない可能性が高い理由は、彼らが知らないということです。なぜ失敗したものが試行されたのか、そのロジックは呼び出しコードにあります。