私は、管理者がフィールドを含むフォームを定義できるシステムに取り組んでいます。定義されたフォームは、システムにデータを入力するために使用されます。フォームは、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に進むことを決定しました。ドメインモデルに多くの責任を割り当てないように注意してください。同様の状況に直面している人は、関連する質問を確認することもできます。階層化アーキテクチャでの検証と承認およびデータ入力検証-どこですか?いくら?。