web-dev-qa-db-ja.com

範囲外の意味のある値の場合は例外をスローするか、自分で処理する必要がありますか?

緯度/経度の座標を表す構造体を書きました。それらの値の範囲は、経度では-180〜180、緯度では90〜-90です。

その構造体のユーザーが私にその範囲外の値を与えた場合、2つのオプションがあります。

  1. 例外をスローします(範囲外の引数)
  2. 値を制約に変換します

-185の座標には意味があるため(極座標であるため+175​​に非常に簡単に変換できます)、それを受け入れて変換することができます。

例外をスローして、コードに不要な値が与えられたことをユーザーに通知する方が良いでしょうか?

編集:また、緯度/経度と座標の違いも知っていますが、簡単に説明できるように簡略化したかったので、これは最も明るいアイデアではありませんでした

42

あなたの質問の核心がこれなら...

一部のクライアントコードが、データ構造がモデリングしているものに対して無効な値の引数を渡す場合、値を拒否するか、適切な値に変換する必要がありますか?

...それから私の一般的な答えは「拒否」になります。これは、実際に無効な値がプログラムに表示され、コンストラクタに到達する原因となっているクライアントコードの潜在的なバグに注意を引くのに役立つためです。バグに注意を向けることは、少なくとも開発中は、ほとんどのシステムで望ましいプロパティです(ただし、エラーが発生した場合に混乱するシステムの望ましいプロパティでない限り)。

問題は実際にそのケースに直面しているかどうかです。

  • データ構造が一般的に極座標をモデル化することを意図している場合、-180と+180の範囲外の角度は実際には無効ではないため、値を受け入れます。それらは完全に有効であり、常に-180から+180の範囲内にある同等のものをたまたま持っています(そして、それらをその範囲にターゲットするように変換したい場合は、自由に感じてください-クライアントコードは通常気にする必要はありません)。 。

  • データ構造がWebメルカトル座標を明示的にモデル化している場合(その初期形式の質問による)、仕様に記載されているすべての規定に従うのが最善です(わからないので、何も述べません)。 。 Ifモデル化するものの仕様に、無効な値があると記載されているため、拒否してください。それらが賢明なものとして解釈できると(したがって、それらは実際に有効であると)言われている場合は、それらを受け入れます。

値が受け入れられたかどうかを示すために使用するmechanismは、言語の機能、一般的な哲学、およびパフォーマンス要件によって異なります。したがって、(コンストラクターで)例外をスローするか、(プライベートコンストラクターを呼び出す静的メソッドを介して)構造体のnull可能バージョンを返すか、ブール値を返し、構造体をoutパラメーターとして呼び出し元に渡す(もう一度プライベートコンストラクターを呼び出す静的メソッドなど)。

それはかなり異なります。しかし、何かを行うにはdecideおよびdocument itを実行する必要があります。

コードが行う唯一の間違いなく間違ったことは、ユーザー入力が期待される範囲外である可能性があることを忘れて、誤って動作。それは、一部の人々はコードの動作について誤った仮定をしてそれがバグの原因となる一方で、他の人はコードの動作に誤って依存するためです(その振る舞いが完全に失敗したとしても)があるので、後で問題を修正するときに、さらに多くのバグを引き起こします。

この場合、どちらの方法でも引数を見ることができます。誰かが175度から+10度移動すると、最終的に-175度になります。ユーザー入力を常に正規化し、185を-175と同等に扱う場合、クライアントコードは10度を追加しても間違った処理を行うことはできません。常に正しい効果があります。 185をエラーとして扱うと、クライアントコードが正規化ロジックに相対度を追加するすべてのケースを強制する(または少なくとも正規化プロシージャを呼び出すことを忘れない)と、実際にはバグ(うまくいけば、すぐにつぶされるバグを簡単に見つけることができます)。ただし、経度の数値をユーザーが入力したり、文字どおりプログラムで記述したり、常に[-180、180)になるように意図された手順で計算したりした場合、その範囲外の値はエラーを示している可能性が高いため、「 「変換すると問題が隠れる可能性があります。

