刘兴起

I am coder. Currently doing more in backend, focused in Ruby and Python.

领域驱动设计学习笔记

28 Jun 2018 » book

领域驱动设计——软件核心复杂性应对之道

  1. 通过将文档减至最少,并且主要用它来补充代码和口头交流,可以避免文档和项目脱节。

  2. 任何参与建模的技术人员,不管在项目中的职责是什么,都必须花时间了解代码。任何负责修改代码的人则必须学会用代码来表达 模型。每一个开发人员都必须不同程度地参与模型讨论并且与领域专家保持密切联系。参与不同工作的人都必须有意识地通过通用语言 与接触代码的人及时交换关于模型的想法。

  3. 一个对象是用来表示某种具有连续性和标识的事物呢,还是用于描述某种状态的属性呢?这是 Entity 和 Value Object 之间 最根本的区别。

  4. 主要由标识定义的对象被称作 Entity。Entity 可以是任何事物,只要满足两个条件即可,一是它在整个生命周期中具有连续性, 二是它的区别并不是由那些对用户非常重要的属性决定的。

    Entiry 又称为 Reference Object

  5. 用于描述领域的某个方面而本身没有概念标识的对象称为 Value Object(值对象)。值对象被实例化之后用来表示一些设计元素,对于 这些设计元素,我们关心它们是什么,而不关心它们是谁。

  • 值对象可以是其他对象的集合
  • 值对象可以引用 Entity
  • 值对象经常作为参数在对象之间传递消息。它们常常是临时对象,再一次操作中被创建,然后丢弃
  • 值对象可以用作 Entity 或其他 value 的属性
  • 值对象应该是不可变的,不要为它分配任何标识,而且不要把它设计成 Entity 那么复杂
  1. 当领域中某个重要的过程或转换操作不是 Entity 或 Value Object 的自然职责时,应该在模型中添加一个作为独立接口的操作, 并将其声明为 Service。定义接口时要使用模型语言,并确保操作名称是通用语言中的术语。此外,应该使 Service 是无状态的。

    无状态是指任何客户都可以使用某个 service 的任何实例,而不必关心该实例的历史状态。

  2. Service 是应客户端请求来完成某事,当对软件中的某项无状态的活动进行建模时,就可以将该活动作为一项 Service。

  3. 应该将 Entity 和 Value Object 分门别类的聚集到 Aggregate(聚合)中,并定义每个聚合的边界。在每个聚合中,选择一个 Entity 作为根,并通过根来控制对边界内其他对象的所有访问。只允许外部对象保持对根的引用。对内部成员的临时引用可以被传递出去,但仅在一次操作中有效。由于根控制访问,因此不能绕过它来修改内部对象。这种设计有利于确保聚合中的对象满足所有固定规则,也可以确保在任何状态变化时聚合作为一个整体满足固定规则。

  4. 应该将创建复杂对象的实例和聚合的职责转移给单独的对象,这个对象本身可能没有承担领域模型中的职责,但它仍是领域设计的一部分。 提供一个封装所有复杂装配操作的接口,而且这个接口不需要客户引用要被实例化的对象的具体类,在创建聚合是要把它作为一个整体,并确保 它满足固定的规则。

实现领域驱动设计

  1. 从战略层面来讲,企业应该在核心域上胜人一筹。我们应该给予核心域最高的优先级、最资深的领域专家和最优秀的开发团队。 在实施 DDD 的过程中,你将主要关注于核心域。

  2. 有些相似的对象拥有不同的属性和行为,此时我们可以认为上下文边界的划分是合理的。然而,如果你在不同的界限上下文看到 了完全相同的对象,这通常意味着你的模型是错误的。

  3. 一个团队,一个界限上下文。团队中,领域专家和开发者只关注于一个界限上下文的通用语言。