
- 领域模型对设计能力要求很高,没把握用好,一个错误的抽象还不如不抽象,宁可不要用,也不要滥用,不要为了DDD而DDD。
- 问题的关键是要看,新增的模型没有给你带来收益。比如有没有帮助系统解耦,有没有提升业务语义表达能力的提升,有没有提升系统的可维护性和可测性等等。
模型虽然可选,但DDD的思想是一定要去学习和贯彻的,特别是统一语言、边界上下文、防腐层的思想,值得深入学习,仔细体会。实际上,COLA里面的很多设计思想都来自于DDD。其中就包括领域包的设计
分层结构

1)适配层(Adapter Layer):负责对前端展示(web,wireless,wap)的路由和适配,对于传统B/S系统而言,adapter就相当于MVC中的controller;
- 2)应用层(Application Layer):主要负责获取输入,组装上下文,参数校验,调用领域层做业务处理,如果需要的话,发送消息通知等。层次是开放的,应用层也可以绕过领域层,直接访问基础实施层;
- 3)领域层(Domain Layer):主要是封装了核心业务逻辑,并通过领域服务(Domain Service)和领域对象(Domain Entity)的方法对App层提供业务实体和业务逻辑计算。领域是应用的核心,不依赖任何其他层次;
- 4)基础实施层(Infrastructure Layer):主要负责技术细节问题的处理,比如数据库的CRUD、搜索引擎、文件系统、分布式服务的RPC等。此外,领域防腐的重任也落在这里,外部依赖需要通过gateway的转义处理,才能被上面的App层和Domain层使用。
包结构

| 层次 | 包名 | 功能 | 必选 |
|---|---|---|---|
| Adapter层 | web | 处理页面请求的Controller | 否 |
| Adapter层 | wireless | 处理无线端的适配 | 否 |
| Adapter层 | wap | 处理wap端的适配 | 否 |
| App层 | executor | 处理request,包括command和query | 是 |
| App层 | consumer | 处理外部message | 否 |
| App层 | scheduler | 处理定时任务 | 否 |
| Domain层 | model | 领域模型 | 否 |
| Domain层 | ability | 领域能力,包括DomainService | 否 |
| Domain层 | gateway | 领域网关,解耦利器 | 是 |
| Infra层 | gatewayimpl | 网关实现 | 是 |
| Infra层 | mapper | ibatis数据库映射 | 否 |
| Infra层 | config | 配置信息 | 否 |
| Client SDK | api | 服务对外透出的API | 是 |
| Client SDK | dto | 服务对外的DTO | 是 |
解耦
- “高内聚,低耦合”这句话,你工作的越久,就越会觉得其有道理
- 所谓耦合就是联系的紧密程度,只要有依赖就会有耦合,不管是进程内的依赖,还是跨进程的RPC依赖,都会产生耦合。依赖不可消除,同样,耦合也不可避免。我们所能做的不是消除耦合,而是把耦合降低到可以接受的程度。在软件设计中,有大量的设计模式,设计原则都是为了解耦这一目的
- 在DDD中有一个很棒的解耦设计思想——防腐层(Anti-Corruption),简单说,就是应用不要直接依赖外域的信息,要把外域的信息转换成自己领域上下文(Context)的实体再去使用,从而实现本域和外部依赖的解耦
- 在COLA中,我们把AC这个概念进行了泛化,将数据库、搜索引擎等数据存储都列为外部依赖的范畴。利用依赖倒置,统一使用gateway来实现业务领域和外部依赖的解耦
这样做有两个好处,一个是降低了对外域信息依赖的耦合;另一个是通过上下文映射(Context mapping),确保本领域边界上下文(Bounded context)下领域知识的完整性,实现了统一语言(Ubiquitous language)。
落地实践
为了避免adapter层和app层的访问混乱,将consumer、listener(app)-> 移动到adapter层,adapter全权负责和外部系统的交互
- 领域事件event从client -> 移动到app层,client负责和外部系统进行RPC调用
- 这样app层就可以负责整体的业务编排处理,整个包依赖(清洁架构) controller/client->app->domain->infra;实现包数据的高内聚
