DDD理论的核心
背景介绍
tip
张建飞软件教练, 代码精进之路,程序员的底层思维,cola框架 作者
核心理论
DDD本质
- 统一语言
- 领域建模
- 领域边界
核心概念
- 领域 特定的知识或者范围
- 模型 领域特定的抽象
- 上下文 决定词的含义和内涵
统一语言的重要性
- 本质
- 提高效率
- 解决协同沟通问题
- 是否有软件产品的领域词汇表
- 词汇表和代码能对应上
建模过程
- 提取特定的抽象
- 考虑上下文
- 提取公共业务,循序渐进,沉淀领域能力
eg1:
假如有一个客户管理系统,业务那边发起了一个 新的业务规则: 从3月份,注册资本1000万以上的公司被认为是大客户
重构前
场景1:
if registeredCapital >= 1000w {
// do something
}
场景2:
if registeredCapital >= 1000w {
// do something
}
重构后
场景1:
if customer.isBigClient() {
// do something
}
场景2:
if customer.isBigClient() {
// do something
}
Customer {
registeredCapital int64
func isBigClient() {
return registeredCapital >= 1000w
}
}
重构收益
-
代码维护性: 只需要修改一处代码,避免散弹式修改
-
代码可理解性: 大客户是一个重要 的领域知识,业务语义得到显性化的表达,是一种knowledge Rich Design的设计
注:知识丰富的设计(Knowledge Rich Design),怎么理解?,就是通过领域对象(Domain Object),
领域语言(Ubiquitous Language)将核心的领域概念通过代码的形式表达出来,从而增加代码的可理解性。
这里的领域核心不仅仅是业务里的“名词”,所有的业务活动和规则如同实体一样,都需要明确的表达出来。
eg2:
先把App做厚,再把App做薄
第一步:先在里面把完整的业务逻辑表达出来
public class CustomerServiceImpl {
public void register(CustomerDTO customerDTO) {
// 查找 customer
Customer customer = Customer.fromDTO(customerDTO)
// 校验
if customer.getAge() > 18 {
return errors.New("对不起,你未满18")
}
// 查看健康码
HealthCode requset = new HealthCodeRequest();
HealthCodeRes res = healthoCodeSevice.check(request)
if res.isSucess() {
return errors.New("get code err")
}
if !res.isGreen() {
return errors.New("code not greeen")
}
//注册用户
customer.Save(xxx)
}
}
第二步: 沉淀领域能力
对于年龄校验,谁最清楚?当然是customer自己,这是他自己的能力,需要把领域知识沉淀 对于外部域,通过gateway 进行防腐,转义,同样也可以内聚到customer
public class CustomerServiceImpl {
public void register(CustomerDTO customerDTO) {
// 查找 customer
Customer customer = Customer.fromDTO(customerDTO)
// 校验
customer.isRequireAge()
// 查看健康码
customer.isHealthCodeGreen()
//注册用户
customer.Save(xxx)
}
}
微服务相关
- 提供了方法论
- 边界模型和统一语言是基础
模糊概念
- 核心域 能赚钱的域
- 跨多个实体的业务逻辑通过领域服务来实现,跨多个聚合的业务逻辑通过应用来实现。考虑一致性的话通过消息中间件,幂等,重试等分布式中间件保证,聚合内的逻辑可以使用单一数据库事务处理
- 一次事件只更新一个聚合
- 事务包裹跨聚合服务编排,应用于实时性和数据一致性比较高的场景
- 领域事件后可以影响读模型,也可以触发规则策略
- 实体只包含get/set为失血,包含get/set,原子 为贫血, 包含set/get,原子,组合业务逻辑为充血,包含 set/get, 原子,组合,持久化为胀血
- 领域最核心
- CQRS 业务实现读模型可以不经过domain,如果业务逻辑需要更新系统状态变更就必须要在domain层处理