サーバーは、受け入れるものを「寛容」にし、「障害のある入力を静かに破棄する」必要がありますか?


27

私は、今ではこの格言が間違いであることに誰もが同意するという印象を受けていました。しかし、私は最近、「寛大な」コメントが137回(今日現在)支持されているこの回答を見ました。

私の意見では、ブラウザが受け入れるものに対する寛大さが、HTMLや他のいくつかのWeb標準が数年前にあった完全な混乱の直接の原因であり、ごく最近その混乱から適切に結晶化し始めました。私はそれを見る方法、あなたが受け入れるものの中に寛大されますこれにつながります。

格言の2番目の部分は、「仕様で要求されていない限り、エラーメッセージを返さずにエラーのある入力を静かに破棄する」ことです。何かが静かに失敗したときに頭を壁にぶつけたプログラマーは、私の言っていることを知っているでしょう。

だから、私はこれについて完全に間違っていますか?私のプログラムは、受け入れるものに寛容で、静かにエラーを飲み込むべきですか?または、これが意味するものを誤って解釈していますか?


元の質問は「プログラム」でしたが、それについてはみんなの意見を取り入れています。プログラムが寛大であることは理にかなっています。しかし、私が本当に意味したのはAPIです。人々ではなく、他のプログラムに公開されるインターフェースです。HTTPはその一例です。プロトコルは、他のプログラムのみが使用するインターフェースです。「If-Modified-Since」のようなヘッダーに入る日付を直接提供することはありません。

したがって、問題は次のとおりです。標準を実装しているサーバーは寛大で、標準で実際に必要なものに加えて、いくつかの他の形式の日付を許可する必要がありますか?「寛大になる」というのは、ヒューマンインターフェースではなく、この状況に当てはまると思われます。

サーバーが寛大な場合、それは全体的な改善のように思えるかもしれませんが、実際には、寛容に依存するクライアント実装につながるため、わずかに異なる方法で寛大な別のサーバーで動作することに失敗すると思います。

だから、いくつかのAPIを公開するサーバーは寛大である必要がありますか、それとも非常に悪い考えですか?


次に、ユーザー入力の緩やかな処理について説明します。YouTrack(バグ追跡ソフトウェア)を検討してください。Markdownを連想させる言語をテキスト入力に使用します。「寛大」であることを除いて。たとえば、書く

- foo
- bar
- baz

ない箇条書きリストを作成するための文書化の方法、そしてまだそれが働きました。その結果、内部バグトラッカー全体で多く使用されることになりました。次のバージョンが登場し、この寛大な機能はわずかに異なる動作を開始し、この(非)機能を(誤って)使用したリストの束を壊します。箇条書きリストを作成する文書化された方法は、もちろん機能します。

だから、私のソフトウェアは、それが受け入れるユーザー入力に寛容でなければなりませんか?


4
「エラーのある入力を静かに破棄する」ことについて、私はそれぞれのケースで入力の誤りとみなされるべきものを尋ねます。ユーザーに質問し、「はい」または「いいえ」を期待している場合、「YES」は誤った入力ですか?「y」はどうですか?「oui」はどうですか?一般に、入力が期待したものではないことをユーザーに伝えることを恥ずかしがらないでください。ただし、可能な限り包括的であることを確認してください-私の考えでは、それは「寛大であること」の意味です。

3
エンドユーザーの入力について話している場合-アプリケーションのユーザーフレンドリに関連している場合は、怠leでなければなりません。自動化されたマシン生成入力(APIから)の場合、冗長(厳密)である必要があります。
バーハンKhalid

2
実際、HTMLの寛大さが、HTMLが人気を博した理由でした(そして、XHTMLの厳格さにより、HTMLが削除されました)。
オリバーワイラー

1
重要なのは、それが正常に失敗することを許可できるシナリオである場合、少なくともイベントをログに記録することだと思います。
リグ

2
@OliverWeiler XHTMLの失敗は、それがまったく不要だったという事実と関係があると感じています。HTMLはすでにそこにあり、少しは機能していました。また、HTMLはもちろん非常に人気がありますが、この技術を成功と呼んでいるのは少し残念です。これは需要を満たしますが、Symbianがスマートフォンの需要を満たしたのと同じくらい満足します。
ローマンスターコフ

回答:


9

