1

現在、DDD における不変式と検証に関する情報を消化しようとしています。私が正しく取得した場合、検証はドメインの問題ではなく、不変条件が発生しないように外部で行う必要があります。一方、ドメイン、特に集合体では、不変条件を適用する必要があります。

私を混乱させるのは、実際には2つのことです。

  • ビジネス ルール (不変条件) を検証と区別する方法
  • DRY原則を尊重する方法

詳しく説明しましょう。Tendersをカバーする Domain Model があるとします。2 つの主要なアクターは、入札プロセスの主催者 ( Organizer ) と入札プロセスの参加者 ( Participant ) です。主催者は、ステージの条件と要件に関する情報を含む入札公告を発行します (たとえば、最高価格の開始)。入札は、いくつかの段階からなるプロセスです。すべてのステージには条件があります。最初のステージは「入札の募集」です。この段階で、参加者はオファーを送信できます (提案)。

2 つの基本的な要件があります。

  1. プロポーザル価格は開始上限価格よりも低くする必要があります
  2. 参加者は、「入札の募集」段階でのみオファーを提出することができます

技術的には、次のように実装できます (詳細は省略します)。

class SubmitHandler
{

    /**
    * Send proposal
    *
    * @param SubmitCommand $command
    */
   public function execute($command)
   {
       $this->isReadyToBeSend($command);

       $participant = $this->participantRepository->find($command->id);
       $participant->submitProposal();

   }

   private function isReadyToBeSend($command)
   {
        $result = $this->validate($command);
        if (!$result->isValid()) {
            throw new ProposalException($result->getMessages()[0]->getMessage());
        }
   }

   public function validate($command)
   {
       // Here we check if starting price is provided 
       // and it is less than starting maximum price 
       // as well as the Call for bids Stage is still active 
       // so that we are allowed to submit proposals

       return Validator::validateForSending($command);
   }

   public function canBeExecuted($command)
   {
       return $this->validate($command)->isValid();
   }
}

// In the UI we send command to the handler
$commandHandler->handle($submitCommand);


class Participant extends AggregateRoot
{
   public function submitProposal()
   {
      // here we must enforce the invariants
      // but the code seems to be almost the same as
      // in the validator in the Command Handler
      $this->isReadyToBeSent();
   }

   // throws exceptions if invariants are broken
   private function isReadyToBeSent()
   {
       $this->isPriceCorrect();
       $this->AreTermsCorrect();
   }
}

上記のすべてを考慮すると、特定のコンテキストでの不変条件と検証の微妙な違いは何ですか? バリデータと集計でコードを複製する必要がありますか? (エンティティにバリデータを挿入したくありません)

どうもありがとうございました。

更新

私は十分に明確ではなかったと思います。簡単に言うと、次の 2 つの点を考慮する必要があります。

  1. ビジネス ルールと不変条件の違い。
  2. SRP に違反する DRY に固執し、その逆も同様です。

最近、私と別の開発者が話し合い、次のような結論に達しました。

  • 不変条件は、ビジネス ルールとは別に従わなければならないルールです。概念的には 2 つの異なるものですが、コードは同じかもしれません。
  • このコンテキストでの DRY 原則は、SRP 原則に準拠するために違反する可能性があります。

私が間違っている場合は修正してください。

4

1 に答える 1

1

私は多くの DDD コードを書いてきましたが、率直に言って、用語についてはまだ確信が持てず、コミュニティのコンセンサスがあるかどうかもわかりません。私は DDD の専門用語の使用をほとんどやめて、あなたが提起しているようなかじる質問がはるかに少なくなったことに気付きました。

したがって、実用的な用語を使用して問題を述べる別の方法は...

クローズド オークションに入札する場合と同様に、入札単価が低い人に高値を付けられると、ユーザーは本当に腹を立てます。ですから、そうならないようにする必要があります。

データ読み取り時の検証

ユーザーが入札を入力するための画面を表示するときは、もちろん、入札が以前の入札よりも大きくなければならず (jQuery 経由など)、入札が受け入れられるのは次の場合のみであることをユーザーに確認することになります。CallForBidsステージで(たとえば、フォームを表示するだけで.

この検証を行う必要があります。そうしないと、ユーザーに非常にくだらない体験を与えることになります。オークションが終了したことを知らされるだけで、入札を入力できるようになります。したがって、データを読み取るときに何らかの方法でこれらのルールを表現する必要があることはわかっています。ただし、重要なことは次のとおりです。

時間 A の情報に基づいて画面に表示する内容が、時間 B にデータを書き込むアクションをユーザーが実行するまでに真になることを保証することはできません。

したがって、ここでの検証は気密である必要はありません。そんなに汗をかかないでください。ロジックを複製して失敗したとしても、書き込みが完了することを 100% 保証することはできません。

データ書き込み時の検証

上記のように、画面上のデータが古くなる: オークションが終了した後にユーザーが入札したか、データが画面に表示されてから最低入札額が上がった可能性があります。したがって、システムがビジネス ルールに違反している (したがって、信頼性が低く、整合性がない) 状態になることを回避するには、次のようにします。

データを書き込むときにビジネス ルールを確認する必要があり、これを同じトランザクション内で行う必要があります。そうしないと、一貫性を保証できません。

(結果整合性もありますが、それはこの回答の範囲外のまったく別のワックスのボールです。)

それで、それはあなたにとって何を意味しますか?

  • あなたのコマンド ハンドラーは、集計/トランザクション境界/今週、人々がそれを呼んでいるものは何でもです。
  • これら 2 つのルールのいずれかが破られている場合、そのコマンドは成功しません (例外をスローする必要があります)。状態を変更しないでください。
  • そのコマンドは成功したと見なされるべきです。つまり、MVC コントローラーから、失敗したコマンドの特別なエラー処理を追加しないでください。コマンドの失敗は非常にまれですが、時々発生します。
  • 内部実装はそれほど重要ではありません。各ルールを適用するために 1 つずつ、2 つのクラスが必要な場合は、すぐに行ってください。 ルールが単一のトランザクション内で適用される限り、それはビジネスにとって重要ではありません。そして、それがあなたが焦点を当てるべきものです。
  • そして、それもテストする必要があります-コマンドのパラメーターがシステムの状態に対して無効な場合に例外がスローされることだけです。(他のハンドラーをトリガーするイベントを発行する場合にのみ、成功をテストします。)

それが解決することを願っています。

于 2014-03-28T23:58:44.200 に答える