データベースのコンテンツに依存するドメインモデルルールをどこで検証しますか?


10

私は、管理者がフィールドを含むフォームを定義できるシステムに取り組んでいます。定義されたフォームは、システムにデータを入力するために使用されます。フォームは、GUIを介して人間が入力する場合もあれば、別のシステムから報告された値に基づいて入力される場合もあります。

各フィールドについて、管理者はフィールドに許可される値を制限する検証ルールを定義できます。検証ルールは、「フィールドに入力された値はTrueまたはFalseである必要があります」から「フィールドに入力された値はデータベースのテーブルBの列Aに存在している必要があります」まで、任意です。管理者はいつでもフィールドの検証ルールを変更できます。

このシナリオでは、各フィールドが正しく入力されていることを検証するのに最も適した場所は何だと思いますか?私は現在、主に2つのアプローチを考えています。

オプション#1:ドメインモデルで検証する

各フィールドオブジェクトには、管理者が指定した検証ルールが含まれます。Fieldオブジェクトには、IValidatorへの参照も含まれます。フィールドの値を設定しようとすると、フィールドは指定された値と検証ルールをIValidatorに渡します。指定された値が有効でない場合、ValidationExceptionがスローされ、他のシステムへのGUI /インターフェイスで適切に処理されます。

長所:

  • 検証ルールに違反するフィールドが誤って割り当てられたフィールドに対する強力な保護

短所:

  • データアクセスレイヤーは、検証をバイパスし、現在の検証ルールに違反するフィールドを構築できる必要があります。管理者がフィールドの入力規則を変更しても、何年も前に入力されたフォームをレンダリングするときなど、古いデータに基づいてフィールドオブジェクトを構築できる必要があります。これは、フィールドを保存するたびに現在の検証ルールを保存することで解決できる可能性があります。

  • この設計では、フィールドモデルはIValidatorを介してデータアクセスレイヤー/リポジトリに間接的にリンクしています。ドメインモデルへのサービス/リポジトリの挿入は、一般的には嫌われているようです。

オプション#2:サービスで検証する

フィールドの値を設定するすべての試行が、検証ルールが確実に実行されるサービスを通過するようにしてください。検証ルールに違反している場合は、ValidationExceptionをスローします。

もちろん、以前はDBに永続化されていたFieldオブジェクトを作成する場合、データアクセス層はサービスを使用しません

長所:

  • 「サービス/リポジトリをドメインモデルに挿入しない」という考え方に違反していない。

  • フィールドを永続化するときに、現在の検証ルールを永続化する必要はありません。サービスは、フィールドの現在の検証ルールを単純に検索できます。履歴データを見ると、フィールドの値は変更されません。

短所:

  • サービスを使用してフィールド値を設定する必要のあるすべてのロジックが実際にそうであるとは限りません。私はこれを大きな欠点だと考えています。誰かが「thisField.setValue(thatField.getValue())」を書いているだけで、thisFieldの検証ルールに違反する可能性があります。これは、データアクセスレイヤーがフィールドを永続化しようとしているときに、フィールドの値が入力規則と一致するようにすることで軽減できる可能性があります。

私は現在、オプション#2よりもオプション#1を好みます。これは主にこれをビジネスロジックと見なしており、オプション#2がシステムに不正なデータを導入するリスクが大きいと感じているためです。どちらのオプションを選択しますか、またはこのシナリオに適合する、説明した2つのオプションよりも優れた別のデザインはありますか?

編集(検証の複雑さ)

現在のところ、検証ケースは比較的単純です。フィールド値は、数値、日付、時刻付きの日付、またはデータベース列の既存の値である必要があります。ただし、時間の経過とともに複雑さが徐々に増加すると思われます。たとえば、検証ソリューションは国際化を念頭に置いて構築する必要があります。日付などはロケール固有の構文で入力できます。

ここでは、オプション1に進むことを決定しました。ドメインモデルに多くの責任を割り当てないように注意してください。同様の状況に直面している人は、関連する質問を確認することもできます。階層化アーキテクチャでの検証と承認およびデータ入力検証-どこですか?いくら?


モデルの作成は、すべての検証でうまく機能します。ただし、フォームを編集または表示する場合は、検証も実行されます。これは、空のフィールドまたは無効な値を持つフィールドに対して例外をスローします-おそらくdbで変更されたか、Excelからロードされました。予想される解決策は、更新時にフォームを表示して、管理者がこれらのフィールドを修正できるようにすることです。
tunmise fasipe 2015

回答:


4

検証はどのくらい複雑ですか?多くの場合、検証では、フィールドとビジネスルールを組み合わせて、フィールドを正確に評価する必要があります。

検証が複雑になるほど、オプション2は難しくなり、パフォーマンスが低下します。

もちろん、データ層は永続化時に検証サービスを呼び出すことができます。これは、ルールの変更が原因でデータが無効な状態になるという奇妙な状況に役立ちます。

コメントする価値のあるもう1つの項目は、なんらかのqaサイクルなしで検証ルールを変更できることです。しかし、それは別のスレッドのトピックです。

上記の情報を考えると、オプション1は、規律を維持し、検証と永続性を分離していると仮定すると、最も柔軟性があるようです。


0

レイヤーが不足している可能性があります。アプリケーションの詳細(要件、アーキテクチャなど)がわからない場合は、クライアント(だれでも)のようなものを実行します->アプリケーションサービス->ドメインモデル

アプリケーションサービスレイヤーは、リポジトリおよびビジネスロジックを含むドメインモデルと対話できます。だからあなたは次のようなものを持つことができます:

FieldUpdateService >> updateField(fieldId, newValue)
  List<FieldRule> rules = this.rulesRepository.findRulesFor(fieldId)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(rules,newValue)
    fieldRepository.save(field)
  catch 
    // manage error

FieldとそのFieldRulesの間に関係があり、JavaでHibernateのようなORMを使用する場合は、次のことだけを実行します。

FieldUpdateService >> updateField(fieldId, newValue)
  Field field = this.fieldRepository.find(fieldId)
  try 
    field.updateValue(newValue)
    fieldRepository.save(field)
  catch 
    // manage error

Field >> updateValue(newValue)
  for rule in rules
     if !rule.isValid(newValue)
        throw ValueNotAllowedException
  this.value = newvalue

ORMは、要求したオブジェクトのグラフをクエリしてインスタンス化するためです。

誰かができることについての疑問について

thisField.setValue(thatField.getValue()) "およびthisFieldの入力規則は、誰も賢明でないと違反する可能性があります

誰かが次のように書くこともできます:FieldRule alwaysReturnTrueRule = new FieldRule {isValid(newValue){return true; }} field.updateValue( "uncheckedValue"、alwaysReturnTrueRule)これはあいまいな例ですが、何を言っても、コードの不正使用からユーザーを保護するものは何もありません。おそらく、適切なドキュメンテーションとコミュニケーションが向かい合っています。コードの悪用からあなたを守るものは何もないと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.