もちろん、あなたは完全に正しいです。プログラムは「寛大な」ものであってはなりません。そうすることで問題が隠されるだけです。問題は、敷物の下に流されるのではなく、強調されるべきです。有益なエラーメッセージは、プログラムがユーザーの役に立つために絶対に必要なものです。

誤った/無効なデータが提供されるほとんどの場合、そのデータのプロバイダー(ユーザーまたは他のプログラムの出力)は、おそらくそれが無効であることを知らなかったでしょう。エラーを飲み込むと、エラーが有効である(または有効である可能性がある)と考えられ、無効なデータが増殖します。

システムが相互運用する唯一の方法は、その相互運用を完全かつ明確に定義することです。仕様外のデータを受け入れるプログラムは、仕様で無効であってもそのデータを事実上受け入れます。これにより、互換性が非常に負荷が高くなるだけでなく、正式に定義されなくなります。このプログラム自体が事実上の標準になりました。したがって、寛大なプログラムをさらに開発したり置き換えたりすることは不可能です。なぜなら、その動作方法をほんのわずかしか変更できないからです。


25

それはすべてあなたのターゲット層が誰であるかによると思います。プログラマーなら、絶対にそうではありません。あなたのプログラムは激しく失敗し、血まみれの殺人を叫ぶはずです。ただし、ターゲットオーディエンスプログラマーでない場合、プログラムは例外を適切に処理できる寛大なものでなければなりません。そうでなければ、甘い血まみれの殺人をささやきます。

ケーススタディとして、NPAPI Flashプレーヤーを使用してください。発生する可能性のあるエラーの99%を本当に気にしない人のための「リリース」バージョンがありますが、何かがうまくいかないときに流血の殺人を叫ぶために使用できる「デバッグ」バージョンもあります。それぞれがFlashコンテンツの再生をサポートしていますが、2つの完全に異なる人口統計を対象としています。

最後に、重要なことは次のとおりだと思います:ユーザーは何を気にしますか?


4
それにもかかわらず、プログラマ以外の対象者を対象にしていると主張するUnixyコマンドラインツールの大部分は、間違いを犯したユーザーには役に立たない。あなたがプログラマーでなくても、通常はプログラムが問題を説明する方が無意味なことや意図しないことをするよりも優れています。
ティムウィ

2
@romkyns:完全ではありませんが、アプリケーションはターゲットユーザーにとって意味のある方法でエラーを処理する必要があると言っています。
デミアンブレヒト

@Timwi:その場合、これらのUnixyコマンドラインツールは十分に設計されていません;)
デミアンブレヒト

3
@romkyns-良い例は次のとおりだと思います:デバッグモードでは、問題が発生したときにプログラムを停止し、何が間違っていたかを伝えたいと思います。プロダクションモードでは、プログラムをできる限り動作させ、処理可能な問題をログに記録する必要があります。このようにして、プログラマーは自分が間違ったことを確認して修正できますが、ユーザーは修正できないものに悩まされることはありません。いくつかの問題は明らかに修正できませんが、良い例はCSSスタイルルールです。スタイルルールの1つを理解していなくても、サイトをレンダリングできます。
モニカの復元

1
@BrendanLongのコメントは、ほとんど頭を悩ませています。出力を生成することが、正しいことよりも重要な場合があります。一部のエラー(または警告)は、ユーザーの入力なしで正常に回復できます。これらのケースでアプリケーションに何をさせたいかはあなた次第です。
ダニエルB

7

「寛大な」2つのタイプがあります:1つは不正確な入力を受け入れ、それを意味することを試みることであり、他は異なるタイプの入力を受け入れることです。

一般に、実行可能な場合は常に2番目のものが必要です。1つ目は、速く死ぬまでの時です。例:日付。

有効、無効、あいまいな入力を含む入力例を次に示します。

  • 2011-01-02
  • 01/02/2011
  • Jan 2, 2011
  • 2-Jan-2011
  • Green

無効な入力は1つだけです: Green。日付として受け入れようとしないでください。Green明らかに日付ではないので、これはサイレント障害が許容される場合です。

01/02/2011有効ですが、あいまいです。米国の日付(1月2日)として入力されたかどうか(2月1日)かどうかは必ずしもわかりません。ここでは、大声で失敗し、ユーザーに明確な日付を尋ねることがおそらく最善です。

