软件开发的界限

2025/05/03

1. 简介

“软件架构是一门画线的艺术,我称之为‘边界’。这些边界将软件元素彼此分离,并限制一边的元素了解另一边的元素。”-Robert C. Martin。这句话摘自Uncle Bob的《整洁架构》一书,完美地诠释了软件开发中边界的本质。

在本教程中,我们将探讨边界的概念及其在软件架构各个层面的重要性。

2. 界限的重要性

我们系统不同部分之间的边界使每个部分能够独立运行,这种分离有助于简化系统的开发、部署和测试。通过创建清晰的边界,我们获得了灵活性,使我们能够更有效地维护系统,并避免陷入“泥球”的陷阱-一个代码杂乱、难以管理的系统

接下来我们来探讨一下软件工程中的一个基本概念:“低耦合,高内聚”。

2.1 低耦合、高内聚

耦合和内聚是两个相关的概念,由Larry Constantine在20世纪60年代末提出。我们通常的目标是在模块之间实现低耦合和高内聚,模块的大小可能差异很大,从类的大小到分布式架构中的完整服务。接下来,我们将分别描述这两个概念,并了解低耦合和高内聚如何帮助我们。

2.2 耦合

耦合度是指软件模块之间相互依赖的程度,如果两个模块紧密相连,则它们耦合度高。换句话说,如果一个模块的变更会触发另一个模块的变更,我们就可以说这两个模块耦合度高。相反,耦合度低的模块彼此之间相对独立。

松散耦合的模块更易于开发和维护,并提供更高的灵活性。由于模块之间相互独立,我们可以构建、测试和部署一个模块而不会影响其他模块。它们还可以独立地进行修改和更新,这在复杂的架构中至关重要。

如果系统各部分之间耦合度高,这些优势就会丧失。更新一个模块会变得困难,因为它会触发其他模块的链式更新。此外,测试也会变得非常具有挑战性,因为我们需要Mock许多调用或同时测试多个模块。

因此,松耦合的模块体现了我们系统的高质量,我们应该致力于设计尽可能独立的模块。但是,低耦合度通常是可以接受的,因为要让所有模块完全解耦是非常困难的。

值得注意的是,紧密耦合的模块并不总是坏事。我们可以容忍高内聚元素之间更高的耦合度,我们将在下一节中探讨这一点

2.3 内聚

内聚性是指模块内部元素之间的关联程度,简而言之,“一起修改的代码将保持完整”,高内聚性的模块仅包含彼此紧密相关的元素。相反,低内聚性的模块包含彼此不相关的元素。内聚性的概念与单一职责原则相关,该原则规定一个模块应该只有一个职责,因此也应该只有一个修改的理由。

高内聚的模块显著提升了可维护性,这些模块更易于理解和更新,因为所有相关代码都封装在模块内部。高内聚简化了开发、测试和部署流程,因为更改仅限于单个独立的模块。

与低耦合一样,高内聚也是高质量系统设计的指标。当模块定义明确且内聚时,整个系统架构会变得更加健壮、灵活且易于管理。

3. 边界的类型

在软件开发中,边界的概念非常广泛。边界可以存在于各个层面,从源代码级别到分布式架构中的独立服务。每种类型的边界都有不同的用途,并以各自的方式帮助管理复杂性。

今天,我们将重点讨论源代码级别的边界,理解这些边界对于构建模块化且可维护的应用程序至关重要。

4. 源代码边界

现在我们专注于源代码级别的边界,可以探索几种关键类型。此外,我们将从面向对象编程语言的角度来描述它们。

4.1 封装

封装是一种通过定义明确的接口隐藏内部细节并仅公开必要功能的做法,虽然封装通常用于向其他类隐藏某个类的成员,但它也可以通过选择性地公开某些功能,将封装应用于整个包或模块。

这一原则通过隐藏目标的内部复杂性来简化其使用。此外,封装允许内部更改而不会影响依赖于目标的外部代码,这对于可维护性而言至关重要。通过限制对某些组件的访问,封装还可以增强安全性,并降低对类或模块内部工作造成意外干扰的风险。

4.2 分层

