我目前正在尝试消化与DDD中的不变量和验证相关的信息。如果我得到正确的验证不是域的关注,应该在外面完成,以防止不变量发生。另一方面,必须在域中强制执行不变量,特别是在聚合中。
令我困惑的是两件事:
让我详细说明一下。考虑我们有一个涵盖招标的域模型。两个主要参与者是招标流程组织者(组织者)和招标流程参与者(参与者)。 主办单位发布招标公告,其中包含有关舞台条款和要求(例如起始最高价格)的信息。 投标是一个由多个阶段组成的过程。每个阶段都有自己的条款。第一个阶段是“征集出价”。在阶段期间,参与者可以发送其优惠(提案)。
有两个基本要求:
从技术上讲,我们可以像这样实现它(省略细节):
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();
}
}
考虑到上面提到的一切,在给定的上下文中不变量和验证之间的细微差别是什么?代码是否应该在验证器和聚合中重复? (我不想将验证器注入实体)
非常感谢。
更新:
我想我不够清楚。简而言之,我有两件事需要考虑:
我和另一位开发人员最近进行了讨论,我们得出的结论如下:
如果我错了,请纠正我。
答案 0 :(得分:1)
尽管我已经写了很多DDD代码,但坦白地说我仍然不确定术语,我不确定是否有社区共识。我基本上已经停止使用DDD的行话,发现我没有像你正在摆出的那样啃着很多问题。
另一种使用实际术语陈述问题的方法是......
出价较低的人出价会让你感到沮丧 用户,以及对已结束拍卖的出价。所以我们需要确保不会发生这种情况。
阅读数据时的验证
当您显示用户输入出价的屏幕时,您当然会对用户进行一些验证,即出价必须大于之前的出价(例如通过jQuery)并且出价只能在CallForBids
阶段被接受(例如,仅显示表格。
您必须进行此验证,否则您将为用户提供非常糟糕的体验 - 允许他们输入出价仅被告知拍卖已结束。所以我们知道你在阅读数据时必须以某种方式表达这些规则。然而,关键是这个:
您不能保证您在屏幕上显示的内容基于此 A时的信息在用户发布时为真 执行在时间B写入数据的操作。
所以这里的验证不一定是密不透风的。不要那么多出汗。即使您通过复制逻辑搞砸了,我们也无法100%保证写入仍会通过。
撰写数据时的验证
我们在上面观察到屏幕上的数据变得陈旧:用户可能在拍卖结束后输入了出价,或者自屏幕上显示数据以来最低出价可能已经上升。因此,为了避免状态违反业务规则的系统(因此不可靠且没有完整性)......
在编写数据和时,您必须检查业务规则 您必须在同一交易中执行此操作,否则您不能 保证一致性。
(最终也有一致性,但这是另一个蜡的范围,超出了这个答案的范围。)
那么这对你意味着什么?
希望能够解决它。