moduliths: 使用Spring Boot构建模块化单体架构的工具

22-08-20 banq

在设计应用程序时,我们目前处理两种架构方法:单体应用程序和微服务。虽然通常以相反的方法呈现,但在极端情况下,它们实际上形成了特定应用程序架构可以定位的范围的末端。小型系统的趋势受到以下事实的强烈推动:单体应用程序往往会随着时间的推移在架构上退化,即使——在它们生命的开始——定义了一个架构。随着时间的推移,架构违规行为会悄悄潜入项目中。随着系统变得更难改变,可演化性受到影响。

另一方面,微服务承诺更强大的分离手段,但同时引入了很多复杂性,因为即使是小型应用程序团队也必须应对分布式系统的挑战。
这个 repo 就像一个游乐场,可以尝试不同的方法来定义模块化的单体,这样就可以很容易地随着时间的推移保持模块化并及早发现违规行为。这将保持随着时间的推移修改和推进代码库的能力,并简化拆分系统以尝试将其部分提取到专用项目中的工作。

Moduliths 是基于 ArchUnit 的 Spring Boot 扩展,旨在实现以下目标:

[list]

[*]验证单体 Spring Boot 应用程序中各个逻辑模块之间的模块化结构。
防止循环依赖以及明确定义允许的对其他模块的依赖。验证对 API 包中公共组件的访问(基于约定,可定制)。

[*]引导单一 Spring Boot 应用程序的模块子集。
将 Spring Boot 的引导(组件扫描和自动配置的应用)限制为单个模块、一个模块及其直接依赖项或整个树。

[*]派生有关模块的 PlantUML 文档。
通过 Structurizr 将实际模块结构转换为 PlantUML 组件图,以便轻松包含在基于 Asciidoctor 的文档中。可以一次为单个模块及其协作者或整个系统呈现图表。

[/list]

架构代码差距
在软件项目中,架构设计决策和约束通常以某种方式定义,然后必须在代码库中实现。传统上,架构决策和实际情况之间的联系一直是命名约定,这些约定很容易产生分歧,并导致在代码库中实际实现的架构随着时间的推移而缓慢退化。我们希望探索架构和代码之间更强大的连接方式,甚至研究对框架和库的高级支持,例如允许对整个系统中的各个组件进行可测试性。
已经有多种技术试图从架构定义方面弥合这种差距,主要是通过尝试以可执行形式捕获架构定义(请参阅jQAssistant现有工具)并验证代码库是否符合定义的约定。在这个操场上,我们将探索相反的方式:提供约定以及库和框架手段,直接在代码库中表达架构定义,主要目标有两个:

[list=1]

[*]让约定的验证更接近代码/开发人员 ——如果架构决策是由开发团队驱动的,那么在代码库中定义架构概念可能会感觉更自然。架构规则验证系统与代码库集成得越无缝,使用该系统的可能性就越大。可以由编译器验证的架构规则优先于通过执行测试验证的规则,而后者又优于通过专用构建步骤进行的验证。

[*]与现有工具集成——即使与现有工具结合使用,它也可能只是帮助他们提供开箱即用的通用架构规则,开发人员只需遵循约定或显式注释代码以触发实际验证。

[/list]

设计目标

[list]

[*]使开发人员能够编写架构上明显的代码,即提供在代码中表达架构概念的方法,以缩小两者之间的差距。

[*]提供方法来验证尽可能接近代码的定义的架构约束(通过编译器,通过测试或其他构建工具)。

[*]尽可能少的侵入性技术。即,我们更喜欢记录的约定而不是所需的类型依赖关系的注释。

[/list]

快速开始

[list=1]

[*]创建一个简单的 Spring Boot 应用程序(例如通过 Spring Initializer)。

[*]将 Moduliths 依赖项添加到您的项目中:<dependencies>

 

<!-- For the @Modulith annotation -->
  <dependency>
    <groupId>org.moduliths</groupId>
    <artifactId>moduliths-core</artifactId>
    <version>${modulith.version}</version>
  </dependency>

  <!-- Test support -->
  <dependency>
    <groupId>org.moduliths</groupId>
    <artifactId>moduliths-test</artifactId>
    <version>${modulith.version}</version>
    <scope>test</scope>
  </dependency>
</dependencies>

<!-- If you use snapshots -->
<repositories>
  <repository>
    <id>spring-snapshots</id>
    <url>https://repo.spring.io/libs-snapshot</url>
  </repository>
</repositories>

[*]像这里描述的那样设置你的包结构。

[*]像这里描述的那样创建一个模块测试。

[/list]