blog-hexo/source/_posts/front-end/ddd.md
2023-11-06 16:05:27 +08:00

105 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 领域驱动设计
categories:
- Front-End
status: doing
---
# 参考文献
- [蚂蚁金服数据体验技术团队 - 领域驱动设计](https://juejin.cn/post/6844903618680881165)
- [美团 - 领域驱动设计在互联网业务开发中的实践](https://tech.meituan.com/2017/12/22/ddd-in-practice.html)
- [领域驱动实战思考](https://huhao.dev/posts/61190ae2/#%E9%97%AE%E9%A2%98%E5%AD%90%E5%9F%9F%E8%AF%86%E5%88%AB)
- [基于 DDD 的前端项目架构设计与实战](https://www.tangshuang.net/8663.html)
- [React 语境下前端 DDD 的思考](https://www.tangshuang.net/8212.html)
# 架构对比
从后端视角看,对比传统的三层架构,领域驱动
- `充血`复用了:领域对外的接口
- `领域服务`封装了:领域之间的联系
贫血模型->充血模型,降低了`service层`的负担,同时保证了业务迭代,`entity`的独立性
## MVC
从数据库视角、分析实体出发,进行系统的构建
- DAO 层
- Service 层
- Controller 层
## 后端 DDD
> 针对基础设施层,也可以考虑加入`防腐层`、`工厂`
一个领域基本四层架构
1. 用户层(user interface): 对标 controller对外提供 web 服务、接口
2. 应用层(application): 业务层,定义领域可以解决的问题 `domainService`
3. 领域层(domain): 纯粹的描述业务实体
4. 基础设施层(infra): 持久化层(Builder+repository)
同时,领域拆分带来如下两个致命问题
- 领域化(微服务)后,数据库是分开的,导致实体调用链复杂,避免跨库查询
- 避免分布式事务同步
## 前端 DDD
> ?? 这里存在一个问题api 网关到底要不要挪到前端领域目录下来开发
1. 用户层: web、mobile、mini-program ...多端
2. service: 暴露给 UI 组件的 `domainSerivce`,组织实体的状态流转
3. entity: 实体、聚合实体、事件
4. infra: api 请求、缓存、工具
## 工厂 Factory / Builder
- 数据库表设计层面,如果要`多对多`的关系,只能很别扭的设计一个中间表。
- 实体 A 适合 `mongo`文档形存储,实体 B 适合`mysql`关系型存储。对于 `Builder` 而言,直接在这个领域搓出来 `A 和 B``CRUD`的实现方法
## 防腐层 Facade / Adaptor
也被成为适配器,隔离第三方/外部服务,例如场景,用户上传文件到阿里云、腾讯云
```js
class UserUploadServiceFacade extends UserService {
/**
* 上传
*/
async upload(oss) {
if (oss === "ali") return "OK";
if (oss === "tx") return "FAIL";
}
}
```
# 领域模型
实体的`贫血->充血`是一个随着业务发展过程演变的结果,初期业务场景不明确,很难充血,瞎几把充血,纯属找难受。
是否需要引入`聚合根(aggregate root)`的概念,解决领域内实体独立、平铺关系带来的不方便,这个可能比较看心情
## 贫血模型(POJO)的问题
> 脱离了业务复杂度谈分层,好比抛开剂量谈毒性
领域对象里只有`get/set`方法,所有的业务逻辑都不包含在内,从而造成`失忆症`,从实体中,无法知道发生了那些业务,需要去 `service层` 里挨个梳理,一旦业务迭代、`service 层`直接开始变成屎山
## 充血模型 && 领域服务的关系
> 确保领域之间独立的,随着不断的充血,保证领域(实体)是独立发展的
假定两个 domain(实体)
- 学生: 上课、做作业
- 老师、全体起立、布置作业
假定`老师`调用`全体起立`,对应肯定要`学生`调用`上课`,这个就是 `领域服务(domainService)` 需要去处理的,他俩不能建立直接的联系。
- 增加新的业务逻辑:在 `domainService` 增加新的方法。
- 调整旧的业务逻辑:修改`学生``老师`,内部具体的方法,`domainService` 完全不需要变化。