领域驱动设计的开始

软件不仅仅是代码。 如果你仔细想想,代码很少是我们这个职业的最终目标。 代码只是解决业务问题的媒介。 那么为什么我们要谈一种不同的语言呢? 领域驱动设计强调确保企业和软件使用同一种语言。 一旦打破这个障碍,就不需要翻译或繁琐的同步,信息也不会丢失。 每个人都有助于发现业务领域,而不仅仅是程序员。 由此产生的软件是共同语言的唯一真理。

为什么领域驱动设计很重要

软件不仅仅是代码。 如果你仔细想想,代码很少是我们这个职业的最终目标。 代码只是解决业务问题的媒介。 那么为什么我们要谈一种不同的语言呢? 领域驱动设计强调确保企业和软件使用同一种语言。 一旦打破这个障碍,就不需要翻译或繁琐的同步,信息也不会丢失。 每个人都有助于发现业务领域,而不仅仅是程序员。 由此产生的软件是共同语言的唯一真理。

领域驱动设计它还为战略和战术设计提供了一个框架 - 战略性地确定了基于业务价值开发的最重要领域,以及构建一个由经过实战考验的构件和模式组成的工作领域模型的战术。

领域驱动设计的三大支柱

  • Ubiquitous Language(无处不在的语言) 领域专家和软件开发人员共同为正在开发的业务领域构建通用语言。 开发软件是一项商业投资,而不仅仅是一项成本。 构建无处不在的语言(Ubiquitous Language)可以在团队成员中传播深层的领域洞察力。

  • Strategic Design(战略设计) 领域驱动设计的战略不仅仅是技术方面,而是业务方向背后的战略。 它有助于定义内部关系和早期预警反馈系统。 在技术方面,战略设计通过提供如何实现面向服务的体系结构服务的动机来保护每一项业务服务。

  • Tactical Design(战术设计) 领域驱动设计提供了迭代软件交付的工具和构建模块。 战术设计工具生成的软件不仅是正确的,而且是可测试的,更不容易出错。

无处不在的语言(Ubiquitous  Language)

如果我们刻意去探索和总结无处不在的语言(Ubiquitous  Language),往往会有以下几个相同点:

  • 识别关键业务流程、它们的输入和输出
  • 创建术语和定义的词汇表
  • 使用某种文档来获取重要的软件概念
  • 与团队的其他成员(开发人员和领域专家)共享和扩展所收集的知识
事件风暴(Event Storming)

事件风暴是一种用于快速探索复杂业务领域的研讨会格式:

  • 它很强大: 它让我和许多从业者能够在数小时而不是数周内提出完整业务流程的综合模型。
  • 它很有吸引力:整个想法是把有问题的人和知道答案的人聚集在同一个房间里,一起建立一个模型。
  • 它很高效:最终的模型与领域驱动设计实现风格完美一致(特别适合事件溯源法(Event Sourcing approach)),并允许快速确定上下文和聚合边界。
  • 它很简单: 这个符号非常简单。 没有复杂的 UML 可能会切断参与者与讨论的核心的联系。
  • 它很有趣:我总是很愉快地领导研讨会,人们充满活力,并提供比他们预期的更多。 出现了正确的问题,气氛也是正确的。

考虑使用领域驱动设计

领域驱动设计并不是万能的; 就像软件中的所有东西一样,它取决于上下文。 作为一个经验法则,只使用它来简化您的域,但绝不要增加更多的复杂性。

如果你的应用程序是以数据为中心的,而你的用例主要是操纵数据库中的行和执行 CRUD 操作ーー即创建、读取、更新和删除ーー那么你就不需要领域驱动设计。 相反,你的公司唯一需要的是在你的数据库前面有一张花哨的脸(完善的ORM)。

如果您的应用程序少于30个用例,那么使用 Symfony 或 Laravel 这样的框架来处理业务逻辑可能会更简单。

然而,如果您的应用程序有超过30个用例,那么您的系统可能正朝着可怕的大泥球的方向移动。 如果你确信你的系统将会变得越来越复杂,你应该考虑使用领域驱动设计来对抗这种复杂性。

如果您知道您的应用程序将会增长并且可能经常更改,那么领域驱动设计应用程序肯定会帮助您管理复杂性并随着时间的推移重构您的模型。

如果您不了解您正在处理的域,而且以前没有人提出过解决方案,这可能意味着它已经足够复杂,您可以开始应用领域驱动设计。 在这种情况下,您需要与领域专家密切合作,以获得正确的模型。

棘手的部分

应用领域驱动设计并不容易。 需要时间和精力来解决业务领域,术语,研究和与域专家的协作,而不是编写行话。 您需要拥有领域专家的承诺才能参与该过程。 这将需要开放和健康的持续对话,以将他们的口语建模为软件。 最重要的是,我们必须努力避免在技术上思考,首先认真考虑对象的行为和普适语言。

战略概述

为了对领域驱动设计的战略方面提供一个总体概述, 考虑两个不同的空间: 问题领域(problem space)和解决方案领域(solution space)。


在问题领域中,领域驱动设计使用域和子域来分组和组织公司想要解决的问题。 就在线旅行社(OTA)而言,问题在于处理机票和预订酒店等事宜。 可以将此类域组织到不同的子域中,例如定价,库存,用户管理等。


