DevilKing's blog

冷灯看剑,剑上几分功名?炉香无需计苍生,纵一穿烟逝,万丈云埋,孤阳还照古陵

0%

Domain Design

原文链接

DDD的核心思想可以认为是两个:

  • 无处不在的领域业务语言即Ubiquitous Language,这是DDD最为强大的一个工具之一
  • 绑定的领域上下文即Bounded Context

分为不同的子领域和绑定上下文部分

通过将问题领域分割为多个子领域,复杂的问题得以简化;通过聚焦于核心领域,核心的商业价值得以最大化。每一个子领域和围绕它形成的领域专家和技术专家共同产生和维护的统一语言构成了特定的绑定上下文。

领域并不是组件、模块等纯软件概念

我们界定绑定上下文的边界的时候,必须避免软件架构技术产生决定性的影响;因为这一方法的指导性原则是,需要倾听和修正领域模型和语言边界,而不是软件架构实现技术的边界。

上下文映射关系

  • 伙伴式关系:两个领域之间是通过紧密写作来完成各自的领域职责;一荣俱荣一损俱损的关系,两者之间有直接而深入的耦合关系。相互关联的功能必须要通过两个团队之间的紧密合作才可能开发和集成成功。
  • 共享内核:两个领域之间共享一些基本的公用模型或者核心设施、代码等;从而两个领域的设计可以得到极大的简化;如果存在共享内核,需要尽力使得共享内核足够的小和简单。
  • 上下游关系:上游领域的改动无需通知下游,而下游的成功非常依赖于上游提供的服务。
  • 反破坏层:当上游领域和下游领域团队之间的沟通异常困难,或者下游非常难以协调上游的资源支持的时候,下游领域团队往往会需要选择构建一个针对上游领域的反破坏层;这在大公司里面非常常见。
  • 开放宿主服务:一个领域通过想其它领域提供一个开放协议的方式提供支持;新的领域如果需要和它继承,需要根据已有的协议添加适配即可。很多时候,下游的领域会将这个开发协议的提供方看做是一个难以可靠协调的上游, 并且构建反破坏层来维护自身的稳定性。
  • 已发布的公用语言:两个领域之间可以通过共享一部分领域通用语言的方式来沟通和交互。
  • 大泥球:大泥球现象在一些上了历史的老项目中非常场景,当需要和这些遗留领域打交道的时候,我们需要格外小心构建隔离边界,防止大泥球问题的蔓延

依赖倒置原则其实从某种程度上来看打破了传统的分层架构的严谨性,但是同时又允许更大的灵活性,因为组织依赖上都要求大家尽量依赖于抽象而不是依赖于具体的实现;甚至可以认为层次的概念呗弱化的同时,软件的灵活性还得到了保证。

这一架构风格原来也被称为是六边形架构;或者另外一个所谓的洋葱架构指向的也是这种风格

CQRS

CQRS即命令和查询职责分离的简称;这一做法要求我们任何一个方法要么负责查询,要么负责执行命令修改状态;但是永远不要将两者混合在一起。依据这种做法,传统的领域模型就不得不分为两个部分:一个子模型负责查询,另外一个则负责执行命令

Event Sagas用于描述长期运行、持续不断的事件处理过程;有如下三种常见的办法来描述长期运行的长时间处理过程

  • 将处理过程作为一个组合任务过程,用一个可以持久化的对象来记录任务执行时间、完成度信息
  • 将处理过程表述为收集各种活动交互的聚合的集合;其中一个或者多个维护整体的执行和状态信息
  • 处理过程本身设计为无状态的,但是每个处理时间的任务在处理完毕之后都增加更多信息到输出事件上,从而把进度、完成情况等信息递增地包含在事件中

Event Sagas的方式要求我们必须拥抱最终一致性模型,并且妥善处理好超时和重试处理,尽量补偿可能出现的异常情况,甚至在情况复杂的时候尽量引入工作流来降低领域问题的复杂性。

领域驱动开发的核心是关于领域的行为和特征,而不是数据的获取和读取。之所以要用领域实体的概念来封装业务特征,而不是直接在数据集的基础上采用CRUD来直接实现业务规则,主要是因为系统的业务复杂度不断提高的时候,直接CRUD的方式带来了软件复杂度的急剧上升。

不论怎样选择这里的角色抽象,需要始终牢记的是跨职能团队根据领域业务逻辑而统一的领域语言才是决定这些角色和实体类的职责的最重要的因素,而实际实现这些抽象的面性对象技术应该作为具体实现的支撑细节。