DDDの例外


11

私はDDDを学んでいて、特定の状況で例外をスローすることを考えています。私はオブジェクトが悪い状態に入ることができないことを理解しているので、ここで例外は問題ありませんが、多くの例では、たとえば、データベースに電子メールが存在する新しいユーザーを追加しようとした場合にも例外がスローされます。

public function doIt(UserData $userData)
{
    $user = $this->userRepository->byEmail($userData->email());
    if ($user) {
        throw new UserAlreadyExistsException();
    }

    $this->userRepository->add(
        new User(
            $userData->email(),
            $userData->password()
        )
    );
}

したがって、この電子メールを持つユーザーが存在する場合、アプリケーションサービスで例外をキャッチできますが、try-catchブロックを使用してアプリケーションの操作を制御するべきではありません。

これに最適な方法は何ですか?


1
ドメインサービス(ハンドラー)が例外をスローするようにしても問題ありません。
アンディ

回答:


20

問題空間の簡単な復習から始めましょう。DDDの基本的な原則の1つは、ビジネスルールを適用する必要のある場所にできるだけ近づけることです。これは非常に重要な概念であり、システムをより「まとまり」のあるものにします。ルールを「上向き」に移動することは、一般的に貧血モデルの兆候です。ここで、オブジェクトは単なるデータのバッグであり、ルールには適用されるデータが注入されます。

貧血モデルは、DDDを使い始めたばかりの開発者には非常に理にかなっています。メールを検証するために必要な情報が注入されるUserモデルとを作成EmailMustBeUnqiueRuleします。シンプル。エレガント。問題は、この「一種の」思考が根本的に手続き型であるということです。DDDではありません。何十ものRulesきちんとラップされてカプセル化されたモジュールが残されてしまいますが、いつどこで適用されるかが明確ではないため、変更できなくなるところまで完全にコンテキストがありません。それは理にかなっていますか?それは可能という自明のこと EmailMustBeUnqiueRuleの作成時に適用されますUserが、何についてUserIsInGoodStandingRule?。ゆっくりだが確実に、抽出の粒状化Rulesそれらのコンテキストから外れると、理解しにくい(したがって変更できない)システムが残ります。ルールは、実際のクランチ/実行が非常に詳細であり、モデルがフォーカスを失い始めた場合にのみカプセル化する必要があります。

今すぐあなたの特定の質問へ上:持つ問題Service/ CommandHandlerスローExceptionビジネスロジックは、自分のドメインのうち、(「上向き」)リークし始めているということです。なぜ、あなたのんService/ CommandHandler電子メールを知る必要は一意である必要がありますか?アプリケーションサービスレイヤーは通常、実装ではなく調整使用されます。この理由は、ChangeEmailメソッド/コマンドをシステムに追加した場合に簡単に説明できます。これで、メソッド/コマンドハンドラーの両方に独自のチェックを含める必要があります。これは、開発者がを「抽出」したくなるかもしれない場所EmailMustBeUniqueRuleです。上で説明したように、そのルートには行きたくありません。

追加の知識を駆使すると、より多くのDDD回答が得られます。電子メールの一意性は不変であり、Userオブジェクトのコレクション全体に適用する必要があります。ドメインに「Userオブジェクトのコレクション」を表す概念はありますか?たぶん私がどこに行くのかわかると思います。

この特定のケース(およびコレクション全体で不変条件を適用することを含む多くのケース)では、このロジックを実装するのに最適な場所はRepositoryです。これはRepository、この種の検証を実行するために必要な追加のインフラストラクチャ(データストア)も "知っている" ため、特に便利です。あなたの場合、私はaddメソッドにこのチェックを入れます。これは理にかなっていますか?概念的にはUser、システムにを追加するのはこの方法です。データストアは実装の詳細です。


どういう意味Moving rules "upwards" is generally a sign of an anemic modelですか?アプリケーション層にとって上向きの意味ですか?またはドメインモデルに?
Anyname Donotcare

1
「上向き」とは、アプリケーション層に向かうことを意味します(階層化アーキテクチャーを考えてください)。上記で触れましたが、ルールを上に移動する理由は、貧血モデルの兆候であり、コアドメインモデルを持つという目的全体に反する方法でデータと動作の分離を表すためです。電子メールの検証が電子メールの送信とは別のモジュールでEmail行われる場合、モデルは送信前に不変量が検査されるデータのバッグでなければなりません。参照:softwareengineering.stackexchange.com/questions/372338/...
キングサイドスライド

2
ドメインロジックをリポジトリに移動するのは間違っています。ドメイン層のルートを集約してドメインルールを適用する必要があります。
アラッシュ

1
@Arash Setの検証はトリッキーであり、DDDではうまく機能しないことがよくあります。一部のプロセスが機能することを検証する前に、そのプロセスを試行する(を追加するUser)か、この特定の種類の不変条件がドメインに適切にカプセル化されないことを受け入れるかのどちらかを選択できます。前者は、データと動作の分離を表しており、その結果、手続き型のパラダイムになります。これは理想的ではありません。検証はデータの周りではなくデータとともに存在する必要があります。さらに、この1つのルールのチェックのみを行うドメインサービスを作成することにはどのようなメリットがありますか?表面的には、このサービス...
キングサイドスライド

1
@ArashカップルあなたのRepositoryUserし、この不変、したがって、あなたはとにかくために推進している純粋主義者のビジョンを達成していません。リポジトリの実装はドメインの一部であるため、特定の責任を与えることができます。
キングサイドスライド

0

アプリケーションのすべての層に検証を課すことができます。アプリケーションに依存するルールを課す場所。

たとえば、エンティティはビジネスルールを表すメソッドを実装し、ユースケースはアプリケーションに固有のルールを実装します。

Gmailのような電子メールサービスを構築している場合、「ユーザーには一意の電子メールアドレスが必要です」というルールはビジネスルールであると主張できます。

新しいCRMシステムの登録プロセスを構築する場合、このルールはユースケースの一部である可能性が高いため、このルールはユースケースで実装するのが最適です。さらに、ユースケーステストでリポジトリの呼び出しを簡単にスタブできるので、テストが簡単になる場合もあります。

追加のセキュリティのために、このルールをリポジトリに適用することもできます。

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