Arch Day 25: 架构文档工程化 — 从"写了没人看"到"活的文档"
架构文档工程化是将架构文档从"Word/Confluence上的一次性产物"升级为和代码一样可版本控制、可自动验证、可持续更新的工程制品——核心三要素:arc42模板(写什么)+ Docs-as-Code(怎么写)+ Fitness Functions(怎么验证)。
日期: 2026-04-24 (Day 25) 阶段: 第一阶段 - 架构基础 标签: #arc42 #DocsAsCode #FitnessFunctions #LivingDocumentation #ArchUnit
核心概念
一句话定义
架构文档工程化是将架构文档从"Word/Confluence上的一次性产物"升级为和代码一样可版本控制、可自动验证、可持续更新的工程制品——核心三要素:arc42模板(写什么)+ Docs-as-Code(怎么写)+ Fitness Functions(怎么验证)。
为什么资深架构师仍需关注
| 痛点 | 频率 | 后果 |
|---|---|---|
| "架构文档写了但没人看" | 每个项目 | 文档变废纸,新人只能口口相传 |
| "文档和代码严重脱节" | 3个月内 | 按文档理解系统的人踩坑 |
| "架构约束被违反但无人发现" | 每天 | 架构腐化,最终变成"大泥球" |
| "每次迁移都要重新理解系统" | 每次交接 | 知识丢失,学习成本翻倍 |
| "合规审计时找不到架构文档" | 年度审计 | 审计发现→整改→罚款 |
在金融行业,架构文档不是"nice to have"而是"must have"——银保监的IT治理指引明确要求金融机构维护系统架构文档并定期更新。
常见误区与反模式
| 误区 | 真相 |
|---|---|
| "文档越详细越好" | 详细但过时的文档比没有文档更危险(误导人) |
| "用Word/PPT写就行" | 二进制格式无法diff/merge,多人协作困难 |
| "写完一次就行了" | 架构文档的价值和"鲜度"正相关,过时的文档价值为负 |
| "开发者应该看代码,不需要文档" | 代码说明"是什么",文档说明"为什么" |
| "文档模板越标准越好" | 模板只是起点,必须根据项目裁剪,80%的项目只需要arc42的40%章节 |
知识点详解
知识点1:arc42模板12章精要
arc42是最流行的架构文档模板,12个章节覆盖架构决策的所有关键方面。但不是每个章节都必须写——以下是金融系统的裁剪建议:
| 章节 | 内容 | 金融系统必要性 | 建议深度 |
|---|---|---|---|
| 1. Introduction & Goals | 需求概览、质量目标、干系人 | ★★★★★ 必写 | 1-2页 |
| 2. Constraints | 技术/组织/合规约束 | ★★★★★ 必写 | 1页(金融合规是核心约束) |
| 3. Context & Scope | 系统上下文、边界 | ★★★★★ 必写 | C4 Context图 + 说明 |
| 4. Solution Strategy | 整体技术方案、关键决策 | ★★★★★ 必写 | 1-2页 + ADR链接 |
| 5. Building Block View | 系统分解(容器→组件) | ★★★★★ 必写 | C4 Container/Component图 |
| 6. Runtime View | 运行时行为、关键流程 | ★★★★ 推荐 | 3-5个核心流程的序列图 |
| 7. Deployment View | 部署架构、基础设施 | ★★★★★ 必写 | C4 Deployment图 + 环境说明 |
| 8. Crosscutting Concepts | 横切关注点 | ★★★★ 推荐 | 安全/日志/错误处理/... |
| 9. Architecture Decisions | ADR记录 | ★★★★★ 必写 | 链接到ADR目录 |
| 10. Quality Requirements | 质量属性场景 | ★★★★ 推荐 | 质量属性树 + 场景表 |
| 11. Risks & Technical Debt | 风险和技术债 | ★★★★★ 必写 | 风险矩阵 + 技术债清单 |
| 12. Glossary | 术语表 | ★★★ 可选 | DDD ubiquitous language |
最小可行架构文档(MVP)= 章节1 + 3 + 4 + 5 + 7 + 9 + 11
知识点2:Docs-as-Code方法论
Docs-as-Code的核心理念:文档和代码使用相同的工具链。
传统方式:
Word/PPT → Confluence → 手动更新 → 逐渐过时
Docs-as-Code:
Markdown/AsciiDoc → Git → PR Review → CI渲染 → 自动发布
核心实践:
├── 格式: Markdown 或 AsciiDoc(纯文本,可diff)
├── 存储: 和代码同一个Git仓库(或紧密关联的仓库)
├── 协作: PR + Code Review(和代码一样的流程)
├── 构建: CI自动渲染为HTML/PDF(MkDocs/Docusaurus/Hugo)
├── 发布: 自动部署到内部文档站(和代码部署同步)
└── 验证: 链接检查 + 格式校验 + Fitness Functions
项目目录结构推荐:
project-root/
├── src/ # 源代码
├── docs/ # 架构文档
│ ├── arc42/ # arc42章节
│ │ ├── 01-introduction.md
│ │ ├── 02-constraints.md
│ │ ├── 03-context.md
│ │ ├── 04-solution-strategy.md
│ │ ├── 05-building-blocks.md
│ │ ├── 06-runtime.md
│ │ ├── 07-deployment.md
│ │ ├── 08-crosscutting.md
│ │ ├── 09-decisions.md # → 链接到 decisions/
│ │ ├── 10-quality.md
│ │ ├── 11-risks.md
│ │ └── 12-glossary.md
│ ├── decisions/ # ADR目录
│ │ ├── 001-use-spring-boot.md
│ │ ├── 002-postgresql.md
│ │ └── 003-event-driven.md
│ ├── diagrams/ # 架构图源文件
│ │ ├── workspace.dsl # Structurizr DSL
│ │ └── sequences/ # PlantUML序列图
│ └── images/ # 自动生成的图片
├── mkdocs.yml # 文档站配置
└── .github/workflows/
└── docs.yml # 文档CI/CD
MkDocs配置示例
# mkdocs.yml
site_name: 支付网关架构文档
theme:
name: material
language: zh
palette:
primary: indigo
features:
- navigation.tabs
- navigation.sections
- search.highlight
nav:
- 首页: index.md
- 架构文档:
- 1. 简介与目标: arc42/01-introduction.md
- 2. 约束条件: arc42/02-constraints.md
- 3. 上下文与范围: arc42/03-context.md
- 4. 方案策略: arc42/04-solution-strategy.md
- 5. 构建块视图: arc42/05-building-blocks.md
- 6. 运行时视图: arc42/06-runtime.md
- 7. 部署视图: arc42/07-deployment.md
- 8. 横切概念: arc42/08-crosscutting.md
- 9. 架构决策: arc42/09-decisions.md
- 10. 质量需求: arc42/10-quality.md
- 11. 风险与技术债: arc42/11-risks.md
- 12. 术语表: arc42/12-glossary.md
- 架构决策记录:
- decisions/001-use-spring-boot.md
- decisions/002-postgresql.md
plugins:
- search
- git-revision-date-localized # 显示每页最后更新时间
markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.tabbed
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
知识点3:Architecture Fitness Functions
Fitness Functions是Neal Ford等人在《Building Evolutionary Architecture》中提出的概念:用自动化测试验证架构约束。
传统方式:
架构师写规范 → 开发者可能遵守 → Code Review可能发现 → 可能已经太晚
Fitness Functions:
架构约束 → 自动化测试 → CI/CD执行 → 违反即失败 → 架构不腐化
ArchUnit示例(Java)
// 包依赖规则
@ArchTest
static final ArchRule controllers_should_not_access_repositories =
noClasses()
.that().resideInAPackage("..controller..")
.should().accessClassesThat().resideInAPackage("..repository..")
.because("Controllers should use Services, not Repositories directly");
// 分层约束
@ArchTest
static final ArchRule layer_dependencies_are_respected =
layeredArchitecture()
.consideringAllDependencies()
.layer("Controller").definedBy("..controller..")
.layer("Service").definedBy("..service..")
.layer("Repository").definedBy("..repository..")
.whereLayer("Controller").mayOnlyAccessLayers("Service")
.whereLayer("Service").mayOnlyAccessLayers("Repository")
.whereLayer("Repository").mayNotAccessAnyLayer();
// 命名规范
@ArchTest
static final ArchRule services_should_be_suffixed =
classes()
.that().resideInAPackage("..service..")
.should().haveSimpleNameEndingWith("Service")
.orShould().haveSimpleNameEndingWith("ServiceImpl");
// 安全约束(金融特定)
@ArchTest
static final ArchRule sensitive_data_classes_must_use_encryption =
classes()
.that().areAnnotatedWith(SensitiveData.class)
.should().beAnnotatedWith(Encrypted.class)
.because("All sensitive financial data must be encrypted at rest");
// 事件驱动约束
@ArchTest
static final ArchRule events_should_be_immutable =
classes()
.that().resideInAPackage("..event..")
.should().beAnnotatedWith(Immutable.class)
.because("Domain events must be immutable");
非Java项目的替代方案
| 语言/平台 | Fitness Function工具 | 示例 |
|---|---|---|
| TypeScript | eslint-plugin-import + dependency-cruiser | 模块依赖规则 |
| Python | import-linter | 层间依赖约束 |
| Go | go-arch-lint | 包依赖规则 |
| 通用 | 自定义脚本 | 检查API版本/数据库直连等 |
| .NET | NetArchTest | 类似ArchUnit |
// dependency-cruiser配置示例(TypeScript/JavaScript)
// .dependency-cruiser.js
module.exports = {
forbidden: [
{
name: "no-controller-to-repository",
comment: "Controllers should not directly access repositories",
severity: "error",
from: { path: "^src/controllers" },
to: { path: "^src/repositories" }
},
{
name: "no-circular-deps",
comment: "No circular dependencies allowed",
severity: "error",
from: {},
to: { circular: true }
},
{
name: "no-direct-db-access-from-api",
comment: "API layer must not directly access database drivers",
severity: "error",
from: { path: "^src/api" },
to: { path: "node_modules/(pg|mysql|mongodb)" }
}
]
};
知识点4:Living Documentation理念
Living Documentation(活文档)由Cyrille Martraire提出,核心思想是:文档应该从代码和测试中自动生成,而非手动编写。
传统文档:
人工编写 → 逐渐过时 → 被忽略 → 误导新人
Living Documentation:
代码 + 注释 + 测试 → 自动提取 → 生成文档 → 永远最新
实现方式:
├── API文档: OpenAPI/Swagger → 从代码注解自动生成
├── 数据模型: 从Entity类自动生成ER图
├── 依赖关系: dependency-cruiser自动生成依赖图
├── 行为文档: BDD测试(Cucumber)→ 业务行为说明
├── 架构约束: ArchUnit测试 → 当前架构规则清单
└── 变更日志: Conventional Commits → 自动CHANGELOG
实操示例:从代码生成API文档
// Spring Boot Controller
@RestController
@RequestMapping("/api/v1/payments")
@Tag(name = "支付API", description = "支付网关核心接口")
public class PaymentController {
@Operation(
summary = "创建支付订单",
description = "发起一笔支付请求,返回支付链接或支付凭证",
responses = {
@ApiResponse(responseCode = "201", description = "支付订单创建成功"),
@ApiResponse(responseCode = "400", description = "请求参数错误"),
@ApiResponse(responseCode = "429", description = "触发限流")
}
)
@PostMapping
public ResponseEntity<PaymentResponse> createPayment(
@RequestBody @Valid CreatePaymentRequest request,
@RequestHeader("Idempotency-Key") String idempotencyKey
) {
// ...
}
}
// CI中自动生成文档:
// mvn springdoc-openapi:generate → openapi.json
// npx redoc-cli build openapi.json → api-docs.html
对比分析
架构文档模板对比
| 模板 | 章节数 | 适用规模 | 学习曲线 | 社区活跃度 | 推荐场景 |
|---|---|---|---|---|---|
| arc42 | 12 | 任意 | ★★☆ | ★★★★★ | 通用首选 |
| C4 + ADR | 无模板 | 中小 | ★☆☆ | ★★★★ | 轻量级项目 |
| TOGAF Content Framework | 30+ | 企业级 | ★★★★★ | ★★★ | 大型企业 |
| ISO/IEC 42010 | 自定义 | 大型 | ★★★★ | ★★ | 合规要求 |
| Documenting Software Architectures (SEI) | 自定义 | 大型 | ★★★ | ★★★ | 学术研究 |
Docs-as-Code工具对比
| 工具 | 语言 | 特色 | 适用场景 |
|---|---|---|---|
| MkDocs + Material | Markdown | 美观、插件丰富 | 技术文档(推荐) |
| Docusaurus | MDX | React生态、版本管理强 | 开源项目文档 |
| Hugo | Markdown | 构建最快 | 大型文档站 |
| AsciiDoc + Antora | AsciiDoc | 适合出版级文档 | 复杂技术手册 |
| Sphinx | reStructuredText | Python生态标准 | Python项目 |
| Backstage TechDocs | Markdown | 和开发者平台集成 | 微服务架构文档 |
架构设计实操
实操:支付网关arc42架构文档 + Fitness Functions
01-introduction.md(章节1示例)
# 1. 简介与目标
## 1.1 需求概览
支付网关是面向商户的统一支付接入层,提供:
- 多渠道支付(银行卡/电子钱包/银联/跨境)
- 统一收单接口(降低商户对接成本)
- 实时交易监控与风控
- 资金清结算与对账
## 1.2 质量目标
| 优先级 | 质量属性 | 目标 | 度量方式 |
|--------|---------|------|---------|
| 1 | **可用性** | 99.99%(年不超过52分钟宕机) | 监控告警/SLA报告 |
| 2 | **安全性** | PCI DSS Level 1合规 | 年度审计 |
| 3 | **性能** | P99 < 500ms, TPS > 5000 | APM监控 |
| 4 | **可扩展性** | 支持水平扩展至10x当前流量 | 压测 |
| 5 | **可修改性** | 新支付渠道接入 < 2周 | 交付周期统计 |
## 1.3 干系人
| 干系人 | 关注点 | 期望 |
|--------|--------|------|
| 商户 | 接口简单/稳定/快速 | 完善的SDK和文档 |
| 运营团队 | 交易监控/异常处理 | 实时Dashboard |
| 合规部门 | PCI DSS/反洗钱 | 完整审计日志 |
| 开发团队 | 可维护性/可测试性 | 清晰的架构约束 |
| CFO | 成本控制 | 基础设施成本可预测 |
Fitness Functions定义
# 支付网关架构Fitness Functions
## FF-001: 分层约束
**规则**: Controller层不能直接调用Repository层
**工具**: ArchUnit / dependency-cruiser
**触发**: 每次PR
**失败动作**: 构建失败,PR无法合并
## FF-002: API向后兼容
**规则**: 已发布API的Response字段不能删除,只能新增
**工具**: OpenAPI diff工具(oasdiff)
**触发**: API相关文件变更时
**失败动作**: 告警 + 需要架构师审批
## FF-003: 敏感数据加密
**规则**: 标记为@SensitiveData的字段必须在持久化前加密
**工具**: ArchUnit自定义规则
**触发**: 每次PR
**失败动作**: 构建失败
## FF-004: 幂等性保障
**规则**: 所有支付接口必须支持幂等键(Idempotency-Key)
**工具**: 自定义检查脚本(检查Controller方法签名)
**触发**: 每次PR
**失败动作**: 构建失败
## FF-005: 循环依赖检测
**规则**: 服务间不允许循环依赖
**工具**: dependency-cruiser / JDepend
**触发**: 每次PR
**失败动作**: 构建失败
## FF-006: 文档鲜度
**规则**: arc42核心章节(1/3/5/7/9)的最后更新时间不超过90天
**工具**: 自定义脚本(检查git log)
**触发**: 每周定时任务
**失败动作**: 通知架构师
CI/CD管线
# .github/workflows/architecture.yml
name: Architecture Quality
on: [push, pull_request]
jobs:
fitness-functions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Fitness Function: 分层约束
- name: Check layer dependencies
run: npx dependency-cruiser src --config .dependency-cruiser.js
# Fitness Function: API兼容性
- name: Check API backward compatibility
run: |
git diff HEAD~1 -- openapi.yaml | \
npx oasdiff breaking --fail-on ERR
# Fitness Function: 循环依赖
- name: Check circular dependencies
run: npx madge --circular src/
docs-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # git-revision-date需要
# 构建文档站
- name: Build docs
run: |
pip install mkdocs-material mkdocs-git-revision-date-localized-plugin
mkdocs build --strict # strict模式:断链即失败
# Fitness Function: 文档鲜度
- name: Check doc freshness
run: |
python scripts/check_doc_freshness.py \
--max-age-days 90 \
--files docs/arc42/01-introduction.md \
docs/arc42/03-context.md \
docs/arc42/05-building-blocks.md
# 部署文档站
- name: Deploy docs
if: github.ref == 'refs/heads/main'
run: mkdocs gh-deploy --force
ADR: 架构文档工程化方案
# ADR-025: 采用arc42 + Docs-as-Code + Fitness Functions
## 状态
已接受
## 背景
1. 现有架构文档在Confluence上,和代码脱节严重
2. 架构约束只在评审时口头传达,缺乏自动化验证
3. 新人入职需要2周才能理解系统架构
## 决策
1. 架构文档迁移到Git仓库,使用Markdown格式
2. 采用arc42模板(裁剪为7个核心章节)
3. 用MkDocs + Material主题构建文档站
4. 定义6个Fitness Functions,纳入CI/CD
5. 每季度架构文档Review
## 投入估算
- 文档迁移:2人周
- Fitness Functions开发:1人周
- CI/CD配置:2人天
- 总投入:约3人周
## 预期收益
- 新人入职理解时间从2周降至3天
- 架构约束违反在PR阶段即发现(vs 代码评审遗漏)
- 合规审计时文档随时可提供
AI增强实践
AI辅助架构文档生成
Prompt: 基于以下信息,生成arc42格式的架构文档:
系统:支付网关
技术栈:Java 21 + Spring Boot 3 + PostgreSQL + Kafka + Redis
核心功能:多渠道支付、交易监控、清结算
质量要求:99.99%可用性,P99<500ms,PCI DSS合规
团队规模:15人
外部系统:银联、微信支付、支付宝、各合作银行
请生成以下arc42章节的完整内容:
1. Introduction & Goals(含质量属性树)
3. Context & Scope(含Context图的文字描述)
4. Solution Strategy(含关键技术决策)
11. Risks & Technical Debt(基于技术栈特征推断)
AI辅助Fitness Function设计
Prompt: 我有一个支付网关系统,使用Java Spring Boot。
请为我设计Fitness Functions,覆盖以下架构约束:
1. 分层架构约束(Controller→Service→Repository)
2. PCI DSS相关约束(敏感数据处理)
3. API设计约束(向后兼容、版本管理)
4. 性能约束(数据库查询不超过100ms)
5. 安全约束(SQL注入防护、XSS防护)
对每个Fitness Function,请提供:
- ArchUnit或dependency-cruiser的具体代码
- CI/CD集成配置
- 失败时的告警策略
AI自动检测文档-代码偏差
# 概念方案:用AI检测架构文档和代码的不一致
def detect_doc_code_drift():
"""
1. 读取arc42 Chapter 5(构建块视图)中描述的模块
2. 扫描代码目录结构获取实际模块
3. 用AI对比差异
"""
doc_modules = extract_modules_from_doc("docs/arc42/05-building-blocks.md")
code_modules = scan_code_modules("src/")
prompt = f"""
架构文档描述的模块:
{doc_modules}
实际代码中的模块:
{code_modules}
请对比差异:
1. 文档中有但代码中不存在的模块(可能是计划中未实现)
2. 代码中有但文档中未记录的模块(可能是文档过时)
3. 名称不匹配的可能对应模块
4. 建议更新哪些文档内容
"""
return call_llm(prompt)
与Web3/DeFi的关联
DeFi协议的文档挑战
DeFi项目有独特的文档需求:
| 文档类型 | 传统系统 | DeFi系统 |
|---|---|---|
| 架构文档 | 内部团队用 | 社区和开发者都需要 |
| API文档 | OpenAPI | Solidity NatSpec + SDK文档 |
| 安全文档 | 内部安全评估 | 公开审计报告 |
| 治理文档 | 内部流程 | 公开提案(Snapshot/Tally) |
| 经济模型 | 内部商业计划 | 公开Tokenomics文档 |
DeFi项目的"arc42"
# DeFi协议架构文档模板
## 1. Protocol Overview
- 一句话定义
- 核心价值主张
- 目标用户(交易者/LP/治理参与者)
## 2. Smart Contract Architecture
- 合约拓扑(Factory/Router/Pool/Governance)
- 合约间调用关系
- 升级机制(Proxy/Diamond/Immutable)
## 3. Risk Model
- 清算参数
- 预言机依赖
- 多签/Timelock设置
## 4. Audit History
- 审计公司 + 报告链接
- 已知问题和修复状态
- Bug Bounty计划
## 5. Deployment Addresses
- 每条链的合约地址
- 子图地址
- 前端部署地址
## 6. Integration Guide
- SDK使用方式
- 常见集成场景
- 错误处理
Fitness Functions在Web3中的应用
// Solidity层面的"Fitness Functions"
// 通过自动化测试验证架构约束
// FF: 关键函数必须有重入保护
// → 检查所有external payable函数是否使用nonReentrant修饰符
// FF: 权限控制一致性
// → 检查所有admin函数是否通过Timelock调用
// FF: 事件覆盖率
// → 检查所有状态变更函数是否emit了事件
// 实现方式:Slither自定义检测器 + CI集成
今日思考
思考题1:文档的"正确粒度"
多少文档是"够用"的?在你的经验中,过多和过少的文档各带来了什么问题?你如何判断一个项目的文档是否"恰到好处"?
思考题2:Fitness Functions的ROI
实现Fitness Functions需要投入,但它的价值是"防止架构腐化"——这个收益很难直接量化。你会如何向团队推销Fitness Functions?如果团队认为"Code Review就够了",你怎么反驳?
思考题3:Docs-as-Code的文化挑战
把文档从Confluence迁移到Git,对非技术角色(BA、PM、QA)可能造成障碍。你如何推动这种文化变革?有没有折中方案?
面试题准备
面试题1:架构文档如何保持最新?
30秒版本: 三层策略:1) Docs-as-Code——文档和代码存在同一个Git仓库,PR review时同步检查;2) 自动化生成——API文档、依赖图等从代码自动提取;3) 鲜度检查——CI定期检测文档最后更新时间,超过阈值自动告警。
2分钟版本: 架构文档过时是行业通病。我的实践分为三层防御:
第一层:降低更新摩擦(Docs-as-Code) 文档用Markdown写,存在代码仓库的docs/目录。PR模板包含"是否需要更新架构文档"的checkbox。代码和文档在同一个PR中修改,同时review、同时合并。这消除了"改完代码忘记更文档"的问题。
第二层:自动化生成(Living Documentation) 能自动生成的就不手写:
- API文档从代码注解生成(OpenAPI/Swagger)
- 依赖关系图从代码自动生成(dependency-cruiser)
- 数据库Schema从Entity类自动生成
- CHANGELOG从Conventional Commits自动生成
手写的只有:架构决策的"为什么"(ADR)、质量属性场景、风险评估——这些只有人能写。
第三层:自动化守护(Fitness Functions + 鲜度检查) CI管线每周检查核心文档的最后更新时间。如果超过90天未更新,自动创建Issue提醒架构师review。同时用ArchUnit等工具验证代码是否符合文档中描述的架构约束。
追问准备:
Q: 现实中开发者真的会在PR中更新文档吗? A: 需要三个条件:1) 文档就在代码旁边(同目录),不需要切换工具;2) PR模板有强制提醒;3) 文档不用"完美"——只要记录变更即可,每季度统一整理。
面试题2:什么是Architecture Fitness Functions?
30秒版本: Fitness Functions是用自动化测试验证架构约束的实践——和单元测试保护代码逻辑一样,Fitness Functions保护架构不腐化。比如用ArchUnit验证"Controller不能直接调用Repository",在CI中每次PR自动检查,违反就构建失败。
2分钟版本: 这个概念来自Neal Ford的《Building Evolutionary Architecture》。核心思想:架构约束不应该只存在于文档或口头约定中,而应该被编码为自动化测试。
为什么需要: 传统方式靠架构评审和代码Review来维护架构约束,但这有两个问题:1) 人会遗漏;2) 等发现时可能已经积累了大量违反。Fitness Functions把检查前置到每次PR,违反即失败。
常见Fitness Functions:
- 依赖方向:Controller→Service→Repository(不能反向或跳层)
- 循环依赖:模块间不允许循环引用
- API兼容性:已发布API的字段不能删除
- 安全约束:敏感数据必须加密后存储
- 命名规范:Service类必须以Service结尾
工具:Java用ArchUnit,TypeScript用dependency-cruiser,通用场景用自定义脚本。关键是纳入CI/CD,不是可选检查而是强制门槛。
在我的支付系统项目中,引入Fitness Functions后,架构违反在6个月内从"每月发现3-5个"降到"几乎为0"——因为违反在PR阶段就被拦住了。
学习资源
| 资源 | 类型 | 推荐度 |
|---|---|---|
| arc42.org | 官网+模板 | ★★★★★ 必读 |
| Building Evolutionary Architecture (Ford/Parsons) | 书 | ★★★★★ Fitness Functions |
| Living Documentation (Cyrille Martraire) | 书 | ★★★★ |
| Docs as Code | 文章 | ★★★★ |
| ArchUnit | 工具 | ★★★★★ 实操必备 |
| dependency-cruiser | 工具 | ★★★★ JS/TS项目 |
| MkDocs Material | 工具 | ★★★★ 文档站首选 |
明日预告
Day 26: 架构沟通术(高级) — 文档写好了,但不同受众需要不同的叙事。明天我们将学习"Architecture Elevator"概念(Gregor Hohpe)——如何在同一栋大楼里,坐电梯从C-Suite到开发团队,每一层都用对方听得懂的语言讲架构。为CTO讲战略对齐,为VP讲技术债,为开发讲接口契约,为监管讲合规架构。