web-dev-qa-db-ja.com

検証内でリモートリソースをクエリすることは悪い習慣ですか?

見て このsymfonyフォームと検証についての話、23:06 を見て、満足のいく答えが見つからないことに疑問を感じました。

バリデーター内でクエリ(またはWebリクエスト、または一般的な副作用)を実行することは悪い習慣ですか?

私の場合、Symfony検証制約仕様パターンのいくつかの実装があります。

同じコントローラーで(またはSymfonyコンポーネントを使用する場合は同じ形式で)複数回使用できるという事実を考えると、これらの検証要素へのデータベースへのクエリを実行するのがどれほど悪いか疑問に思っています。

  • パフォーマンスの懸念があります;特に、検証へのリクエストが常に同じであり、それを複数回送信する実際の理由がない場合。
  • 失敗の懸念があります;応答が遅れた場合、またはさらに悪いことに、要求が失敗した場合はどうなりますか?
    • データが実際に有効であることを確認できず(実際に有効な場合でも)、他のインシデント/違反と一緒に報告することができなかったため、検証によりインシデント/違反を追加する必要がありますか?
    • 検証することができないため、代わりにそれを受け入れる必要がありますか?
    • 再試行する必要がありますか?
    • エラーをスローする必要がありますか?
  • 境界を越え、懸念の分離の欠如があります;ドメインモデル(IMHO、そのインバリアント/検証ルールを含む)の何もがインフラストラクチャ(この場合は永続化レイヤー)の何かについて知っている、または依存関係があるとは思いません。

受け入れられますか?避けるべきですか?全く元気ですか?私は一般的にそれを拒否する気持ちを持っています(それが私が求めている理由です)。

2
Kamafeather

(あなたが言及する理由のために)それは強く避けられるべきですが、時々他の選択肢よりも優れています。必要に応じて、パフォーマンスの問題を軽減し、障害の問題を減らすために(ローカル)キャッシュを作成することは非常に一般的です。

4
Telastyn

はい。

理由は簡単です。 always検証コンポーネント(モデル)の呼び出し元(サービス)が適切なデータのクエリを発行し、検証コンポーネント(モデル)にクエリを送信させる代わりに、それをパラメーターとして渡すことが可能自体。

例えば:

public function validateData($database, $dataId)
{
    $data = $database->getData($dataId);
    // do validation
}

次のようにリファクタリングできます。

// caller is responsible for getting data

public function validateData($data)
{
    // do validation
}

これの利点(明らかなテストへの影響は別として)は、アプリケーションでデータの取得を可能な限り「高く」するため、クエリ/キャッシュの最適化を改善できることです。発信者が2つのデータを検証するつもりだとします。単一のクエリを発行し、応答を適切なデータスライスに解析して、それぞれを対応する検証コンポーネントに渡すことが可能です。

2
king-side-slide

私は同意しました。外部サービスの呼び出しに関しても、同じように拒否されます。 @Telastynの発言は、ツールや代替案を深く掘り下げるために少し調査する価値があるために必要な場合があります。

@Telastynはキャッシュについても言及しました。彼の主張に沿って、最初にツールに会うことをお勧めします。ツールの中には、すぐに使えるキャッシュを実装しているものがあります。これは、DBドライバー、WWWアーキテクチャ、ERM、フレームワークなどの場合です。

例えば

given the fact that they could be used multiple times

DB、ドライバー、ERM、またはフレームワークがすでにステートメントをキャッシュしているかどうかを調べます。その場合、最終的に多くの検証クエリがキャッシュされます。しばらくの間。同じことがHTTPリクエストにも当てはまります(適切なヘッダーを設定した場合)。

ただし、無効化の方法、時期、内容がわからないと全体的にキャッシュを操作するのは大変です。

performanceについては、あまりにも早く焦点を合わせることがよくあります。最初に最も簡単なソリューションの実装を開始し、負荷テストを実行して実際のメトリックを取得します。その後、これらはデータに基づいて裏付けられるため、意思決定を行うためのより良い立場になります。

最後に、通信障害になると、パターンと戦略を知る価値があります。たとえば、サーキットブレーカー、再試行、フェイルファスト。これらは、分散コンピューティングの誤りからあなたを救うことはできませんが、実際のソリューションをシンプルで信頼性の高いものに保つことができます。

要約すると、回避できる場合はそれを実行します。それができない場合は、手元にあるリソースに会い、簡単なものを実装してテストしてください。次に、必要に応じて拡張機能や代替策を探します。

1
Laiv

一部のリソースをクエリし、最終的には検証された結果または何らかのエラーを返すコードが必要です。通常、これは非同期になります。

非同期の場合、クエリを実行することはまったく問題なく、検証は別のクエリを実行します。コードのユーザーにとっては、違いはありません。

問題は、レイテンシが2倍になることです。したがって、検証に必要なリソースが常に必要であることがわかっていて、どのリソースが必要かがわかっている場合、両方のクエリを同時に実行し、両方のリソースが到着したときに検証済みの結果を生成する方が効率的ですが少し複雑になります。

あなたが選択の余地のない状況があるかもしれません。顧客番号を照会し、検証のために、顧客が1,000ポンドを超えて借りていないかどうかを確認するとします。先の顧客番号がわからないため、検証では、顧客番号がわかるまで、顧客に関する情報のクエリを待機する必要があります。それはニースではありませんが、あなたがする必要があることを行います。

PS。検証に必要なクエリが失敗することを恐れる必要はありません。データとそれを検証するために必要なものの2つの要求を行います。それぞれが失敗する可能性がありますが、それはまずありません。それぞれの失敗を失敗として報告するだけです。 「データはここにありますが、確認できませんでした」と言うのではなく、「検証済みデータのリクエストに失敗しました」と言います。 (通常、失敗はランダムではありませんが、ライン上のどこかの問題が原因です。最初のクエリが成功した場合、インターネット接続は正常で、DNSサーバーは稼働しており、サーバーがクラッシュしていないため、クエリ検証が成功する可能性がはるかに高くなります)。

0
gnasher729