几年前我总结过DDD战术设计的一些落地经验可落地的DDD(5)-战术设计,和一次关于聚合根的激烈讨论最近两年有些新的落地体验,回过头来发现,当初对这些概念的理解还是没有深入,这篇文章重新阐述下。
之前理解不到位的点有
以上问题将会在下文解释清楚。
DDD的战术设计即设计某个子域的领域模型以及代码落地。领域事件、领域对象、聚合根、实体、值对象、领域服务、工厂、资源库等这些概念都属于这个范畴。
笔者将这些概念重新分层组装了下,如下图所示。
首先将整体分成两部分,问题空间和方案空间。
问题空间即领域建模,是通过实体、值对象、领域服务、领域事件来表达。
方案空间即如何解决问题,实现领域模型与代码的映射。设计与实现的一致性。主要通过工厂,聚合,资源库来表达。
从笔者的实践角度来说,落地DDD过程中,问题空间比方案空间更重要,收益更大。因为通常我们吐槽的某些代码写的烂,贫血模型。背后并不是因为没有用DDD,而是问题空间没有定义好,对于业务没有深刻理解,导致模型抽象不足。
通常在某个子域落地DDD,我们会按照业务分析-》用例分析-》领域建模(问题空间) -》技术落地(方案空间)这些步骤来操作。但其实即使我们不在代码里落地DDD,只用前面3步维护一个子域内的领域模型也同样能够带来很多收益,包括但不限于
比如在淘宝有个血的教训,至今这个历史债还无法被修复。早期在淘宝开店。一个卖家只能开一个店。卖家和店铺是两个领域对象,关系是1:1。店铺服务觉得是1:1的关系,对外提供的服务有根据sellerId获取店铺信息,所以其他调用方就无意识的直接引用了卖家id,这样也可以拿到店铺。导致shopId被等同于了sellerID。这个误引用发生在成千上万个地方,最后导致后续需要支持一个卖家开多店铺时无法支持。只能通过其他trick方式实现。
以之前介绍过的CRM领域 来讲解。省略业务分析,直接拿到用例。
按用户角色罗列所有的用例,用来推导模型、以及模型之间的关系。领域模型建立好了,需要根据列出的用例来走查一遍,要确保所有的用例都能走通。完整的用例集才能推导出正确的模型,所以当有变化时,首先调整用例集,再来修改领域模型
领域建模就是定义模型对象,以及模型对象之间的关联关系。分两步建模,第一步通过名词找模型对象。第二步通过动词、形容词分析对象关联关系
通常反复出现的主语和宾语中的名词就是模型对象,比如市场人员创建一个活动,活动就是一个模型对象。当然定语中出现的名词也可能是模型对象。
1.名词的定义一定要清晰。比如说crm领域有通用的名词叫商机。但是你对口的产品经理不熟悉crm领域,新造了一个词,那你要及早纠正他。
2.名词的含义在限界上下文内语义唯一,在不同的上下文中概念就不一定一样了。比如市场人员创建的活动,和做营销时创建的活动就不一定。
1个市场人员可以创建多个活动,所以市场人员和活动关联关系是1对多。两者独立存在,普通关联关系。
这里为了简化描述,只列了市场活动、线索、客户、商机这些域。用户、角色、权限、数据分析这些域先忽略了。
在线教育crm领域模型 (1).png
在推导的过程中,我们是按照自下向上的方式推导的,最后我们呈现出来的结果是按照如下方式
线索: 销售人员基于线索发掘潜在客户,多个线索转换为一个客户。线索可以由一个市场活动生成,或者其他渠道。
客户:有意向购买公司产品的用户,销售人员可以通过跟进客户,转化销售机会。
销售机会:更高质量的线索,有机会签单。可以通过客户转换得到,也可以通过其他渠道来获取
在线教育crm领域状态.png