2011-01-02通常は明確であると見なされるため、先に進んで「YYYY-MM-DD」の形式であると想定し、それ以降は失敗するだけでよい場合がよくあります。ただし、ユーザー入力を処理するときは、ちょっとした判断が必要です。

Jan 2, 2011そして2-Jan-2011それらが受け入れられるべきで、有効かつ明確なです。しかし、The Second of January of the year 2011であるにも有効かつ明確な、しかし行く遠いという寛大さのためには過剰です。先に進んで、静かに失敗してくださいGreen

要するに、答えは「依存する」です。入力できるものを見て、競合するタイプの入力(DD/MM/YYYYvsなどMM/DD/YYYY)を決して受け入れないようにしてください。

リンクされた質問/コメントのコンテキストでは、それはのケースです2011-01-02。入力はJSONのように見え、mimetypeが間違っていてもJSONのように検証されます。さらに進んで、ある時点で障害が発生した場合でも使用してみてください。


1
ここで検討していないことが1つあります。ユーザーがその文字列を入力した場合、はい、さまざまな形式を受け入れる必要があります。それについては間違いありません。しかし、私たちはAPIについて話している。APIのクライアントは他のプログラムです。日付形式に寛容な場合、このAPIを公開するすべての将来のサーバーは、まったく同じ方法で寛容でなければなりません。寛容さは、結局、役に立たず、むしろ不利益になると思いませんか?
ローマンスターコフ

1
@romkyns寛容さがどこにあるのかを誤解していると思います。APIは、それが何で寛大であるべき受け入れ(それはすべてを理解しておく必要があり2011-01-02Jan 2, 20112-Jan-2011ていない、それは何で、それを実装するにはあまりにも難しいことではありません場合は、)を出力します。そのAPIの将来のクライアントは、それらの1つを正しく入力している限り、特定のAPIについて知る必要さえありません。理想的には、APIレイヤーはこれらすべてを、コードが渡す前に使用するのと同じ内部表現に変換します。
イズカタ

たとえば、@ romkynsの出力は、常に2011-01-02形式にすることができます。これは、ドキュメントに入れるものです。有害な影響はまったくありません。
イズカタ

4
@Iskata:あなたは誤解していました。バイナリとしてのみ利用可能な古いプログラムがあったと想像してください。古いものと同じ入力を受け入れる新しいプログラムを作成する必要があります。古いプログラムが受け入れる内容が明確に定義されていれば、ジョブは明確に定義されています。寛大な場合、あなたの仕事は不可能です。
ティムウィ

1
まったくそう思わない。ユーザーが入力したものでない限り、常に入力と出力の両方に厳密になります。サービスを再実装する必要がある場合はどうなりますか?可能なすべての日付形式を文書化しましたか?古いクライアントを破壊したくないので、それらをすべて実装する必要があります。マシンで生成されたすべての日付インスタンスおよび期間にISO 8601を使用してください。これは適切に指定されており、ライブラリで広く利用可能です。ところで、2011-01-02とはどういう意味ですか?2日の00:00から3日の00:00までの期間は?どのタイムゾーンで?
ディベケ

6

黙って失敗することは、あなたができる限り最悪のことです。サイレントエラーでAPIをデバッグしようとしましたか?それは不可能です。

「回復するために最善を尽くしますが、詳細なエラーを送信します」と「サイレントエラー」があります。


3

ポステルの法則-「あなたは何をするかについて保守的であり、他人から受け入れることについては寛大であること」がJSONサービスについて議論されているようです。これは通常、UIではなくWebサービスに適用されます。

UIの建設的なユーザーフィードバックとユーザー入力の制限には、経験則が使用されます。


しかし、ここの答えを見ると、UIの場合のみ理にかなっている、つまり元の法律の反対であることに誰もが同意するようです。
ローマスターコフ

私はあなたの言っていることを見て、きれいな厳密なAPI /サービスが目標であるというポスターに同意しますが、良くも悪くも私のサービスに何らかの形で「堅牢性」を追加したことを知っています。通常、境界での1つまたは2つの値の変換。意味が明確である限り、アプリはメッセージの処理方法を認識しており、ビジネスルールに違反することはありません。堅牢性を追加すると相互運用性が向上します。
マークローレンス

