? 优质资源分享 ?
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
? Python实战微信订餐小程序 ? | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
?Python量化交易实战? | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
背景
几年前我总结过DDD战术设计的一些落地经验可落地的DDD(5)-战术设计,和一次关于聚合根的激烈讨论最近两年有些新的落地体验,回过头来发现,当初对这些概念的理解还是没有深入,这篇文章重新阐述下。
之前理解不到位的点有
- 战术设计的各个模块是的协作关系
- 哪些是问题空间问题,哪些是方案空间问题边界没有划分清楚。
- 实体和聚合根的区别理解不不深刻,实体和聚合根建模的方法不对。
以上问题将会在下文解释清楚。
战术设计拆解
DDD的战术设计即设计某个子域的领域模型以及代码落地。领域事件、领域对象、聚合根、实体、值对象、领域服务、工厂、资源库等这些概念都属于这个范畴。
笔者将这些概念重新分层组装了下,如下图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-38iZWLzF-1657860808612)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/78524dba9fad4d38b77f13a1e7251e7c~tplv-k3u1fbpfcp-watermark.image?)]
首先将整体分成两部分,问题空间和方案空间。
- 问题空间即领域建模。是对业务问题的描述,以及我们如何对这些问题进行抽象。这些是需要在业务、产品、开发都必须达成一致的,与具体的技术方案无关。
- 方案空间即如何用技术手段来解决问题,与具体技术的实现有关。
问题空间即领域建模,是通过实体、值对象、领域服务、领域事件来表达。
- 实体和值对象是模型对象,实体是重中之重,包括核心模型数据、行为、状态。之所以要区分实体和值对象,是为了降低复杂度,因为值对象是个常数对象,不需要花太多精力。
注意某个对象在某个领域内是个值对象,在另外的领域可能是个实体,所以脱离领域上下文,说某个对象是值对象,肯定是不对的,比如大家常说的地址是个值对象,这一定是对的吗? - 领域事件即实体产生的事件
- 领域服务包括一些逻辑的计算,和业务策略。比如商业决策逻辑、业务流程等。
方案空间即如何解决问题,实现领域模型与代码的映射。实现设计与实现的一致性。主要通过工厂,聚合,资源库来表达。
- 聚合是对实体、值对象的封装。领域外部对领域对象所有访问都基于聚合来。如基础设施层操作聚合进行数据保存。其他领域引用聚合对象数据。
聚合的设计一般是围绕着技术来的,比如聚合对象事务性。 - 工厂,复杂对象的创建工厂类
- 资源库,对聚合的操作。
从笔者的实践角度来说,落地DDD过程中,问题空间比方案空间更重要,收益更大。因为通常我们吐槽的某些代码写的烂,贫血模型。背后并不是因为没有用DDD,而是问题空间没有定义好,对于业务没有深刻理解,导致模型抽象不足。
如何建模
为什么要建模
通常在某个子域落地DDD,我们会按照业务分析-》用例分析-》领域建模(问题空间) -》技术落地(方案空间)这些步骤来操作。但其实即使我们不在代码里落地DDD,只用前面3步维护一个子域内的领域模型也同样能够带来很多收益,包括但不限于
- 统一业务组各个角色的认知,业务、产品、开发大家对同一概念的认知是一致的。
- 指导开发工作的拆分。
比如在淘宝有个血的教训,至今这个历史债还无法被修复。早期在淘宝开店。一个卖家只能开一个店。卖家和店铺是两个领域对象,关系是1:1。店铺服务觉得是1:1的关系,对外提供的服务有根据sellerId获取店铺信息,所以其他调用方就无意识的直接引用了卖家id,这样也可以拿到店铺。导致shopId被等同于了sellerID。这个误引用发生在成千上万个地方,最后导致后续需要支持一个卖家开多店铺时无法支持。只能通过其他trick方式实现。
以之前介绍过的CRM领域 来讲解。
省略业务分析,直接拿到用例。
用例分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2BDMnzxs-1657860808617)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f051a4755f06412b8899c6a77d14c795~tplv-k3u1fbpfcp-watermark.image?)]
按用户角色罗列所有的用例,用来推导模型、以及模型之间的关系。领域模型建立好了,需要根据列出的用例来走查一遍,要确保所有的用例都能走通。完整的用例集才能推导出正确的模型,所以当有变化时,首先调整用例集,再来修改领域模型
建模
领域建模就是定义模型对象,以及模型对象之间的关联关系。分两步建模,第一步通过名词找模型对象。第二步通过动词、形容词分析对象关联关系
名词
通常反复出现的主语和宾语中的名词就是模型对象,比如市场人员创建一个活动,活动就是一个模型对象。当然定语中出现的名词也可能是模型对象。
1.名词的定义一定要清晰。比如说crm领域有通用的名词叫商机。但是你对口的产品经理不熟悉crm领域,新造了一个词,那你要及早纠正他。
2.名词的含义在限界上下文内语义唯一,在不同的上下文中概念就不一定一样了。比如市场人员创建的活动,和做营销时创建的活动就不一定。
动词、活动
1个市场人员可以创建多个活动,所以市场人员和活动关联关系是1对多。两者独立存在,普通关联关系。
这里为了简化描述,只列了市场活动、线索、客户、商机这些域。用户、角色、权限、数据分析这些域先忽略了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lWiGjkKe-1657860808618)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/31626ae62ae241d6be7d6d570b6da601~tplv-k3u1fbpfcp-watermark.image?)]
产出物
在推导的过程中,我们是按照自底向上的方式推导的,最后我们呈现出来的结果是按照如下方式
- 领域名词
市场活动: 市场人员为了展示公司形象、推广公司产品,获取线索而举办的活动。一个活动中可以创建多个线索。
线索: 销售人员基于线索发掘潜在客户,多个线索转换为一个客户。线索可以由一个市场活动生成,或者其他渠道。
客户:有意向购买公司产品的用户,销售人员可以通过跟进客户,转化销售机会。
销售机会:更高质量的线索,有机会签单。可以通过客户转换得到,也可以通过其他渠道来获取
- 领域模型
如上图 - 主要领域状态转换。
因为复杂的领域对象生命周期以及一些跨领域对象交互情况在领域模型图中表达不出来,所以需要借助额外的图来表达。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-abQggXbu-1657860808619)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8a83f4fc30e8465588e1a9fdad5d438a~tplv-k3u1fbpfcp-watermark.image?)]
转载请注明:xuhss » 可落地的DDD(7)-战术设计上的一些误区