在解决方案领域,领域驱动设计提供了两种模式:有界上下文和上下文映射。目标是通过定义其交互和这些交互的详细信息来定义如何为所有已识别的子域提供实现。继续OTA示例,每个子域将通过有界上下文实现来解决 - 例如,考虑由团队为定价管理子域开发的自定义Web应用程序,以及用户管理子域的现成解决方案。上下文映射将显示每个有界上下文如何与其余上下文相关联。在上下文映射中,我们可以看到两个有界上下文所具有的关系类型(例如: 客户-供应商,合作伙伴)。 理想的方法是通过一个有界上下文实现每个子域,,但这并不总是可行的。 从实现的角度来说,当你遵循领域驱动设计时,你最终会得到分布式体系结构。 正如您可能已经知道的,分布式体系结构比单块体系结构更复杂,那么为什么这种方法是有趣的,特别是对于大型和复杂的公司? 这真的值得吗? 是的。

事实证明,分布式体系结构可以提高公司的整体生产力,因为它们可以为您的产品定义可由专注团队开发的边界。

如果您的域 - 您需要解决的问题 - 并不复杂,应用领域驱动设计的战略部分可能会增加不必要的开销并降低您的开发速度。

相关技术运动: 微型服务和自包含系统

随着领域驱动设计的推广,也促进了微服务和自包含系统的架构的诞生。


微服务架构风格是一种将单个应用程序开发为一套小型服务的方法,每个小型服务都在自己的进程中运行,并使用轻量级通信协议(通常是HTTP REST API)。 这些服务是围绕业务功能构建的,并且可以使用完全自动化的机制进行独立部署。 这些服务只有最低限度的集中管理,可以用不同的编程语言编写,也可以使用不同的数据存储技术。

微服务就是领域驱动设计有界上下文的实现。


自包含系统方法是一种体系结构,它侧重于将功能分离到许多独立的系统中,使得完整的逻辑系统成为许多较小的软件系统的协作。 这避免了大型单体结构不断增长并最终变得不可维护的问题。 在过去的几年里,我们已经在许多中型和大型项目中看到了它的好处。 其思想是将一个大型系统拆分为若干个遵循某些规则的较小的独立系统(SCS)。

该网站还阐述了SCS的八个特征:

  1. 每个 SCS 都是一个独立的 web 应用程序。 对于 SCS 的所有数据,其处理这些数据的逻辑和呈现 web 界面的所有代码都包含在 SCS 中。 SCS 可以自己完成其主要用例,而不必依赖其他可用的系统。

  2. 每个 SCS 由一个团队拥有。 这并不一定意味着只有一个团队可以更改代码,但拥有代码的团队对代码库中的内容拥有最终决定权,例如通过合并 pull-requests。

  3. 与其他SCS或第三方系统的通信尽可能是异步的。 具体而言,不应在SCS自己的请求/响应周期内同步访问其他SCS或外部系统。这解耦了系统,减少故障的影响,从而支持自治。目标是关于时间的解耦:即使其他SCS暂时离线,SCS也应该正常工作。  即使在技术层面上的通信是同步的,也可以实现这一点,例如通过复制数据或缓冲请求。

  4. SCS可以具有可选的服务API。 因为SCS有自己的Web UI,所以它可以与用户交互。 但是,移动客户端或其他SCS对于API可能仍然需要。

  5. 每个 SCS 必须包括数据和逻辑。 要真正实现任何有意义的特性,两者都是必需的。 一个 SCS 应该自己实现特性,因此必须同时包括这两个特性。

  6. SCS应该通过自己的UI使其功能对最终用户可用。 因此,SCS应该没有与其他SCS共享的UI。 SCS可能仍然具有彼此的链接。 但是,异步集成意味着即使另一个SCS的UI不可用,SCS仍应工作。

  7. 为避免紧密耦合,SCS不应与其他SCS共享业务代码。 为SCS创建拉取请求或使用公共库可能没什么问题,例如:数据库驱动程序或oAuth客户端。

  8. 为了使SCS更加健壮并改善解耦,可以最大限度地减少共享基础架构。 例如。 SCS使用共享数据库,其故障、安全性和可扩展性取决于其中央数据库。 但是,由于成本原因,每个SCS使用具有单独模式或数据模型的共享数据库可能是有效的替代方案。

总结

  • 领域驱动设计与技术无关; 它实际上是通过专注于模型来提供您正在工作的领域的价值。 每个人都参与了发现域的过程,开发人员和领域专家通过共享同一种语言 - 无所不在的语言 - 来组建知识库。

  • 领域驱动设计提供战术和战略建模工具来设计高质量的软件。 战略设计针对业务方向,帮助定义内部关系,并通过定义强大的边界在技术上保护每个业务服务。 战术设计为迭代设计提供了有用的构建块。

  • 领域驱动设计只有在特定的情况下才有意义。 它不是解决软件中所有问题的灵丹妙药,所以你是否使用它在很大程度上取决于你处理的复杂程度。

  • 领域驱动设计是一项长期投资,需要积极的努力。 领域专家将被要求与开发人员密切合作,开发人员将不得不从业务角度考虑问题。 最后,商业客户才是需要被满足的人。

参考

Domain Driven Design Distilled by Vaughn Vernon

Domain-Driven Design Reference: Definitions and Pattern Summaries by Eric Evans

Introducing EventStorming

Big Ball of Mud

Applying Domain-Driven Design and Patterns

Microservices Resource Guide

Building Microservices

Self-Contained Systems

Domain-Driven Design in PHP