我们如何从DDD中受益? 第二部分| Shinetech软件


“做正确的事;做正确的事”在我脑海中有机地出现。简单的CRUD项目变得越来越不能胜任,程序员的速度很难提升,他们的工资也很难提升。我急于解决这个问题。然后有一天我看到了这样一句话:我选择做一件事不是因为它很简单,而是因为它很难。我对这些话很有动力,我不能停止思考“简单”“复杂”的“麻烦”。然后我想出了我需要做的事情:
1.做正确的事
2.做正确的事
做难事

然后我开始在互联网上搜索“复杂”“软件”等关键词,一本名为“领域驱动设计”的书吸引了我的眼球。我很久以前就听说过Domain-Driven Design,对我来说真正有吸引力的是小标题 - “解决软件核心的复杂性”。我不得不说,在我仔细阅读本书之后,书中提到的战略设计确切地提供了解决复杂业务的解决方案:无处不在的语言,有界上下文,设计是代码,代码是设计等等。我相信这是解决的逻辑艰难的事情,做正确的事情。那么当你粗略地了解这个策略时,如何实现呢?在本书出版之前,我无法提供一个合适的例子来帮助我的同事使用领域驱动设计 - “实现域驱动设计”,

当你得到两个“圣杯” - “领域驱动设计”和“实施领域驱动设计”时,就像你从美女那里得到了一个联系信息并知道她的家庭住址,但是从日出到现在还有一段距离。两个人之间真实日期的日落。没有在真正的项目中练习,只能理解逻辑就像在岸上游泳一样。虽然我们已经在某些项目中使用了Domain的一些概念,但我们应该知道基于Database Driven应用DDD很困难。就在那时,我们从“财富”全球500强客户那里获得了一个项目,他们的架构师被指定使用DDD,这让我非常兴奋,因为它让我们有机会在复杂的业务中练习DDD。

就像“实现领域驱动设计”所说,Domain-Driven主要有两个部分 - 战略设计和战术设计。

战略设计(做正确的事)
无处不在的语言
域驱动开发让域专家和开发人员将业务结合在一起,最有效的沟通方式是使用无处不在的语言。我们在这个项目的开头定义了很多词汇表,这是我们无处不在的语言。

有界上下文和域
当我们得到无处不在的语言和词汇表时,每个词汇都应该有自己的有界上下文,因为它在不同的有界上下文中有不同的含义。例如,你家里的情人的有界背景是“你的妻子”,如果她是一名教师,那么她在学校的有限语境就是“老师”。我们多次讨论过如何定义边界,我们采用了这种方法:将它划分为多个子系统(Bounded Context看起来与微服务类似吗?)每个子系统都有自己的自治权。
稍后我们将业务抽象为域模型,每个域都有自己的自治权。模型中的属性和行为表达式是域专家可以理解的代码,例如,使用 Job. Publish().。虽然它最终产生了聚合根,实体和值对象等,但在与域专家沟通时我们应该避免使用这些词汇表。我们可以用另一种方式表达它,例如:在招聘时,该职位是否必须由公司管理?然后我们就会知道Job属于公司Aggregate root。使用统一语言构建模型(使用自然语言命名类名称和方法名称),领域专家将能够直接阅读并理解我们的代码,并知道它是否表达了业务需求。

战术设计(做正确的事)
在战术设计方面,由于业务行为和规则都属于领域而系统被划分为多个子系统,因此给技术实施带来了巨大挑战,尤其是我们大多数人都有一个基于数据驱动开发。从技术上讲,有不同的实施方式,但我们从一开始就选择了“最佳实践”(实施域驱动设计),也就是说,我们使用了事件源和CQRS,这也是一种前进的难点。

事件溯源
事件溯源意味着我们不记录数据的最终状态,我们记录事件(数据的每次更改),然后我们将通过在读取数据时重新开始获取数据状态。例如,当您的银行账户中有一百美元,而且只剩下10美元时,记录的内容不会是“money.total = 10”,而是记录您提取现金的每条记录并重播您退出的过程。 100美元,那么你将获得10美元。
在我们编写Event Sourcing时,我们通常会回想起Data-Driven的好处,我们认为在系统复杂性不断增加之前使用事件采购非常烦人,我们发现使用Event Sourcing有很大的好处。我稍后会独立谈论它。

CQRS
当使用事件源时,做数据查询真的很烦人,尤其是跨业务(聚合)查询,在查询中没有像关系数据那样的优势。CQRS是解决这个问题的好方法。CQRS分离查询和写入,它写入需要以其原始形状查询的接口数据,这意味着它预先正确地记录接口,与其显示方式相同,这与原始缓存类似,没有额外的连接操作,这是非常有效的查询方式。