如何在DDD中设计多阶段任务



大约一年前,我们已经重构了后端代码库,使其架构与DDD更加一致,而且我们还在大多数服务中实现了Hexagonal architecturePorts & Adapters模式的组合。到目前为止,我们的大多数用例都非常简单明了;因此,使用简单的实体和CCD_ 4处理程序等可以很好地工作。但随着软件功能的增长,我们现在需要更复杂的结构。

所以我们想要实现一些功能,我能给出的最好的描述是multistage tasks。例如,我们对注册和登录有两步验证:用户输入他们的信息,然后(通过短信(向他们发送验证码,他们必须输入验证码才能获得令牌。或者对于某些功能,我们需要获得用户的驾驶执照和照片等,然后管理员必须验证它们并向用户发送通知,然后用户必须进行付款,等等

我们观察到,我们不能像对待简单的entitiesCQRS模式那样对待这类功能(任务?(,但我们也未能找到一种好的、惯用的方法来实现这些功能。因此,我们正在寻求一些信息和指导方针来帮助我们

广泛的方法是将长期运行的流程建模为传奇,它可以跟踪其状态(持久性:事件源在这里通常非常有用,因为持久化的事件几乎免费为您提供审计日志记录和可观察性(,同时向其他服务发送命令(以及接收命令(。传奇可以从故障中自主恢复,使系统处于定义的状态(理想情况下为良好/功能状态,尽管有时让系统不可操作并发出需要修复的信号可能很有用…(

例如,您可以将未经验证的用户建模为一个传奇,其中的状态可能是:

  • 使用配置文件信息创建,不发送短信
  • 短信已发送,正在等待代码(保留配置文件信息(。。。可以从中发送带有新代码的SMS,但这会使旧代码无效
  • 已验证(可能不需要验证用户ID以外的配置文件信息(

在前两种状态中的任一状态中;发送验证SMS";命令是有效的并且将转换到第二状态(在生成代码并发送SMS之后(。在第二状态中;验证来自SMS的代码";命令可以被验证,并且如果有效,则转换到第三状态(在转发配置文件信息以使得可以创建具有该配置文件信息的已验证用户之后(。

你基本上可以把一个传奇看作一个"传奇";todo列表";(DDD附近的一些学校更喜欢这个术语(。就像在很多DDD中一样,想想如何在不使用计算机的情况下解决问题。对于身份验证过程,你可能会有一张纸,上面有一份清单,最终会附在用户的文件中;这类过程已经存在/蓬勃发展了很长时间,因此有充分的理由将它们的各个方面纳入我们的软件设计中。

在某种意义上,大多数聚合可以被视为有限状态机。

聚合通常涉及相当复杂的工作流,这些工作流在许多(但有限(状态中循环,每个转换都与定义良好的业务规则相关联。

在您的示例中,User记录在REGISTED、VERIFIED、ADMIN APPROVED、PAID等状态之间移动。这也使您可以自由地从任何状态转换到任何状态,允许您随着时间的推移添加新规则(从不付款的折扣用户、不必验证的受邀用户等(

状态机内置在聚合中。命令启动转换。命令处理程序调用执行转换的聚合方法,并在持久化它们(以及引发事件(如果有的话((之前更改聚合状态。

顺便说一句,这是一个很好的启发式方法,可以发现你的应用程序是否适合使用DDD/CQRS模式。对于CRUD操作这样的简单情况,状态机是没有意义的。大多数CRUD记录将在ACTIVE-ARCHIVED或CREATED-UPDATED-DELETED状态之间循环。

阅读更多:

  • 有限状态机-维基百科
  • 重构大师状态设计模式
  • 使用状态机-Richard Clayton

最新更新