我们将从一个可靠的消息传递和持久性基础设施开始。我们采取的方法是从简单的先开始,并根据需要建立基础设施,这意味着我们在旅程中积累了技术债务。我们还发现,采用这种方法意味着在某些情况下,我们对基础设施的选择影响了我们实现领域的方式。
Jana(软件架构师)发言:
从旅行的角度来看,如果我们从一个坚实的基础设施开始,我们将有时间处理领域中一些更复杂的部分,比如等待列表(Wating-list)。
从一个可靠的基础设施开始也能使我们更早地开始性能测试。我们还将进一步研究其他人如何在基于CQRS的系统上进行性能测试,并在其他系统上寻找性能基准,比如Jonathan Oliver的EventStore。
我们采取这种方法的原因之一是我们从顾问那里得到的建议:“不要担心基础设施。”
更多地利用基础设施的能力从一个坚实的基础设施开始也将允许我们更多地利用基础设施的能力。例如,当我们发布一个事件时,我们使用消息发起者的ID作为会话ID在Azure服务总线传递,但从系统处理事件的部分来看,这并不总是最好的使用会话ID的方式。
作为其中的一部分,我们还将研究基础设施如何支持其他最终一致性的特殊情况,如时间一致性、单调一致性、“read my writes”和自我一致性。
我们想探讨的另一个想法是使用基础设施来支持版本之间的迁移。我们可以考虑使用基于消息的流程或实时通信流程来协调把新版本上线,而不是针对每个版本以特定的方式处理迁移。
采用更系统的方法来实现过程管理器我们在旅程的早期就开始实现我们的过程管理器,并且仍然在强化它,并确保它的行为在旅程的最后阶段是幂等的。同样,从为流程管理人员提供一些坚实的基础设施支持开始,使他们更有弹性,这将对我们有所帮助。但是,如果我们要重新开始,我们也会等到过程的后期再实现流程管理器,而不是直接开始。
在旅程的第一阶段,我们开始实现RegistrationProcessManager类。第3章“订单和注册限界上下文”描述了初始实现。在旅程的每个后续阶段,我们都对流程管理器进行了更改。
以不同的方式划分应用程序在项目开始时,我们会更仔细地考虑系统的分层。我们发现我们的划分的方式是把应用程序分到web角色和工作者角色中,这在第4章“扩展和增强订单和注册限界上下文“中进行了描述。但这不是最优的,在旅程的最后阶段,在第7章“增加弹性和优化性能”中,作为性能优化的一部分,我们对架构做了一些重大改变。
例如,在旅程的最后阶段,作为重新组织的一部分,我们在web应用程序中引入了同步命令处理,同时引入了已存在的异步命令处理。
以不同的方式组织开发团队我们学习CQRS模式的方法是迭代开发、回顾、讨论,然后重构。但是,我们可以通过让几个开发人员在相同的特性上独立工作,然后比较结果,从而学到更多。这可能揭示了更广泛的解决方案和方法。
评估领域域和限界上下文是否适合使用CQRS模式我们希望从一组更清晰的启发开始(如本章前面概述的启发),以确定特定的限界上下文是否会受益于CQRS模式。如果我们关注领域中更复杂的地方,比如等待列表(Wating-list),而不是订单、注册和支付的限界上下文,我们可能会学到更多。
性能计划我们将在旅程的早期处理性能问题。我们尤其要:
提前设定明确的性能目标。
在过程中更早地运行性能测试。
使用更大更实际的负载。
我们没有做任何性能测试,直到旅程的最后阶段。有关我们发现的问题以及如何解决这些问题的详细讨论,请参见第7章“添加弹性和优化性能”。
在旅程的最后阶段,我们在服务总线上引入了一些分区,以提高事件的吞吐量。此分区是基于事件的发布者完成的,因此由同一个聚合类型发布的事件将发布到同一个Topic。我们希望把当前使用一个Topic的扩展到使用多个Topic,可能会基于消息中OrderID的hash进行分区(这种方法通常称为分片)。这将为应用程序提供更大的扩展。
以不同的方式思考UI我们认为UI与读写模型交互的方式,以及它处理最终一致性的方式都很好,并且满足了业务需求。特别是,UI检查预订是否可能成功并相应地修改其行为的方式,以及UI允许用户在等待更新读模型时继续输入数据的方式。有关当前解决方案如何工作的更多细节,请参见第7章“添加弹性和优化性能”中的“优化UI”一节。