DDD

DDD学习笔记

Posted by 孙继峰 on April 7, 2020

WHAT?

DDD 是一种处理高度复杂领域的设计思想,它试图分离技术实现的复杂性,并围绕业务概 念构建领域模型来控制业务的复杂性,以解决软件难以理解,难以演进的问题。DDD 不是 架构,而是一种架构设计方法论,它通过边界划分将复杂业务领域简单化,帮我们设计出清 晰的领域和应用边界,可以很容易地实现架构演进。

注: 虽然是汉语, 但是我看不懂


WHY?

  • 服务怎么拆? 服务拆多小?
  • 这个功能放到哪个服务里?
  • 这次需要要不要新开个服务?

DDD中的概念

通用语言

通用语言是团队统一的语言,不管你在团队中承担什么角色,在同一个领域的软件生命周期里都使用统一的语言进行交流。

e.g.

  • 产品叫上架, 开发人员叫更新商品状态
  • 阿柯叫删除货号, 我和珍珍叫货号审核关闭

通用语言可以是术语, 也可以是用例场景, 并且能够直接写在代码中.

e.g.

		/**
		 * 透明通道图片
		 */
		private ImageDTO alphaChanelImage;
    /**
     * 确保主力没有删除后再保存
     * 创建 -> 提审 -> 拒绝 -> 删除 -> 提审
     */
    protected void ensureNotDeleteThenSave(String mspuNo) {
        .....
    }
    /**
     * 批量上架商品
     */
    public void shelveGoodsBatch(List<String> gidList) {
    		.....
    }

限界上下文

通用语言都有它的业务边界, 超出了边界理解上就会出现问题。

e.g.

GoodsCenter的商品与TradeCenter 的商品都叫商品, 但是他们有不同的属性, 不同的行为, 不同的弹性边界, 提供不同的业务价值.

实体

一系列属性与行为(除了Getter、Setter以外的行为)的集合, 大多数情况与数据库表是一对一的关系, 有自己的唯一标识(id), 能够实现基本功能自治.

e.g.

public class Person {
    private int id;
    private int age;
    private String name;
    private Address address;
  
  	public void growing() {
    	age++;
    }
}

值对象

一系列属性的集合, 需要依附于实体存在, 例如:

public class Address {
    String province;
    String city;
}

原则上是不可以修改的, 只能使用另一个对象去替换
person.address.city = "北京" ×
person.address = new Address("北京", "北京")

值对象嵌入实体方式
  • 属性嵌入: Person@{id=1, age=10, name="吴", province="北京", city="北京"}
  • 序列化嵌入: Person@{id=1, age=10, name="吴", address="{"province":"北京", "city":"北京"}"} address 的值是 Json 序列化后的 String
持久化方式

根据业务不同可以选择以下两种持久化方式

范式持久化

person 一张表, address 一张表, address 表中有一个 person_id 的属性关联 person.id,
这种方式保留了业务含义, 但是增加了数据库复杂度.

反范式持久化

全部 address 属性都加到 person 表中, 可以field嵌入, 也可以序列化之后嵌入.
这种方式破坏了业务含义, 但是没有增加数据库复杂度.

聚合

领域模型中的实体和值对象就好比个体,而能让实体和值对象协同工作的组织就是聚合
个人理解比较像是项目中使用的 XXService, 这里理解的不是很清晰, Mark下

聚合根

聚合根是一种特殊的实体, 可以理解为聚合根是聚合内实体与值对象的管理者

领域事件

一个领域事件将导致进一步的业务操作, 例如: 密码连续输入错误三次,导致锁定账户的操作
记得有次DDD分享时分享人说过, 领域事件就是该存到数据库中的事件
领域事件的发布通常使用MQ进行发布, 通知订阅者处理领域事件


HOW?

事件风暴

1. 确认需求愿景

用户故事: As a (Role), i want (Activity), so that (Business Value). 在完成用户故事确认之后会留下有效的用户故事, 以有效的用户故事来确定通用语言.

2.


DDD 和微服务的关注点

  • DDD 主要关注:从业务领域视角划分领域边界,构建通用语言进行高效沟通,通过业务抽 象,建立领域模型,维持业务和代码的逻辑一致性。
  • 微服务主要关注:运行时的进程间通信、容错和故障隔离,实现去中心化数据管理和去中心 化服务治理,关注微服务的独立开发、测试、构建和部署。

那为什么DDD适合微服务? DDD的过程会产出实体、值对象, 这些用来建立数据表. 还会产生限界上下文, 这个是微服务拆分的重要参考, “到底该拆多小? 这个功能该放在哪个服务?” 限界上下文会给你答案.


微服务可以怎么拆?

1.按照流程拆

商品的流程: 生产 -> 浏览/收藏 -> 下单 -> 发货 -> 确认收货/退款

每一个阶段提供的业务价值都是独立且无交集的

2.弹性边界

这个弹性边界与云原生的弹性边界概念相同, 一个应用内某个模块的请求量远高于其他模块, 这时候高请求量的模块可以拆出来做单独的运维, 单独给这个模块升级配置