ikki@github.io:~$

领域驱动设计

领域驱动设计实践

一些事实

常见软件状况

  • 软件在第一版设计质量最高, 随着需求的变更, 打乱了原有设计, 软件质量会逐渐退化
  • 代码变更了, 但是模型没有更新, 越积越多, 后续维护会退缩

常见的误解

  • 一套模型打天下: 因为对业务的理解误差, 领域模型是随时都会发生变化的, 模型变化了,代码也是要变化的
  • DDD 和现有框架的冲突: DDD 是设计思想, 框架是编程工具, 两者并不冲突,关键是要让人读懂代码,看懂模型

对领域的拆分和实践 (战略层面)

先给领域起个名:

  • 用一个名词概括一个领域, 比如 身份认证 就要比 登录 好的多,同时包括了多种业务的可能性
  • 这个名词要偏向于业务, 便于沟通和理解
  • 不能偏向于业务的某一种可能性, 可能会僵化部分人对业务的理解。 比如 提到 登录, 大部分脑海里第一时间想到两个框框, 一个填用户名,一个填密码 但是提到 身份认证, 部分人除了想到上面的以外,还会想到,验证码登录,刷脸,指纹识别等内容

限界上下文

  • 减少误解:能穿多少穿多少 这句话在冬天和夏天 有着不同的理解
  • 如果对一个领域中的实体,值对象,领域事件等 的理解没有歧义,限界上下文也就清晰了

大胆使用值对象

  • 是对象是可以没有ID 的, 是不可变的实例, 比如 在清空购物车时,我们只关心,你是否提填写了收货地址, 但是不关心你 的地址中的 街道、门牌号等 所以 在订单表中 我们完全可以大胆的设计成 address json NOT NULL, 在关系表中,序列化成json 字符串存储。
  • 而在派送系统中, 却是要关系收货地址 的小区、街道、门牌号,方便安排一次派送任务 尽可能多地派送货物
  • 因此, 值对象是基于领域上下文的,
  • 但是在代码中,address 还是需要 设计成对象,以满足不同的业务场景和技术需求

实体

  • 关于贫血模型和充血模型的争议: 充血模型固然能够聚焦领域,但是现有的技术框架实现不友好; 贫血模型固然是一个数据容器,但对ORM 友好
  • 建议: 按框架友好的方式去写代码(战术层面),按模型友好的方式去组织代码(战略层面)

领域服务

  • 领域服务可能不属于任何领域,但是它却处理和编排了一系列 领域对象
  • 领域服务操作了整个领域对象

应用服务

  • 不涉及核心的领域逻辑,但又是不可缺少 的服务,比如发短信, 日志等需求和业务之间的桥接方法

对领域的实践 (战术层面)

前提

  • 能够在自己负责的业务系统中, 尽可能准确的识别领域对象

没有最佳实践,只有最适合的实践

  • 按照现有的技术框架或者范式, 的确不太容易去按照DDD 的思想去做一些东西,这需要我们大胆尝试和对旧有的范式的打破。

  • 按照现有的框架设计, 我们更多的是习惯去写一些JavaBean, 作为数据容器使用。 但是按照充血模型的定义,我们又希望JavaBean 不仅仅是 Getter/Setter。 所以, 定义一个包,既写JavaBean类,也写 领域方法类, 把包看作一个充血模型的实现, 而不是一个简单的类。

  • 多去实践一些 设计模式 和 语言特性,这些 更加‘接地气’,更容易落地到代码上。