他の誰かがあなたの仕様を実装するまで、何百ものクライアントが依存するようになった「堅牢性」が実際には仕様に含まれておらず、リバースエンジニアリングが必要であることが
わかり

3

これはTAOUPの第1章、第6章で十分にカバーされていると思います。具体的には、プログラムが入力でできることを実行し、正しいデータを転送し、正しい応答が失敗した場合はできるだけ早く実行することを規定する修復ルール

同様の概念は、防御的プログラミングです。あなたはしていないあなたが受け取る入力の種類を知っているが、あなたのプログラムがカバーする強力な十分なはずですすべてのケースを。この手段はマングルされた入力のような既知の問題のために回復例でプログラム、しなければならないの未知数を処理するためのキャッチすべてのケース。

したがって、その入力処理している限り、欠陥のある入力を静かに破棄することは問題ありません。そのまま床に落としてはいけません。


APIの場合、寛大であることはプログラムの場合と同じだと思います。入力はまだ間違っていますが、可能な限り修復しようとしています。違いは、有効な修復と見なされるものです。あなたが指摘するように、寛大なAPIは、人々が存在しない「機能」を使用するときに問題を引き起こす可能性があります。

もちろん、APIは合成ルールの下位レベルバージョンにすぎません。そのため、インターフェースであるため、実際に最も驚きの少ないルールでカバーされています。

スペンサーからの引用として、表面的な類似性を避けてください。これは、「ファジー」入力について議論することができます。これらの条件下で、私は通常、すべてがプログラムが修復できないことを指していると主張します。なぜなら、それは望まれるものを知らないためであり、ユーザーベースにとって最も驚くべきことではないからです。

ただし、多くの「標準」を持つ日付を扱っています。時々、これらは単一のプログラム(チェーン)に混在することさえあります。日付が予想されることがわかっているので、日付を認識しようとするのは良い設計です。特に、日付が外部プログラムから取得され、変更されずに秒単位で渡される場合。


2

サーバーに展開されるプログラムは、ほとんどの場合、毎分、時には毎秒数千のリクエストを受け取ることになっています。サーバープログラムがクライアントからの誤った入力を受け入れて修正する場合、次の2つの欠点があると思います。

  1. 貴重なサーバー時間の損失。1秒あたり1000件以上の要求がある場合、各要求の障害を確認すると、各クライアントの応答が遅くなることがあります。
  2. 正しい入力を提供するクライアント/クライアントプログラムに対して不公平です。それ以外に、サーバー側のプログラマーがサーバーコードに座るとき、彼/彼女は、不完全な入力が何であるかについてのさまざまなケースについて考えなければなりません。誰がそれを決めるのでしょうか?

サーバープログラムは誤った入力を受け入れてはなりませんが、誤った入力がある場合、サーバーはクライアントにエラーメッセージを返す必要があります。


2

理想的な動作は、概念的には、安全にできることを行うと同時に、問題を解決できる人に何らかの形で通知されるようにすることです。もちろん、実際には、後者の制約を直接満たすことは不可能な場合が多いため、疑わしい入力を処理するのに最適な質問になります。

プロトコル、フォーマット仕様、または「言語」の設計で非常に役立つ可能性のあることの1つは、潜在的な理解されていない項目の4つのカテゴリを区別する手段を持つことです。

  1. 理解できない場合は除外すべきもの。
  2. 理解されない場合は無視されるべきですが、データを渡す必要がある場合は保持されるもの(おそらく、それを理解していない少なくとも1つのステージを通過したことを示す何らかのラッパー)
  3. 理解できない場合は警告を生成するが、データリカバリの試行を妨げないもの(たとえば、Webページ内で、タイプが不明であるが、ファイル内の終わりが明確に定義されているオブジェクトは、赤で表示されるページの残りの部分のレンダリングを妨げることなく「X」。)
  4. それらを理解できないものは、他の場所で深刻で回復不可能な問題を抱えていることを示すもの(たとえば、残りのデータが圧縮されていること、必要な圧縮解除を実行できるものによって理解されるもの)。

