web-dev-qa-db-ja.com

ライブラリ/モジュールに関数の「注意」バージョンと「危険」バージョンの両方を含める

独自のモジュールに切り離したコードを書いています。それを使用するのは私だけである可能性が高いですが、そうではないかもしれないと考えようとしています。このモジュールの関数は、渡された配列内のオブジェクトに対して操作を実行します。現在、不正なデータの取得によって引き起こされる例外を回避するために、一連の安全性チェックを行っています。具体的には、未定義/ null値の可能性を考慮しています。その配列、または配列内のオブジェクトの1つ、またはオブジェクトの1つのプロパティの1つ。言い換えれば、かなり多くのチェックです。ただし、このモジュールが使用されるアプリケーションでは、このモジュールで処理されるデータを送信する前に、これらすべてをすでにチェックしています。このデータのnull値は、他の場所でも問題を引き起こすためです。

すべてがスムーズに機能しているので、作業を複製しているので、効率を上げるためにモジュールの安全チェックの一部を削除したいと思います。ただし、このモジュールだったが他の誰かによって使用される場合は、できるだけ防弾にする方がよいと思います。したがって、悪いデータが彼らの側から渡された場合、私のモジュールはクラッシュの責任を負うことなくそれを処理することができます。しかし、私のモジュールを使用している架空の人物は、私がいるのと同じ位置にいるのではないかと思いました。彼らが渡しているデータは、すでにチェックされているので、良いと確信しています。

私にとって明らかな解決策は、モジュールに特定の主要機能の2つのバージョンを含めることです。データを信頼しない場合は「注意」バージョン、信頼する場合は「危険」バージョンで最大化するだけです。パフォーマンス。これは行われたことですか?良いドキュメントを想定すると、それは良い考えでしょうか?そして、それがだった良いアイデアである場合、関数ごとに2つを区別する方がよいでしょうか。 processSafely(data)およびliveDangerously(data))–またはモジュール内の個別の名前空間を介して– myModule.safe.process(data)およびmyModule.reckless.process(data)

編集:これまでの回答は貴重でしたが、私が話している特定のモジュールは、ブログ記事の(潜在的に大きな)配列をオブジェクトとして受け入れるように設計されていることを(Stack Overflowの領域にあまり踏み込まずに)追加する必要があると思いました(かなり標準的な形式のパーサーから取得されるため)、上記の記事からタグを抽出してカウントし、個々のタグとそのカウントを含む配列を返します。言い換えれば、ファイル/オブジェクトの解析を含むすべてのタスクと同様におそらく特定の形式に準拠しているので、うまくいかないことがたくさんありますが、私(またはユーザー)はおそらく説明する必要がありますとにかく他の場所でそれのために(例えば、記事をビューにレンダリングする前など)。また、私が話しているすべてのチェックはO(n) –1つまたは2つの予備的なifステートメントまたは型強制ではありません。

1
Toadfish

私の経験では、すべてが正常であることが「わかっている」場合でも、関数にすべての前提条件をチェックさせることは非常に価値があります。私たちがコンピューターに任せていることはすべて、混乱して偶発的な間違いを引き起こすことはできません。これを効率的に実装する方法はいくつかありますが(たとえば、本番ビルドではオフにできるアサーションとして)、それらはかなりの量の安全性と引き換えにほとんど利益が得られない傾向があると感じています。

代わりに、実行時に制約が1回チェックされ、言語の型システムが制約が無効になることは決してないことを証明する、水密な抽象化の構築を試みることができます。

例として、電子メールアドレスを操作する関数sendEmail(String to, String subject, String plainTextMessage)があるかもしれません。この関数は、_String to_が有効な電子メールアドレスであることを確認する必要があります。同じアドレスに複数のメールを送信すると、このチェックが不必要に繰り返されます。代わりに、コンストラクターEmailAddress(String maybeAddress)で文字列が有効なアドレスであるかどうかをチェックする_class EmailAddress_を定義できます。そうでない場合は、スローします。その場合、オブジェクトはそのアドレスで初期化されます。このチェックは建設時に一度行われ、その後は追加のチェックなしで使用できます。

ただし、基になる文字列への外部アクセスが必要になります。このアクセスは読み取り専用であることが重要です。基になる型が変更可能である場合、または言語がconst参照をサポートしていない場合は、オブジェクトを公開するのではなく、安全なメソッドをオブジェクトにプロキシする方が理にかなっています。これを行った後、最終的にsendEmail(EmailAddress to, EmailSubject subject, String body)になる可能性があります。

この手法は、新しい型の定義が簡単な、優れたカプセル化メカニズムを備えた静的型付け言語に特に適用できます。私は日常的にこの手法をC++で使用し、場合によってはJavaで使用します。動的言語では、静的型チェックがないため、あまり役に立ちません。ただし、消費関数は実行時型チェックを実行するだけで済みます。これは通常、完全な前提条件チェックよりも安価です。

7
amon

可能であれば、これを処理する最良の方法は、型システムで前提条件をエンコードすることです。次に、前提条件アサーション型のインスタンスを作成する唯一の方法が、Option/Optional/Maybeタイプ。

これの利点は、メソッドの前提条件に違反するコードをコンパイルできないことです。

たとえば、scalaでは、

def toPosInt(n: Int): Option[Int] = if (n > 0) Some(n) else None
// Find the square root of a positive number
def sqrt(n: PosInt): Float = ???

負の数のPosIntを取得できないため、このsqrtを負の数で呼び出すことはできません。 Java 8には同様のOptional型があります。

1
Daenyth

いくつかの可能性があります:

1)兵士をつけて、できることはすべて解析し、文句を言わないでください。これらの404、不正なHTML、およびnullはすべて無視してください。これはひどいオプションです。あなたのためにたくさんの仕事があります、そしてクライアントは結果が彼らが彼らがそうあるべきであると思うものではないかもしれないということを知りません。たとえば、バーニーをつなぐブログのエラーがヒラリーを称賛するブログよりも多い場合、結果に偏りが生じます。

PHPなぜ兵士を雇うべきではないのか)という強い批判からの素晴らしい引用 ""無意味なことをしたり、エラーで中絶したりすると、無意味なことをするでしょう "

2)最初の不正な入力で有用な例外をスローします。コーディングが簡単で、クライアントにとってより便利です。しかし、それでも厄介です-一度に1つずつ修正するのは難しいです。

3)兵士ですが、「悪いブログ」は無視してください。ただし、すべての悪いブログのリスト(理想的には、「リンクに404があります」などの説明)を保持し、それをクライアントに返します。エラーが発生したというフィードバックを受け取り、結果が「十分」であるかどうかを判断できます。また、いくつかの既知の不良入力を含めることでユニットテストできるものもあります。

1
user949300