分层架构是一种设计方法,将应用程序划分为多个独立的水平层,这些层作为一个单元协同工作,常见的层包括:

  • 表示层
  • 应用/业务层
  • 领域层
  • 基础设施/持久层/数据库层

该架构中的每一层都有特定的角色,并根据技术功能划分了界限。这种分离增强了模块化,促进了代码组织,并提高了可读性。

然而,虽然每一层在设计上都独立于其他层级,但层与层之间存在着内在的依赖关系。例如,每一层都依赖于其上一层。这种依赖关系意味着,虽然各层在逻辑上是相互独立的,但它们之间并非完全解耦:

4.3 垂直切片

垂直切片是一种基于业务功能而非技术层来组织系统的方法,在这种方法中,每个垂直切片跨越所有必要的水平层,以提供特定的业务功能或用例:

这种方法有几个优点,每个切片独立运行,这使得特定业务功能的更改和更新更加便捷,而不会影响系统的其他部分。此外,通过将与特定特性或功能相关的所有代码分组,垂直切片增强了每个切片内的内聚性,使业务逻辑更易于管理和理解

垂直切片也与领域驱动设计(DDD)原则和有界上下文完美契合,每个切片可以对应系统内不同的有界上下文或领域,从而有助于维护清晰的边界。此外,垂直切片通过清晰地分离每个切片的命令和查询,补充了命令查询职责分离(CQRS)

4.4 领域驱动设计和有界上下文

领域驱动设计(DDD)是一种设计软件系统的战略方法,它强调关注业务领域及其复杂性。DDD中的一个关键概念是“有界上下文”模式,它有助于将应用程序领域划分为可管理的不同部分。

有界上下文可以定义为应用程序域内的逻辑边界,包含其自己的一组规则、语言和模型。

例如,下图可能突出显示电子商务应用程序中的两个有界上下文:

该图像摘自文章《Bounded Context》(来源)。

此外,这种方法还能降低系统不同部分之间的耦合度。每个有界上下文都是独立的,允许在一个上下文中进行更改而不会影响其他上下文。通过建立清晰的上下文,开发人员可以更好地理解每个上下文中的领域,从而更有效地进行设计和实现。有界上下文还能灵活地使用根据每个上下文的特定需求定制的不同数据模型、技术和流程,从而增强系统的整体适应性。

4.5 模块化整体式架构

模块化单体架构的概念体现了一种混合架构方法,它融合了单体架构和模块化设计的特点。与传统的单体应用不同,传统的单体应用将所有组件紧密集成到一个单元中,而模块化单体架构通过将应用程序划分为多个定义明确的模块,从而引入了更有条理的结构:

这些模块通常以特定的业务功能为中心,在应用程序中创建清晰的边界。这种组织方式通过将功能封装在每个模块中,从而改善关注点分离,从而提高代码库的可管理和维护性。对一个模块的更改不太可能影响其他模块,从而简化维护和更新。

4.6 领域中心架构

接下来,我们将深入探讨领域中心架构:六边形架构、洋葱架构和清洁架构。虽然每种方法都有其独特的特点,但它们都有一个共同的核心原则:将领域与外部关注点分离,从而创建一个独立的单元。

这些架构的核心理念是将领域逻辑与其他层(例如基础架构层或表示层)隔离,这种分离带来了显著的优势,包括能够灵活地切换技术,同时最大程度地减少对核心业务逻辑的影响。例如,如果将领域逻辑从数据库层抽象出来,那么从关系数据库转换到非关系数据库就变得非常简单。核心业务规则不会受到数据存储技术变化的影响,从而能够更敏捷地适应不断变化的需求。

这些架构还利用依赖倒置等原则和适配器模式等模式来保护领域免受外部依赖的影响,这种保护在与第三方服务或库集成时至关重要,通过依赖抽象而非具体的实现,这些架构确保领域层与外部更改保持隔离

5. 总结

正如我们在本文中所发现的,在软件开发中创建边界可以通过各种方法实现,每种方法都具有独特的优势。无论选择哪种方法,核心目标始终不变:增强可维护性,并确保应用程序在发展过程中保持适应性和可管理性。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章