データ形式の任意のバージョンを読み取ることができるアプリが、後のバージョンに準拠して生成されたものに適切なカテゴリを認識することができるように明確に定義された規則を持つことは、アドホック互換性対策をくじくよりもはるかに優れたアプローチです後で。たとえば、ファイル形式に「タグ:値」という形式の行がある場合、タグの最初の文字がそれが属するカテゴリを示すように指定できます。サイレント無視カテゴリのタグの場合、最初の文字にタグが有効であると予想される標準のバージョンを示すこともできます(そのため、「サイレント無視」タグがバージョン3に存在すると主張する場合標準では、バージョンのパーサーは黙って無視しますが、バージョン3以降のパーサーは、解析できなかった場合はスコークします)。

いずれにしても、最も重要なことは、あいまいなデータや誤解されたデータを誤ったデータに変換することを避けることです。場合によっては、あいまいなデータの伝達をまったく拒否する方が良い場合もありますが、他の場合には、受信者がそれを曖昧でないと見なす場合に受信したとおりに正確に伝達する方がよい場合があります。まったくの悪ではないとしても本当に危険なのは、さまざまな仮定を使用したデータの変換です。たとえば、次のような日付のリストの変換です。

01/12/12
12/12/12
99/12/12

のような日付のリストに

2012-01-12
2012-12-13
1999-12-12

いくつかの誤って入力された日付のリストがあったとしても、元の形式のリストを与えられた人間は、どの形式が正しいかを判断し、さらなる調査のために疑わしい値にフラグを立てることができる場合があります(他の記録との照合など) )しかし、後者の形式で日付をレンダリングすると、絶望的で回復不能な文字化けが発生します。


よく言った。あなたの答えが少し深くなるのが好きです。私はこれを受け入れたいと思っていますが、この質問が受けた全体的な関心を考えると、しばらくこのままにしておくと思います。
ローマンスターコフ

1

私のUIエクスペリエンスは主にデスクトップシステムから得られます。Webサイトは異なりますが、デスクトップシステムに挑戦する可能性のあるサイトをいくつか見ました。しかし、それが価値があるもののために:

エラーメッセージは最後の手段であることがわかりました。理想的なシステムにはまったくありません。最善の方法は、まず悪いエントリを許可しないことです。ユーザーが月のドロップダウンリストから選択している場合、ユーザーは「緑」を入力できません。彼は灰色のボタンを押すことができません。

次にやるべきことは、不良データを受け入れることです。1か月間の毎日の売り上げのヒストグラムを表示しているとします。ユーザーの入力後、グラフは1世紀をカバーし、1世紀外のバーは他の10倍になります。ユーザーは、自分が何か間違ったことをしたことを知っており、さらに、メッセージが伝えることができるものよりも、自分が間違ったことをもっとよく知っています。たとえば、マウスをドラッグしてエントリがグラフィカルである場合、この種のフィードバックは引き続き機能し、非常に貴重です。入力の束は無効な場合がありますが、この方法を使用すると、ユーザーは各マウス位置の結果に関する詳細なフィードバックを即座に取得できます。

とは言っても、ユーザーがボタンをグレーアウトして、プッシュできない理由を知る必要がある場合もあります。その後、それに対する助けはありません(もしあれば)、ボタンを非表示にして、彼がそれをクリックしたときに、ボタンが現在動作していない理由の良い説明を彼に与えてください。


0

この声明は、インターネットを介した情報の送信に関するものです。インターネットを介して情報を送信することの1つは、常にターゲットに到達したり断片化したりするわけではないということです。


0

ここで見逃しているように見える何か-失敗の結果は何ですか?

Webページを表示しますか?悪い入力を許容するためにできる限りのことをすべきです。選択肢は、できることを表示するか、エラーをスローすることです。後者のコースはユーザーに何も与えないため、ユーザーに完全に役に立たない結果を与えるため、最後の手段に過ぎません。エラーがこれより悪いのはかなり難しいでしょう。

一方、Minuteman IIIのターゲットを要求している場合、あいまいになる可能性があるため、「モスクワ」を入力として拒否します。


プログラマーであり、バカなコードを書いたとしても、システムは「停止し、「ここで間違えた(行番号)」と叫ぶだけでなく、何かを表示するために最善を尽くすべきです。それがまさに信じられないほど悪いコードにつながると思いませんか?
ローマンスターコフ

@romkyns:エラーのスコーキングに厳格な、そのようなもののためのデバッグモードがあります。
ローレンペクテル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.