软件架构DDD

10.领域驱动设计(译)

2018-08-27  本文已影响81人  qinyu

原文:https://herbertograca.com/2017/09/07/domain-driven-design/

这篇文章是软件架构编年史()的一部分,这部编年史由一系列关于软件架构的文章()组成。在这一系列文章中,我将写下我对软件架构的学习和思考,以及我是如何运用这些知识的。如果你阅读了这个系列中之前的文章,本篇文章的的内容将更有意义。

Eric Evans 于 2003 年出版了精采绝伦的《领域驱动设计:软件核心复杂性应对之道》,在书中他创造了领域驱动设计方法。Eric Evans 的这本著作十分重要,现今许多我们认为理所当然的软件开发概念都是在本书中被正式提出的。

我不可能在一篇博客中全面地回顾 DDD。和 DDD 相关的重要概念实在是太多了。幸好,这篇文章志不在此。而我要做的就是列出一些 DDD 概念,我认为这些概念对我喜欢的组织代码方式和我对架构的看法而言更有意义:系统范围内构成特性开发基础的概念。

在这片文章里,我将着重探讨:

统一语言

在软件开发中,围绕着代码的理解始终有一些问题,代码是什么,它们干了什么,它们如何做到的,它们为什么要这么做...如果代码中使用的术语和领域专家使用的术语不一样的话就更复杂了,例如,领域专家谈到的是老用户而代码谈到的却是管理者,在讨论应用是这可能带来很多的困惑。但是,绝大多数的混淆都可以通过正确的命名类和方法来解决,让它们表达出在领域上下文中对象是什么以及方法干了什么。

统一语言的主要思想是让应用能和业务相匹配。这是通过在业务和代码中的技术之间采用共同的语言达成。这门语言起源于公司的业务侧-他们拥有需要实现的概念,语言中的术语由他们和公司的技术侧通过协商来定义(意味着业务侧也不能总是选到最好的命名),目标是创造可以被业务、技术和代码自己无歧义使用的共同术语,即统一语言。代码、类、方法、属性和模块的命名必须和统一语言相匹配。必要的时候需要对代码进行重构!

分层

之前的文章中我已经谈到过分层,但我觉得这里关键的是记住通过 DDD 识别的层次:

限界上下文

在企业应用中,模型和工作在代码仓库之上的团队规模都增长得很快。这会给我们带来两个问题:

  1. 开发者工作的代码仓库越大,认知超载就越严重,代码就越难理解,这会导致 BUG 的产生和错误的判断;
  2. 在同一个代码仓库上工作的开发者越多,就越难协作以及达成共同的应用领域和技术愿景。

换句话说,我们面临的问题太大了。

通常的解决方法就是把大问题切分成较小的问题,“限界上下文”就是这样干的。

一般来说,两个子系统一定服务于迥然不同的用户群体。——Eric Evans 2014, Domain-Driven Design Reference

限界上下文定义了一个模型中分离的部分可以适用的上下文。这种隔离可以通过解耦技术逻辑,分割代码仓库,分割数据库 Schema 或者团队组织方式来达成。和往常一样,限界上下文将拆分到何种程度取决月实际情况:我们的需求和可能性。

有趣的是,这不是一个全新的概念。早在 1992 年,Ivar Jacobson 在他的中就有子系统的描述,比 Eric Evans 早了十一年!

那时他就提出了一些关于这个主题的具体想法:

防腐层

防腐层基本就是两个系统之间的中间件。它用来隔离两个子系统,让它们都依赖防腐层而不是直接互相依赖。这样,如果我们重构或者完全替换掉其中一个子系统时,只需要更新防腐层,而不需要动其它的子系统。

在将一个新系统和遗留系统进行集成时防腐层特别有用。为了不让遗留的结构显著我们设计新系统的想像力,我们会创建一个防腐层,将遗留子系统的 API 按照新的子系统的需要进行适配。

它有三个主要关注点:

  1. 按照客户端子系统的需要对其它子系统 API 进行适配;
  2. 对系统间传递的数据和命令进行转换;
  3. 根据需要建立单向或多向的通信。

当我们无法控制全部子系统或某个子系统时,使用这项技术的理由更加充分。但在我们能控制所有涉及的子系统时,这项技术也有意义,尽管这些子系统设计良好但仅仅是拥有迥然不同的模型,而我们想要组织一个模型对另一个模型的侵蚀(为了满足一个子系统的需要而修改另一个子系统)。

共享内核

在某些情况下,我们除了渴望完全隔离和解耦的组件之外,在多个组件之间共享一些领域代码也很有意义。

这会让组件之间保持解耦,尽管他们会和同一份代码——共享内核——耦合在一起。

例如,有由一个组件触发并由其它一个或多个组件监听的事件就是这样的例子。但服务接口和事件实体也可能是这样。

不过,我们应该限制共享内核的大小,对它进行修改时要小心翼翼,才不会毫不知情地破坏使用它的代码。共享内核中的代码不经过其它使用它的团队的同意就不能修改,这一点非常重要。

通用子域

子域是领域中非常独立的一部分。通用子域并非是特定于我们的应用的子域,它可以在任何类似的应用中使用。

所以,如果我们的应用中有一部分是关于财务的,也许我们可以在应用中使用现有的财务相关的库。但是,无路以哪种方式实现,哪怕我们没有现成的库可用而要自己构建,如果这部分是通用子域,那么它就不是我们的核心业务,它应该被当作必要的而非决定性的因素。它不是我们应用中最重要部分,所以不是我们最好的专家重点关注的地方,毫无疑问它甚至不应该在主要的源代码之中,可能是通过依赖管理工具安装的。

结语

再一次说明,这里我选择探讨的 DDD 概念多是关于单一职责、低耦合、高内聚、逻辑隔离,这样我们的应用才能变得更一致、更简单、更快地变化并适应业务的需要。

引用来源

1992 – Ivar Jacobson – Object-Oriented Software Engineering: A use case driven approach
1996 – Robert C. Martin – Granularity
2003 – Eric Evans – Domain-Driven Design: Tackling Complexity in the Heart of Software
2014 – Eric Evans – Domain-Driven Design Reference

上一篇 下一篇

猜你喜欢

热点阅读