关于 arch-fitness-functions
面向希望通过自动检查维持架构决策的团队的指南,介绍在 CI 或生产环境运行的架构适应度函数,涵盖依赖规则、层边界和性能属性。
主要功能
- 01架构规则自动化检查
- 02CI 构建失败时阻止违规
- 03静态与动态检查
- 04依赖方向与层边界验证
- 05生产性能属性监测
适用场景
- 01持续执行架构决策
- 02防止模块依赖方向偏离
- 03约束迁移项目的新代码
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill arch-fitness-functions安装后在 Claude Code 中输入/arch-fitness-functions确认已加载。
详细介绍
一句话总结
将架构意图编码为自动化检查,并在每次变更时运行。如果架构规定“领域层不依赖 Spring”,那么一旦违反,适应度函数就会使构建失败。
何时使用此技能
- 某项架构决策至关重要,需要随着时间推移始终成立(依赖方向、层边界、无循环依赖、性能预算)。
- 团队规模足够大,仅靠口头约定“我们说好不做 X”无法确保所有 PR 都遵守。
- 迁移项目(
arch-strangler-fig),需要确保新代码采用新的结构,而不是沿用旧结构。 - 任何原本需要依靠代码审查来发现架构偏移的架构决策。
何时不使用此技能
- 项目很小,只有一名开发者,也没有扩展性问题。
- 架构属性确实主观,无法自动化(例如品味、审美、边缘情况下的命名风格)。
- 过度管控——每条架构规则都有成本;只强制执行那些你愿意据此拦截 PR 的规则。
核心内容
适应度函数是一种用于断言架构属性的测试。与单元测试一样,它们会:
- 在 CI 中随每次变更自动运行。
- 违反规则时使构建失败。
- 以可执行的形式记录架构意图。
适应度函数的类别(Ford、Parsons、Kua,Building Evolutionary Architectures):
- 原子型与整体型。 原子型检查单一属性(此模块中没有循环依赖)。整体型结合多个属性(负载下的性能与正确性)。
- 触发型与持续型。 触发型在每次构建时运行(最实用)。持续型在生产环境中运行(延迟预算、错误率)。
- 静态型与动态型。 静态型分析代码(依赖方向)。动态型运行系统(响应时间检查)。
常见的静态适应度函数(最适合作为入门选择):
- 依赖方向。 “模块 X 不得依赖模块 Y。”通过构建图或专用库强制执行(JVM 使用 ArchUnit,TypeScript 使用 ts-arch,JS 使用 dependency-cruiser)。
- 无循环依赖。 检测因导入位置不当而意外引入的循环依赖。
- 命名约定。 “
controller/中的每个类都必须以Controller结尾。”大多只是表面规范,但实施成本低。 - 公共 API 稳定性。 “此接口上新增公共方法时,必须有对应的测试。”可通过自定义检查实现。
- 层边界违规。 “
domain/中的代码不得导入infrastructure/中的内容。”这是经典的六边形架构检查。
用于生产架构的动态适应度函数:
- p99 延迟低于阈值。
- 限制内存用量。
- 确保特定业务不变量成立(余额不为负;订单不重复)。
ArchUnit 示例(JVM,生态最成熟):
@ArchTest
val domainHasNoSpringDependencies =
noClasses().that().resideInAPackage("..domain..")
.should().dependOnClassesThat().resideInAPackage("org.springframework..")
决策启发
- 从一两个用于强制执行最重要架构属性的适应度函数开始(通常是依赖方向)。随着架构偏移问题逐渐显现,再逐步添加。
- 让适应度函数失败时使构建失败——被忽略了一年的警告,不算适应度函数。
- 将适应度函数视为测试:每个函数都应有清晰的失败消息,解释规则为何存在,而不只是检查什么。
- 不要为你不会据此拦截 PR 的规则编写适应度函数。
- 对于迁移项目,适应度函数可以编码“新代码必须放在路径 X 中,而不是旧路径 Y 中”——这对确保迁移按计划进行至关重要。
反模式
- 无人负责的适应度函数。 出问题 → 有人将其禁用 → 从此一直被绕过。
- 过度监管。 数百个适应度函数强制执行每项偏好。CI 变慢;开发者学会忽略失败。
- 把风格当作架构。 “所有方法名都必须使用 camelCase”是 lint 规则,不是适应度函数。不要滥用这个术语。
- 只有文档,没有自动化。 Wiki 页面描述了架构;没有自动化检查;新成员几周内就会违反约定。
- 一次性检查。 只做一次架构审计,然后把结果归档。之后架构漂移立即开始累积。
另请参阅
arch-layered— 层边界是适应度函数的典型用例。arch-hexagonal— 依赖关系指向领域,是典型的六边形架构适应度函数。arch-adr— 适应度函数编码的是是什么;ADR 解释的是为什么。两者应配合使用。
参考资料
- Neal Ford、Rebecca Parsons、Patrick Kua,Building Evolutionary Architectures(O'Reilly,第 2 版)——奠基性参考资料。
- ArchUnit 文档(JVM)。
- Richards 和 Ford,Fundamentals of Software Architecture,治理 / 适应度章节。
评论
支持 Markdown