DDD 随笔 0-读后感吧...

本文详细介绍了领域驱动设计(DDD)的概念,包括从编码和应用架构两个层面阐述DDD的核心思想。文章讨论了传统服务层的问题,提出使用领域对象(DP)进行重构以提高代码清晰度和测试覆盖率。此外,作者还探讨了Repository模式的重要性,强调了其与底层实现解耦的特性,以及在分库分表场景下的应用。文中还提到了领域事件、领域服务、领域策略和聚合根等DDD关键概念,并分享了DDD实践中的一些坑点,如对象转换器的使用。

0. 有时候感觉自己在爬

淘宝官方技术账号-B乎-阿里技术专家详解DDD系列

DDD中Diff的应用(JAVERS)的封装

1. DDD概述

Domain-Driven Design 领域驱动设计

1.1 从编码角度中概述DDD

关于传统架构中service(业务处理层)的问题
	数据验证、错误处理的维护逻辑冗余
	接口签名的语义不够清晰
	业务代码的语义不够清晰
	测试覆盖性低
从编码的层面->domain primitive(DP)领域对象
	实现
		将隐性的概念显性化(将同一问题下的多字段作为一个新的dp引入)
		将隐性的上下文显性化(将一个字段及其衍射/隐藏字段作为一个新的dp引入)
		行为内聚(充血模式)

1.2 从应用架构中概述DDD

从应用的层面
	domain layer(领域层):取代数据库作为最底层对象,不再依赖任何服务、框架
		领域对象(domain{a,b})及其调用过程(service{return a+b;})
	application layer(应用层)
		编排组件(接口)的调用顺序,接口通过注入实现类
		依赖domain layer
		例如:Application Service、Repository、ACL
	infrastructure layer(基础设施层)
		组件的具体实现类
		相对地来说,该层面变更的频率较低
		例如:XxxMapper
ACL
	Anti-Corruption Layer防腐层
	ACL 不仅仅只是多了一层调用,在实际开发中ACL能够提供更多强大的功能:
		适配入参、出参
		缓存逻辑
		(兜底)降级处理
		易于测试
		门禁,替代了物理的增删

2. DDD方法落地

2.1 Repository模式

Repository模式
		为什么?
			传统Data Mapper(DAO)属于“固件”,和底层实现(DB、Cache、文件系统等)强绑定
		Aggregate root(聚合根)&一对多
			聚合根对象的特征
				可能引入多个Entity(领域层对象)
			为何出现?
				分库分表维护相关数据
				牺牲易于维护的单表单表查询,带来更好的DB性能(粒度更小)
		对象
			DO
			entity
			DTO
		assembler
			不同对象之间的转换器
			一般指DO<->entity/entity<->DTO
		接口规范
			接口名称不应该使用底层实现的语法
				insert、select、update、delete都属于SQL语法,使用这几个词相当于和DB底层实现做了绑定
				我们应该把 Repository 当成一个中性的类 似Collection 的接口,使用语法如 find、save、remove。
			出参入参不应该使用底层数据格式
				不应该使用DO作为参数类型
				Repository 操作的是 Entity 对象(实际上应该是Aggregate Root)
			避免所谓的“通用”Repository模式
				借助诸如:spring jdbc、entity framework等框架的配置、注解自动实现接口
				这么做的话,扩展性将缺失
		值得注意的是:
			Repository的接口是在Domain层,但是实现类是在Infrastructure层。

2.2 domain layer

OOP(完全的OOP)通过继承来支持扩展,违背了开闭原则,这时候自然会想到组合的扩展方式(即在domain service层组合)
这种仅凭domain primitive+domain service的做法并不能满足扩展性的需要,此时可以借鉴游戏程序的经典架构ECS:
	组成模块:
		Entity-Component-System
		这既是其全称,也是三个组成模块的含义
	将复杂的大系统拆分成独立的组件
	将行为从对象代码中剥离(Moveable)
	数据驱动
		对象的行为由其参数决定
		动态修改数据可以快速改变其行为->行为调用逻辑剥离实体(调用反转到System模块)
	ECS不完全适配商业应用程序的原因:
		为降低GC成本,允许直接操作数据->一致性难以保证
DDD的做法
	domain primitive
		尽可能的不维护id以外的数据,将非直接相关的字段隔离开来
		不应该强依赖其他聚合根、领域服务
		构建时必须检查所有参数是合理的
			重载all args constructor
			Factory、builder中通过给定一些默认值简化构建
			setter建议采用行为的命名方式
		通过聚合根来保证主子实体一致
		任何实体的行为只能影响自身
	domain service
		三种常见模型:
			单对象策略模型
				可以采用double dispatch反转调用(将domain service作为方法参数入参到domain primitive)
			跨对象事务模型(一个行为会修改多个实体)
				参数来自多个实体,因此不能作为方法参数入参
				需要借组一个第三方的领域服务实现
			通用组件模型
	domain policy
		作用:封装领域规则
		通过维护了两个方法:能否应用、实际业务方法
	domain event
		领域事件通常是立即执行的、在同一个进程内、可能是同步或异步
		局限
			一个问题是因为Entity不能直接依赖外部对象,所以EventBus目前只能是一个全局的Singleton(全局Singleton对象很难被单测)

3. 坑个坑

DDD架构中对象转换器自动生成框架MapStruct

比对前/后两个聚合根对象,并根据比对结果更新快照中的对象状态(吃持久态、修改、新增、移除、游离态),like jaVers

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肯尼思布赖恩埃德蒙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值