5

ddd の検証アプローチについて質問があります。私はそれについて非常に物議を醸す意見を読みました。これは実体の外で生きるべきだと言う人もいれば、実体の中に置くべきだと言う人もいます。私は従うことができるアプローチを見つけようとしています。

例として、電子メールとパスワードを持つ User エンティティがあるとします。ユーザーにはメソッド Register(email, password) があります。電子メールとパスワードの検証はどこに配置する必要がありますか? 私の個人的な意見では、Register() メソッド内にある必要があります。しかし、そのようなアプローチは、 User クラスを検証のもので混乱させる可能性があります。1 つの方法として、電子メールとパスワードのルールを個別のポリシー オブジェクトに抽出し、Register() メソッドから呼び出す方法があります。

DDD の検証アプローチについてどう思いますか?

4

4 に答える 4

6

まず第一に、検証は、検討する必要があるさまざまなコンテキストの一部が原因で、やや滑りやすいテーマだと思います。最終的に、さまざまなアプリケーション層で実行される検証ルールが存在します。少なくとも、ドメイン オブジェクトには標準的なガードが必要です。Reigsterこれらは、適切に設計されたオブジェクトの一部であり、メソッドに対するあなたの意見に適合する必要がある、定期的な前提条件と引数のチェックです。lazyberezovsky が述べたように、これはオブジェクトが無効な状態になるのを防ぐためです。私はこれについて常に有効な学校の側にいます。エンティティを無効な状態で永続化する必要がある場合は、この目的のために新しいエンティティを作成する必要があると思います。

ただし、このアプローチだけの問題の 1 つは、これらの検証ルールをプレゼンテーション層などの他の層にエクスポートする必要があることが多いことです。さらに、プレゼンテーション層では、ルールを異なる形式にする必要があります。それらはすべて一度に表示され、潜在的に別の言語 (JavaScript などの別の言語に翻訳されて、クライアント側のフィードバックがすぐに得られるようにする必要があります) に表示される必要があります。クラスによって発生した例外から検証規則を抽出しようとするのは、困難または非現実的です。または、検証ルールをプレゼンテーション層で再作成することもできます。これははるかに単純で、DRY に違反する可能性がありますが、ルールをコンテキストに依存させることができます。特定のワークフローでは、エンティティ自体によって適用されるものとは異なる検証ルールが必要になる場合があります。

説明したアプローチのもう 1 つの問題は、エンティティの範囲外に存在する検証規則が存在する可能性があり、これらの規則を他の規則と一緒に統合する必要があることです。たとえば、ユーザー登録の場合、電子メール アドレスが一意であることを確認するという別のルールがあります。該当するユース ケースをホストするアプリケーション サービスは、通常、このルールを適用します。ただし、このルールをプレゼンテーションなどの他のレイヤーにエクスポートできる必要もあります。

全体として、エンティティは常に有効であるべきだと考えているため、エンティティ自体にできるだけ多くの制約チェックを配置しようとしています。場合によっては、例外を発生させ、外部レイヤーにエクスポートできるようにルール フレームワークを設計することができます。また、レイヤー全体でルールを単純に複製する方が簡単な場合もあります。

于 2013-03-15T16:42:39.863 に答える
3

実際には、ユーザーの有効性はコンテキストに依存します。ユーザーは有効 (名前と電子メールは有効) ですが、登録操作を実行できない場合があります。なんで?同じ名前の既存のユーザーが存在する可能性があるためです。したがって、あるコンテキストでは有効に見えるユーザーが、登録コンテキストでは無効になる可能性があります。

そのため、検証の一部をエンティティまたは値オブジェクト (Mail オブジェクトなど) に移動して、エンティティの明らかに無効な状態 (null名前を持つユーザーなど) を回避しました。ただし、コンテキスト依存の検証はそのコンテキストに存在する必要があります。したがって、ユーザーを登録している場合:

Mail mail = new Mail(blahblahblah); // validates if blah is valid email
User user = new User(name, mail); // validates if name is valid and mail not null
// check if there already exist user with such name or email
repository.Add(user);

Registerまた、そのメソッドは何らかのドメイン サービス (MembershipService など) のメソッドであるべきだと思います。これは、何らかのリポジトリを確実に使用する必要があるためです。

于 2013-03-15T15:56:53.427 に答える
2

例として、電子メールとパスワードを持つ User エンティティがあるとします。ユーザーにはメソッド Register(email, password) があります。電子メールとパスワードの検証はどこに配置する必要がありますか?

DDD に従っている場合、メール アドレスとユーザー名はドメインの重要な概念であるため、エンティティとして表す必要があります。その場合、電子メール アドレスの検証はEmailAddressエンティティに存在し、ユーザー名の検証はUsernameエンティティに配置する必要があります。

擬似コードの例:

class EmailAddress
{
    Constructor(string email)
    {
        if (email.DoesNotMatchRegex("\w+@\w+.\w{2,3}"))
            throw error "email address is not valid"
    }
}

class Username
{
    Constructor(string username)
    {
        if (username.length < 6)
            throw error "username must be at least 6 characters in length"
    }
}

class User
{
    Register(Username username, EmailAddress email)
    {
        if (username == null)
            throw error "user must have a username"

        if (email == null)
            throw new error "user must provide email address"

        // At this point, we know for sure that the username and email address are valid...
    }
}
于 2013-03-15T17:58:06.177 に答える