この場合の理想は、正しいドメインを表す型を定義することでしょう。抽象型を使用し(クライアントコードが単純にその中の生の数値にアクセスしないようにします)、正規化ファクトリと検証ファクトリの両方を提供します(したがって、clientトレードオフを行うことができます)。ただし、このタイプの値が何であれ、185はパブリックAPIから見たときに-175と区別できません(それらが構築時に変換されるか、または同等性、アクセサー、および何らかの違いを無視する他の操作を提供するかは関係ありません)。 。

10
Ben

1つのソリューションを選択することが本当に重要でない場合は、ユーザーに決定させることができます。

構造体が読み取り専用の値オブジェクトであり、メソッド/コンストラクターによって作成されている場合、ユーザーが持つオプションに基づいて2つのオーバーロードを提供できます。

  • 例外をスローします(範囲外の引数)
  • 値を制約に変換します

また、ユーザーに他のメソッドに渡す無効な構造体を持たせないでください。作成時に正しく構成してください。

編集:コメントに基づいて、私はあなたがc#を使用していると思います。

3
Filipe Borges

これは、入力がユーザーから直接いくつかのUIを介して行われるか、システムから行われるかによって異なります。

Iからの入力

これは、無効な入力を処理する方法に関するユーザーエクスペリエンスの質問です。特定のケースについてはわかりませんが、一般的にいくつかのオプションがあります。

  • 続行する前にユーザーにエラーを警告し、ユーザーに修正してもらいます(最も一般的)
  • 可能であれば自動的に有効範囲に変換しますが、変更についてユーザーに警告し、続行する前にユーザーが確認できるようにします。
  • 黙って有効範囲に変換して続行します。

どちらを選択するかは、ユーザーの期待とデータの重要度によって異なります。たとえば、Googleはクエリのスペルを自動的に修正しますが、役に立たない変更は問題ではなく簡単に修正できるため、リスクは低くなります(さらに、クエリが変更されたことが結果ページで明らかになります)。一方、核ミサイルの座標を入力する場合は、より厳密な入力検証を行い、無効なデータのサイレント修正を行わないようにする必要があります。したがって、普遍的な答えはありません。

最も重要なのは、入力を修正してもユーザーにメリットがあるかどうかを検討することです。 なぜユーザーは無効なデータを入力するのですか?スペルミスがどのように発生するかは簡単にわかりますが、なぜ経度-185を入力するのでしょうか。ユーザーが+175を本当に意味している場合、おそらく+175と入力します。無効な経度が単に入力エラーであり、ユーザーが-85か何かを意味している可能性が高いと思います。この場合、サイレント変換は悪い、役に立たないです。アプリにとって最もユーザーフレンドリーなアプローチは、おそらく無効な値をユーザーに警告し、ユーザーに修正してもらうことでしょう。

APIを介して入力

入力が別のシステムまたはサブシステムからのものである場合、問題はありません。例外をスローする必要があります。別のシステムからの無効な入力をサイレント変換しないでください。システムの他の場所でエラーがマスクされる可能性があるためです。入力が「修正」された場合、システムのより深い場所ではなく、UIレイヤーで発生するはずです。

0
JacquesB

例外をスローする必要があります。

あなたが与えた例では、185を送信し、それを-175に変換すると、その機能を提供するのに便利な場合があります。しかし、発信者が100万を送信するとどうなるでしょうか。彼らは本当にそれを変換するつもりですか?エラーの可能性が高いようです。したがって、1,000,000の例外をスローする必要があるが185の例外をスローする必要がない場合は、例外をスローするための任意のしきい値について決定する必要があります。一部の通話アプリがしきい値付近の値を送信しているため、そのしきい値はいつかあなたをつまずきます。

範囲外の値については、例外をスローする方が適切です。

0
brendan