经验分享:从CRUD重构到事件源ES的有状态系统 -Stitcher.io


项目是我们正在进行的较大项目之一。最后,它将为成千上万的用户提供服务,处理大量的财务交易,并且需要即时创建独立于租户的安装。
一个关键要求是,可以轻松地报告和跟踪整个历史记录,即企业的核心产品订购流程。同时,也拥有一个易于使用的产品管理系统。

CRUD系统
首先讨论一种如何基于CRUD系列的设计方法:
在这样的系统中,可能会有两个域组:Product和Order,以及两个使用这两个域的应用程序:an AdminApplication和a CustomerApplication。

在先前的项目中成功使用了该架构之后,我们可以简单地依靠它一段时间。但是,它有一些缺点,特别是对于这个新项目:我们必须牢记,报告和历史记录跟踪是订购过程的关键方面。我们希望在我们的代码中如此对待它们,而不仅仅是代码的次要功能或副作用。
例如:我们可以使用活动日志包来跟踪有关订单发生的“历史消息”。我们还可以开始在订单和历史记录表上编写自定义查询以生成报告。

事件溯源EventSourcing
自然地,我们着眼于事件源,这是一种可以满足上述要求的出色而灵活的解决方案。但是,没有什么是免费的:事件源需要编写很多额外的代码才能完成其他简单的事情。在通常需要简单的CRUD操作来处理数据库中数据的地方,现在您不得不担心调度事件,使用投影仪projectors和reactors处理事件,同时始终牢记版本控制。
尽管很明显,事件源系统可以解决许多问题,但即使在不会增加任何价值的地方,它也会带来很多开销。
如果我们决定Orders使用事件源,而Orders依赖于Products模块中的数据,如果Products不实现事件源,则我们将无法重建Orders状态,因此,我们可以通过事件来源获取所有信息,或者为该问题找到解决方案。

事件源所有的东西吗?
通过在我们的一些业余项目中使用事件源,我们痛苦地意识到,我们不应该低估它所增加的复杂性。此外,格雷格·扬(Greg Young)表示,整个系统的事件溯源通常不是一个好主意-他对事件采购的误解有完整的论述,值得一看!
对我们来说很明显,我们不想为整个应用程序提供事件源。这样做根本没有任何意义。唯一的选择是找到一种将有状态系统与事件源系统结合在一起的方法,但是令人惊讶的是,在这个主题上我们找不到很多资源。
尽管如此,我们还是进行了一些劳动密集型研究,并设法找到了我们问题的答案。答案不是来自事件溯源社区,而是来自完善的DDD惯例:有界的上下文。
如果我们想要的Products模块是一个独立的,有状态的系统,我们必须清楚地尊重Products和Orders之间的界限,而不是一个整体单体的应用程序,我们将不得不将这两个模块视为两个单独的上下文,包括单独的服务,仅允许以保证该Order上下文永远不会以无效状态结束的方式相互交谈。
将其Products视为通过REST API访问的单独服务。即使API脱机或对其数据结构进行了更改,我们也可保证事件源应用程序仍然可以正常工作。

更多详细点击标题见原文。