DDD

Tackling Complex Problem

Netease - Jiang Wenkang

What's DDD?

DDD是一种应对复杂需要的软件开发方法,通过核心业务模型的不断演化来实现。

Why DDD?

三段式开发流程的弊端

  • 无法复用
  • 后期维护成本高
  • 业务部门和开发人员沟通成本高

表现特征

  • 贫血模型
  • Fat Service
  • 过程化的开发方式

Why DDD?

DDD带来的好处

表现特征

  • 富领域模型
  • 易于测试
  • 面向对象的开发方式
  • 代码复用
  • 高度模块化、易扩展
  • 业务团队和开发人员沟通成本降低

开发模式的比较

DDD的应用场景

  • 你有一个相对固定的业务场景
  • 你有一个相对复杂的问题领域

如何实施DDD?

  • 战略
  • 战术

向领域专家取经-DDD战略

  • 每个行业都有领域专家
  • 每行代码都有其业务价值

How ?

  • 把开发人员和领域专家聚集在一起
  • 了解业务战略

形成通用语言-DDD战略

  • 产品经理说的是A,我理解的是B,运营觉得是C,测试觉得是D?

How ?

  • 项目的所有参与者都要参与领域建模
  • 讨论过程中的“术语”沉淀并文档化
  • 实时咨询和反馈

找到核心领域-DDD战略

  • 任何业务都有一个核心领域
  • 识别并且找到这个核心领域对项目的成功是至关重要的
  • 对核心领域的投入会增加业务的竞争力

举个例子:

1.访问控制系统的核心是权限

2.仓库系统的核心是库存

找到核心领域-DDD战略

DDD战术模型

  • 实体

  • 值对象

  • 聚合

  • 领域事件

  • 领域服务

...

实体-DDD战术

  • 实体应该包含数据和行为,而不仅仅是geter和setter
  • 实体的行为应该反映业务逻辑
  • 实体的行为应该小而美
  • 实体要尽量避免依赖其他实体
  • 实体的行为应该是仅对本实体属性的操作
  • 实体都有一个唯一标识符
  • 实体是可变的

值对象-DDD战略

  • 不变形

特点

  • 描述或者度量某个事物
  • 可被替换和比较

好处

  • 方便创建、测试和维护
  • 更加准确的表述了事物的特点
  • 类型安全和提前检查
public class OldPushService {

    public void push(String message, long phone) {
        //检查phone的合法性
        Op op = check(phone);
        if (op == Op.Mobile) {
            //发送到移动网关
        } else if (op == Op.Union) {
            //发送到联通的网关
        }else{
            //error
        }
    }

    Op check(long phone) {
        if (phone / 100000000 == 184) {
            return Op.Mobile;
        }
        if (phone / 100000000 == 133) {
            return Op.Union;
        }
        return Op.UNKNOWN;

    }

    enum Op {
        Mobile,
        Union,
        UNKNOWN
    }
}
public class NewPushService {
    public void push(String message, PhoneNumber phoneNumber) {
        if (phoneNumber.isMobile()) {
            //发送到移动网关
        } else if (phoneNumber.isUnion()) {
            //发送到联通的网关
        } else {
            //error
        }
    }
}
public class PhoneNumber implements ValueObject<PhoneNumber> {  
    private long code;

    public PhoneNumber(long code) {
        //验证号码的合法性
        this.code = code;
    }

    //是否为中国移动号码
    public boolean isMobile() {
        return code / 1000000000 == 184;
    }

    //是否为中国联通号码
    public boolean isUnion() {
        return code / 1000000000 == 133;
    }

    public long code() {
        return this.code;
    }

    @Override
    public boolean isSame(PhoneNumber other) {
        return other != null && code == other.code;
    }

}

聚合-DDD战术

  • 聚合内保证业务的一致性(强一致)
  • 聚合应当设计的小巧,正好表示一个业务对象的最小集合
  • 聚合间保持最终一致就行(弱一致)

领域事件-DDD战术

  • 领域事件用于记录领域中发生的事情(动作+上下文)
  • 领域事件发布形式类似于Observer模式
  • 领域事件从本地发布,可以只在本地传播,也可以发布到远端系统(一般使用MQ中间件)

领域事件-DDD战术

领域服务-DDD战术

  • 不适合放到领域或者值对象中的服务
  • 包含业务逻辑
  • 是领域模型的一部分
  • 与应用服务是不同的

注意!

  • 滥用会导致领域贫血

架构

六边形架构

SOA

REST

  • REST是一种架构风格,以资源为中心
  • REST定义了与资源交互的方式
  • DDD可以以REST的风格来暴露领域对象,不是直接暴露

落地

展望

DDD展望

  • 与微服务相得益彰
  • 与敏捷开发的关系
  • 在传统企业中的应用

实施DDD的难点

  • 前期投入相对比较大
  • 要求参与项目的每个人都了解领域
  • 公司或者领导层面的支持
  • 门槛相对较高,依赖开发人员的经验

DDD书籍推荐

Thanks

Q & A

DDD-Tackling Complex Problem

By 蒋文康

DDD-Tackling Complex Problem

From netease Michael Jiang's share

  • 1,464