编写领域代码

在本节中,我们将探讨在编写领域模型代码时需要考虑的一些事项。我们将讨论在领域模型中应该使用和不应该使用哪些类型的库,如何处理应用程序的配置和初始化,以及思考流行的框架对我们的设计有何影响。

决定领域模型中应该包含什么

我们的领域模型是应用程序的核心,而六边形架构将其置于最前沿和中心位置。一个好的领域模型是使用用户问题领域的语言编写的;这也是 “领域模型” 这一名称的由来。我们应该看到用户能够识别的程序元素名称。我们应该能够识别出正在解决的问题,而不仅仅是解决问题的机制。理想情况下,我们会在领域模型中看到用户故事中的术语。

在应用六边形架构时,我们选择让领域模型独立于那些对解决问题并非必需的事物。这就是为什么外部系统被隔离的原因。我们最初可能会认为,创建销售报告意味着我们必须读取文件并生成 HTML 文档。但这并不是问题的核心。我们只需要从某个地方获取销售数据,执行一些计算以生成报告的总计,然后以某种方式格式化它。这个 “某个地方” 和 “某种方式” 可以改变,而不会影响我们解决方案的本质。

牢记这一约束,我们可以采用任何标准的分析和设计方法。我们可以自由选择对象或将它们分解为函数,就像我们通常所做的那样。我们只需要保持问题本质与实现细节之间的区别。

在这些决策中,我们需要运用判断力。在我们的销售报告示例中,销售数据的来源并不重要。作为一个反例,假设我们正在为 Java 程序文件制作一个代码检查工具(linter)——在领域模型中直接表示文件的概念是非常合理的。这个问题领域完全是关于处理 Java 文件的,因此我们应该明确这一点。我们仍然可以将文件的领域模型与操作系统特定的读写细节解耦,但文件的概念应该存在于领域模型中。

在领域模型中使用库和框架

领域模型可以使用任何预先编写的库或框架来帮助完成其工作。像 Apache Commons 或 Java 标准运行时库(Java Standard Runtime Library)这样的流行库通常不会带来问题。然而,我们需要警惕那些将我们与外部系统和适配器层绑定的框架。我们需要反转对这些框架的依赖,使它们仅成为适配器层的实现细节。

一个例子可能是 Spring Boot 中的 @RestController 注解。乍一看,它似乎是纯粹的领域代码,但它将类紧密地绑定到特定于 Web 适配器的生成代码上。

决定编程方法

领域模型可以使用任何编程范式来编写。这种灵活性意味着我们需要决定使用哪种方法。这从来都不是一个纯粹的技术决策,就像软件中的许多事情一样。我们应该考虑以下因素:

  • 现有团队的技能和偏好:团队最熟悉哪种范式?如果有机会,他们更愿意使用哪种范式?

  • 现有的库、框架和代码库:如果我们要使用预先编写的代码——让我们面对现实,我们几乎肯定会这样做——那么哪种范式最适合这些代码?

  • 风格指南和其他代码要求:我们是否在使用现有的风格指南或范式?如果我们的工作是有偿的——或者我们正在为现有的开源项目做贡献——我们需要采用为我们设定的范式。

好消息是,无论我们选择哪种范式,我们都能够成功地编写领域模型。虽然代码可能看起来不同,但使用任何一种范式都可以编写出等效的功能。