我以 StackOverflow 为例,因为很明显你知道那个网站,而且我的真实用例非常接近。
所以让我们想象一个简化的 SO 域描述:
最后一条大胆的规则对我来说很重要。
我对 AggregateRoot 的理解是它应该包含用于决定接受或拒绝命令的状态,并且它不应该查询数据库来这样做。它保证了应用程序的一致性。它应该只监听它发出的事件以更新其状态。
现在我认为 SO 域有一个名为 Question 的聚合根。
然后,该问题将处理以下命令:
问题是,当 EditQuestion 被触发时,Question AggregateRoot 如何决定是接受还是拒绝该命令?因为如果您还记得,如果您的声誉 < 1000,如果您尝试编辑另一个用户的问题,该命令应该被拒绝。
对我来说,问题 AR 维护所有用户声誉的列表似乎没有意义,以便能够知道如何根据该命令采取行动。
问题是,当我尝试对我的域建模时,我会一遍又一遍地遇到这个建模问题,而且我总是以一个大的 AggregateRoot 告终
有人可以告诉我我缺少什么并帮助我解决这个问题吗?谢谢
此 question似乎在说我们不应该将授权系统放在域模型中。我同意这对于基于角色的身份验证之类的事情可能是实用的。但是,对我来说,“除非有足够的声誉,否则用户无法编辑”确实是一个 SO 业务规则,那么它怎么会在域之外呢?
重要提示:回答时请考虑您是业务专家 .作为用户,您了解 StackOverflow,并且可以自己猜测 SO 约束是什么。即使你错了,也没什么大不了的:只要为你错误的业务限制提出建议,我就可以了!!!
这不是我第一次问这种问题,结果总是没有答案,只是无休止的讨论。我想知道的是,如果您必须构建此站点,您将如何对 StackOverflow 进行建模,重点是关于要编辑的最低声誉的业务规则。
最佳答案
好吧,IMO 事情很简单(仅在此 SO 场景中)。就是这样我会这样做(显然,其他开发人员可能有不同的方法):
您用“cqrs”很好地标记了问题。在 EditQuestion 处理程序中,我将使用域服务(从 CQRS 的角度来看的查询),它将检查某个用途是否具有所需的点,然后返回真/假。像这样的东西(或多或少是伪代码)
public class CanUserEditQuestionService
{
//constructor with deps\\
public bool Handle(CanUserEditQuestion input)
{
//query the read model, maybe a query object to get us the rep of the user
var rep=getReputation.Get(input.UserId);
//we can have a dependency here which tell us the number of points required for a specific permission
return(rep>=1000);
}
}
如果查询返回 true,则处理程序将对 Question 实体执行更改,即 question.ChangeText() 或 smth(我认为 SO 采用事件溯源方法)。
这里有一个简单的用例,它包含一个概念“问题”、它的命令行为“编辑”和决定谁可以做什么的业务规则。问题是,1000 rep 规则从来不是问题概念定义的一部分,因此它不属于该聚合,即问题是如何编辑的。然而,它是用例本身和应用程序服务的一部分。
我相信你会问我:“如果域查询使用的读取模型在命令模型后面怎么办?”。在这种情况下,它无关紧要,延迟可能最多以秒为单位。这里的主要内容是:业务规则不是问题聚合的一部分,因此它不关心是否立即保持一致。
另一件事是用户代表始终与问题的概念不同,因此处理代表永远不应成为问题聚合的一部分。但它是应用程序服务的一部分。
如果您将应用程序视为一组使用概念(它们本身封装数据和业务约束)做事的用例,则很容易识别哪个是应用程序服务、聚合、域服务等。
关于domain-driven-design - 如何使用 DDD 为 StackOverflow 网站建模,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33858699/