CQRS和同步操作(如用户注册)

时间:2013-04-27 09:54:41

标签: domain-driven-design cqrs domain-events

我正在采用DDD概念来设计我们的下一个项目,更具体地说是CQRS。

在阅读了很多东西之后,我现在正试图实现一个简单的概念验证。

事情是我开始后我就被卡住了:p

我正在尝试将此方法应用于简单的用户注册过程,其中的步骤是:

  • 用户填写注册表格&提交请求
  • 该应用创建用户
  • 该应用对用户进行身份验证(自动登录)
  • 该应用向用户发送验证电子邮件
  • 应用程序将用户重定向到其他地方,并显示确认消息

从实施的角度来看,到目前为止我得到的是:

  • 控制器操作将请求数据映射到RegisterCommand对象
  • 控制器操作要求命令总线处理RegisterCommand
  • 命令处理程序(UserService)“register”方法创建一个新的User对象(无论是通过新命令还是工厂对象)
  • 该模型引发了RegisterEvent
  • 命令处理程序要求存储库存储新用户对象

就是这样,控制器动作不知道任何一个。

所以,我的猜测是,因为这个上下文中的所有内容都必须同步完成(除了发送电子邮件),我可以使用直接/同步命令总线,并在控制器操作中,在命令总线调用之后,我可以查询只读用户(查询数据库),如果它存在则假设一切顺利,那么我可以给用户一个确认消息。

由事件处理程序处理自动登录过程。

假设这是正确的,如果出现问题怎么办,如何通知用户正确的信息?

我们可以在互联网上找到的文章中经常使用一个常见的例子:客户使用过期的信用卡支付订单。系统接受请求,通知用户一切正常,但用户在几分钟后收到一封电子邮件,告诉他无法处理他的订单。

嗯,在许多情况下,这种情况是可以接受的,但对于其他情况,这是不可能的。那么处理这些用例的例子在哪里? :P

谢谢!

2 个答案:

答案 0 :(得分:3)

我认为这个注册用例比您认为的订单用例更接近付款。

大多数CQRS思想领袖建议在发出命令之前在阅读方面进行验证,从而使您的命令获得更高的成功概率。

如果验证在读取方面失败,您知道如何处理 - 在您发送注册命令之前让用户选择另一个名称。如果验证成功,发送命令 - 现在你说的话可能是几百微秒,其中一个用户可以进入并在你验证命令和发送它之间采用相同的用户名。极不可能。

在非常罕见的情况下,当这种情况发生时,您的行为与过期的信用卡示例相同 - 下次用户登录时,您会向他们提供说明和表单以提交新的用户名 - 或者向他们发送一封电子邮件,说“嘿 - 其他人拥有该用户名,请点击此处选择新用户名”。为什么这样做?因为您拥有该用户的唯一ID。

查看Twitter等用户注册页面。一旦你输入一个用户名,它就会做一个小的Ajax调用并说“不,这是采取”或“这个是好的!”这是预验证。

我希望这有帮助!

答案 1 :(得分:1)

人为的例子的问题在于你可以改变你对“域”如何运作的看法,所以特别是在讨论这个例子时几乎没用。你似乎放弃的基本前提是我们必须假设事情才会发挥作用。其他一切都是关于风险和缓解风险。举个例子,如果我问你,如果我在100000中丢失了1个用户注册怎么办?如果我失去了十分之一怎么办?为什么会这样?那个时候我有更大的问题吗?当系统重新上线并按预期工作时,未来用户是否可能再次注册?那会是什么时候?如果我们监控我们的服务质量并阻止用户注册,因为我们无法保证他们与我们的品牌相关联的质量,该怎么办?如果服务器爆炸或数据中心被破坏怎么办?我们想要保护吗?你看,没有正确的答案。只是各种灰色阴影。那么我们如何降低风险呢?我们可以使事情同步,但这只是在有限时间点的保证。如果我必须恢复2小时的备份(例如因为磁盘已损坏),该怎么办?这是2个小时的注册用户丢失(也许)。这些事情发生了......我只想指出我认为是虚假安全感的相对性。减轻它,投资你不能承受的损失,确保你有一个良好的审计线索。可能不是你想要的答案......