7软件架构实践(第4版)

架构文档化

沟通与传承

视图4+1模型C4模型ADR架构决策记录

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第7章 架构文档化 (Documenting Software Architectures)

一、导读

1.1 本章学习目标

在本章结束时,你将能够:

  • 理解架构文档的价值,认识文档在沟通、传承和决策中的作用
  • 掌握视图类型,熟悉逻辑视图、进程视图、开发视图、物理视图等
  • 选择适当视图,根据受众和目的选择合适的文档内容
  • 应用文档模板,使用标准化的结构组织架构信息
  • 平衡详略程度,避免过度文档化和文档不足
  • 维护文档活力,确保文档与系统同步演进
  • 利用现代工具,使用代码即文档、自动生成等技术
  • 避免文档陷阱,识别常见的文档编写错误

1.2 为什么本章如此重要

架构文档是架构师与利益相关者沟通的桥梁。再好的架构设计,如果无法有效地传达给相关人员,其价值也会大打折扣。

在实际项目中,我们经常遇到这样的问题:

  • 新加入的开发者看不懂系统结构,需要很长时间才能上手
  • 运维人员不知道系统依赖哪些服务,故障排查困难
  • 业务方不理解技术决策的理由,对变更持怀疑态度
  • 几个月后回头看自己的设计,也记不清当时的考虑

这些问题的根源往往是架构文档的缺失或质量不佳。

架构文档的重要性体现在以下几个方面:

首先,文档是知识的载体。架构设计中包含了大量的决策和权衡,这些知识如果不记录下来,就会随着人员的流动而流失。文档确保了知识的可传承性。

其次,文档是沟通的工具。不同的利益相关者关注系统的不同方面:业务方关心功能和质量,开发人员关心接口和实现,运维人员关心部署和监控。好的文档能够为不同受众提供他们需要的信息。

第三,文档是决策的记录。架构决策背后的理由、考虑的替代方案、预期的影响,这些信息对于后续的维护和演进至关重要。没有记录的决策就像没有注释的代码,后人难以理解。

第四,文档是合规的要求。在某些行业(如金融、医疗、航空),架构文档是审计和认证的必需材料。

最后,文档本身也是一种思考工具。在编写文档的过程中,架构师被迫清晰地表达自己的想法,这往往能发现设计中的漏洞和不一致之处。

然而,文档也是一把双刃剑。过度文档化会浪费资源,文档过时会产生误导,文档不足会导致混乱。本章将教你如何在这些极端之间找到平衡点。

1.3 核心问题引导

在阅读本章时,请思考以下问题:

架构文档的目标读者是谁?不同读者需要什么类型的信息?

为什么单一视图无法完整描述复杂系统?需要哪些视图来互补?

什么是"刚好足够"的文档?如何判断文档是否过多或过少?

架构文档应该包含哪些核心内容?有没有标准的模板?

如何确保文档与代码保持同步?文档过时的原因是什么?

代码即文档(Code as Documentation)的理念可行吗?有什么局限?

敏捷开发中文档的角色是什么?敏捷是否意味着不要文档?

现代工具(如 Swagger、PlantUML、ADR)如何改善架构文档?


二、核心概念详解

7.1 架构文档的本质

严格定义:

架构文档是对软件架构的系统化描述,它通过多种视图展现系统的结构、行为、约束和决策,服务于不同的利益相关者。

通俗地说,架构文档就像是建筑物的蓝图。建筑师不会只画一张图,而是会有平面图、立面图、结构图、水电图等,每种图服务于不同的目的和读者。架构文档也是如此。

文档 vs 代码

一个常见的问题是:"代码不是最好的文档吗?"

代码确实传达了实现的细节,但它无法回答以下问题:

  • 为什么选择这种架构?
  • 系统的高层结构是什么?
  • 各个模块之间的依赖关系如何?
  • 系统如何应对性能、可用性、安全性等非功能性需求?
  • 未来的演进方向是什么?

代码回答的是"怎么做",架构文档回答的是"是什么"和"为什么"。两者互补,不可互相替代。

文档的原则

好的架构文档应遵循以下原则:

面向受众:为特定读者编写,使用他们能理解的语言

多视图:从不同角度描述系统

适度详细:提供足够的信息,但不过度

保持更新:文档应与系统同步演进

易于访问:文档应在容易找到的地方,格式便于阅读

7.2 视图类型

Philippe Kruchten 提出的 "4+1" 视图模型是最经典的架构文档框架。

7.2.1 逻辑视图(Logical View)

目标受众:最终用户、业务分析师、领域专家

关注点:系统提供的功能和服务

内容:

  • 核心领域对象和它们的关系
  • 用例和功能分解
  • 类图和包图

表示方法:

  • UML 类图
  • 领域模型图
  • 用例图

示例:

┌─────────────┐     ┌─────────────┐
│   Customer   │────▶│   Order     │
└─────────────┘     └─────────────┘
                         │
                         ▼
                  ┌─────────────┐
                  │ OrderItem   │
                  └─────────────┘
                         │
                         ▼
                  ┌─────────────┐
                  │   Product   │
                  └─────────────┘

关键问题:

  • 系统有哪些核心实体?
  • 实体之间的关系是什么?
  • 系统提供哪些业务功能?

7.2.2 进程视图(Process View)

目标受众:系统集成人员、性能工程师、运维人员

关注点:系统的运行时行为

内容:

  • 线程和进程结构
  • 并发和同步机制
  • 通信和数据流
  • 性能特征

表示方法:

  • 序列图
  • 活动图
  • 状态图
  • 数据流图

示例:

User → Controller → Service → Repository → Database
                     │
                     ▼
                  Cache (Redis)

关键问题:

  • 系统如何处理并发请求?
  • 组件之间如何通信?
  • 性能瓶颈在哪里?
  • 如何保证线程安全?

7.2.3 开发视图(Development View)

目标受众:开发人员、测试人员

关注点:软件的静态组织结构

内容:

  • 模块和包的划分
  • 依赖关系
  • 构建和配置
  • 代码规范

表示方法:

  • 组件图
  • 包依赖图
  • 目录结构

示例:

src/
├── main/
│   ├── java/
│   │   ├── controller/
│   │   ├── service/
│   │   ├── repository/
│   │   └── domain/
│   └── resources/
└── test/
    └── java/

关键问题:

  • 代码如何组织?
  • 模块之间如何依赖?
  • 如何构建和测试?
  • 新人如何快速上手?

7.2.4 物理视图(Physical View)

目标受众:系统管理员、运维人员、DevOps 工程师

关注点:系统的部署结构

内容:

  • 服务器和网络拓扑
  • 部署单元
  • 资源配置
  • 高可用和灾备方案

表示方法:

  • 部署图
  • 网络拓扑图
  • 基础设施图

示例:

┌──────────────┐
                    │  Load Balancer│
                    └──────┬───────┘
                           │
              ┌────────────┼────────────┐
              ▼            ▼            ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │ Server 1 │ │ Server 2 │ │ Server 3 │
        └────┬─────┘ └────┬─────┘ └────┬─────┘
             │            │            │
             └────────────┼────────────┘
                          ▼
                  ┌──────────────┐
                  │   Database   │
                  │  (Primary +  │
                  │   Replica)   │
                  └──────────────┘

关键问题:

  • 系统部署在哪些服务器上?
  • 网络带宽和延迟要求是什么?
  • 如何实现高可用?
  • 扩容策略是什么?

7.2.5 场景视图(Scenarios / Use Cases)

目标受众:所有利益相关者

关注点:系统在典型用例下的行为

内容:

  • 关键用例的执行流程
  • 异常处理
  • 端到端的行为轨迹

表示方法:

  • 用例图
  • 序列图
  • 用户故事

作用:场景视图不是独立的视图,而是将其他四个视图串联起来,展示它们在具体情境下的协作。

7.3 文档模板

7.3.1 arc42 模板

arc42 是一个广泛使用的架构文档模板,包含 12 个章节:

引言和目标:文档的目的、读者、范围

架构约束:技术、组织、法规约束

上下文和范围:系统与外部的边界

解决方案策略:高层架构决策

构建块视图:系统的静态结构

运行时视图:系统的动态行为

部署视图:系统的部署结构

横切概念:日志、安全、配置等跨领域关注点

架构决策:重要的设计决策及其理由

质量需求:质量属性场景

风险和债务:已知风险和技术债务

术语表:专业术语解释

7.3.2 C4 模型

C4 模型由 Simon Brown 提出,包含四个层次:

Context(上下文):系统与外部世界的关系

Container(容器):应用程序的整体结构

Component(组件):容器内部的组件划分

Code(代码):组件内部的类和方法(可选)

C4 模型的优势是简单直观,适合不同层次的受众。

7.3.3 自定义模板

根据项目特点,可以定制文档模板。核心要素包括:

  • 系统概述
  • 架构视图
  • 关键决策
  • 质量属性
  • 部署说明
  • 运维指南

7.4 文档的详略程度

"刚好足够"的文档

文档的目标是用最小的成本传递必要的信息。判断文档是否"刚好足够"的标准:

  • 完整性:是否包含了读者需要了解的所有关键信息?
  • 简洁性:是否避免了不必要的细节?
  • 可读性:是否易于理解和查找?

过度文档化的迹象

  • 文档比代码还多
  • 包含大量过时的信息
  • 没有人阅读或更新
  • 编写文档的时间超过实现时间

文档不足的迹象

  • 新人需要很长时间才能上手
  • 同样的问题被反复询问
  • 关键决策只有少数人知道
  • 离职人员带走大量知识

平衡策略

分层文档:为不同受众提供不同深度的文档

渐进式细化:先写概要,再根据需要补充细节

自动化生成:从代码和配置中自动生成部分文档

定期审查:定期检查文档的有效性和准确性

7.5 文档的维护

文档过时的原因

  • 系统演进快,文档更新慢
  • 文档分散在多处,难以同步
  • 没有明确的文档责任人
  • 文档编写与维护脱节

保持文档活力的策略

就近原则:文档应尽量靠近它所描述的内容

- API 文档靠近代码

- 部署文档靠近配置文件

自动化:尽可能从源代码和配置中生成文档

- Javadoc/Swagger 从代码注释生成

- Terraform 文档从基础设施代码生成

版本控制:文档应与代码一起进行版本管理

- 使用 Git 管理文档

- 文档变更与代码变更关联

责任明确:指定文档的所有者和审查者

- 每个模块有对应的文档负责人

- 代码审查时同时审查文档

轻量更新:降低文档更新的门槛

- 使用 Markdown 等轻量格式

- 提供文档模板

7.6 现代文档工具

图表工具

  • PlantUML:用文本描述 UML 图
  • Mermaid:Markdown 中的图表语法
  • Draw.io:在线绘图工具
  • Structurizr:基于 C4 模型的建模工具

API 文档

  • Swagger/OpenAPI:REST API 文档标准
  • GraphQL Playground:GraphQL API 文档
  • Postman:API 测试和文档

架构决策记录

  • ADR Tools:管理架构决策记录
  • Log4brains:自动化的 ADR 知识库

文档平台

  • GitBook:在线文档平台
  • Confluence:企业wiki
  • Docusaurus:基于 React 的文档站点
  • MkDocs:Python 驱动的静态文档生成器

三、程序员的视角

3.1 在架构设计中的应用

场景一:新项目启动

新项目开始时,建立文档基础:

文档清单:
1. README.md:项目概述、快速开始
2. ARCHITECTURE.md:架构概览、核心决策
3. API 文档:接口定义(Swagger)
4. 部署指南:如何部署到各环境
5. 开发指南:编码规范、分支策略

工具设置:
- 配置 Swagger 自动生成 API 文档
- 设置 MkDocs 构建文档站点
- 初始化 ADR 目录

场景二:架构评审

评审前准备文档:

评审文档包:
1. 架构概览图(C4 Context + Container)
2. 关键组件的详细设计
3. 架构决策记录(ADRs)
4. 质量属性场景和应对策略
5. 风险评估报告

评审重点:
- 文档是否清晰表达了设计意图?
- 是否有遗漏的关键信息?
- 决策理由是否充分?

场景三:知识传承

团队成员变动时,依靠文档传递知识:

交接文档:
1. 系统架构图和说明
2. 关键模块的设计文档
3. 已知问题和 workaround
4. 联系人和职责矩阵
5. 常见问题 FAQ

方式:
- 文档 + 面对面讲解
- 录制演示视频
- 安排结对编程

3.2 常见陷阱与误区

陷阱一:文档与代码脱节

表现:文档是很久以前写的,与当前代码不一致。

后果:

  • 文档失去可信度
  • 读者被误导
  • 维护成本增加

避免方法:

  • 文档靠近代码(同仓库)
  • 自动化生成可能的部分
  • 代码变更时同步更新文档

陷阱二:过度追求完美

表现:花费大量时间美化文档,而不是传递信息。

后果:

  • 文档发布延迟
  • 资源浪费
  • 实际价值有限

避免方法:

  • 先发布再完善
  • 聚焦内容而非形式
  • 接受不完美的文档

陷阱三:单一文档试图满足所有人

表现:一份超长的文档试图涵盖所有受众的需求。

后果:

  • 文档难以阅读
  • 读者找不到需要的信息
  • 维护困难

避免方法:

  • 分层文档,针对不同受众
  • 提供导航和索引
  • 链接而非复制

陷阱四:忽视文档的可发现性

表现:文档存在但没人知道在哪里。

后果:

  • 重复劳动
  • 知识未被复用
  • 新人困惑

避免方法:

  • 统一的文档入口
  • 清晰的目录结构
  • 搜索引擎友好

3.3 与其他层级的联系

与代码的联系

文档应与代码紧密关联:

  • API 文档从代码注释生成
  • 架构图从代码依赖分析生成
  • 变更日志从 Git 提交生成

与流程的联系

文档应融入开发流程:

  • 代码审查包括文档审查
  • 发布检查清单包括文档更新
  • 定义完成的条件包括文档完成

与工具的联系

工具可以降低文档成本:

  • IDE 插件辅助编写文档
  • CI/CD 自动构建和发布文档
  • 搜索工具帮助查找文档

四、代码实战

4.1 示例一:使用 PlantUML 生成架构图

下面我们用 PlantUML 展示如何用文本描述架构图。

plantuml
@startuml C4_Context

title 电商系统上下文图

Person(customer, "顾客", "浏览商品、下单购物")
Person(admin, "管理员", "管理商品和订单")

System_Boundary(ecommerce, "电商系统") {
    System(web_app, "Web 应用", "用户界面")
    System(api, "API 服务", "业务逻辑")
    SystemDb(database, "数据库", "数据存储")
    SystemQueue(queue, "消息队列", "异步处理")
}

System_Ext(payment, "支付网关", "第三方支付")
System_Ext(email, "邮件服务", "发送通知")

Rel(customer, web_app, "访问")
Rel(admin, web_app, "管理")
Rel(web_app, api, "调用")
Rel(api, database, "读写")
Rel(api, queue, "发送消息")
Rel(api, payment, "处理支付")
Rel(api, email, "发送邮件")

@enduml

@startuml C4_Container

title API 服务容器图

Person(customer, "顾客")

System_Boundary(api, "API 服务") {
    Container(controller, "Controller", "Java/Spring", "处理 HTTP 请求")
    Container(service, "Service", "Java/Spring", "业务逻辑")
    Container(repository, "Repository", "Java/Spring Data", "数据访问")
    
    SystemDb(cache, "Redis", "缓存")
    SystemDb(db, "PostgreSQL", "主数据库")
}

Rel(customer, controller, "HTTP")
Rel(controller, service, "调用")
Rel(service, repository, "调用")
Rel(repository, db, "SQL")
Rel(service, cache, "读写")

@enduml

@startuml sequence

title 订单创建序列图

participant User
participant Controller
participant Service
participant Repository
participant Database
participant Queue

User -> Controller: POST /orders
Controller -> Service: createOrder(request)
Service -> Repository: save(order)
Repository -> Database: INSERT
Database --> Repository: result
Repository --> Service: order
Service -> Queue: publish(OrderCreatedEvent)
Service --> Controller: response
Controller --> User: 201 Created

note right of Queue: 异步处理库存和支付

@enduml

4.2 示例二:架构决策记录(ADR)模板

下面我们用 Markdown 展示 ADR 的标准模板。

markdown
# ADR-001: 采用 PostgreSQL 作为主数据库

## 状态

已接受

## 日期

2024-01-15

## 背景

系统需要存储结构化数据,包括用户、订单、商品等信息。
我们需要选择一个可靠、成熟且支持事务的数据库系统。

考虑因素:
- 需要 ACID 事务保证
- 数据结构相对固定
- 团队熟悉 SQL
- 预期数据量在 TB 级别
- 需要支持复杂的查询和报表

## 决策

选择 PostgreSQL 15 作为主数据库。

理由:
1. 完整的 ACID 事务支持
2. 成熟的 JSONB 类型,兼顾灵活性
3. 强大的查询优化器
4. 活跃的社区和丰富的生态
5. 良好的性能和可扩展性
6. 开源免费,无供应商锁定

## 后果

### 正面
- 简化了数据一致性管理
- 团队学习成本低
- 可以利用成熟的 ORM 框架
- 备份和恢复方案成熟

### 负面
- 水平扩展能力有限,未来可能需要分库分表
- 相比 NoSQL,写入性能略低
- 需要专门的 DBA 知识进行调优

## 替代方案

### MongoDB
- 优势:更好的水平扩展,灵活的 schema
- 劣势:一致性保证较弱,事务支持有限
- 未选择原因:我们的数据一致性要求高于扩展性要求

### MySQL
- 优势:同样成熟,广泛使用
- 劣势:JSON 支持和复杂查询能力不如 PostgreSQL
- 未选择原因:PostgreSQL 在功能上更胜一筹

## 参考链接

- [PostgreSQL 官方文档](https://www.postgresql.org/docs/)
- [PostgreSQL vs MySQL 对比](https://example.com/comparison)

4.3 示例三:使用 Swagger 生成 API 文档

下面我们用 Java 注解展示如何从代码生成 API 文档。

java
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/orders")
@Tag(name = "订单管理", description = "订单创建、查询和管理接口")
public class OrderController {
    
    private final OrderService orderService;
    
    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }
    
    @PostMapping
    @Operation(
        summary = "创建订单",
        description = "根据购物车内容创建新订单"
    )
    @ApiResponse(responseCode = "201", description = "订单创建成功")
    @ApiResponse(responseCode = "400", description = "请求参数无效")
    public ResponseEntity<OrderResponse> createOrder(
            @RequestBody @Parameter(description = "订单创建请求") CreateOrderRequest request) {
        OrderResponse response = orderService.createOrder(request);
        return ResponseEntity.status(201).body(response);
    }
    
    @GetMapping("/{orderId}")
    @Operation(
        summary = "查询订单",
        description = "根据订单 ID 获取订单详情"
    )
    @ApiResponse(responseCode = "200", description = "查询成功")
    @ApiResponse(responseCode = "404", description = "订单不存在")
    public ResponseEntity<OrderResponse> getOrder(
            @PathVariable @Parameter(description = "订单 ID") String orderId) {
        OrderResponse response = orderService.getOrder(orderId);
        return ResponseEntity.ok(response);
    }
    
    @PostMapping("/{orderId}/cancel")
    @Operation(
        summary = "取消订单",
        description = "取消尚未发货的订单"
    )
    @ApiResponse(responseCode = "200", description = "取消成功")
    @ApiResponse(responseCode = "400", description = "订单状态不允许取消")
    public ResponseEntity<Void> cancelOrder(
            @PathVariable @Parameter(description = "订单 ID") String orderId) {
        orderService.cancelOrder(orderId);
        return ResponseEntity.noContent().build();
    }
}

// 请求/响应 DTO
@Data
@Schema(description = "订单创建请求")
class CreateOrderRequest {
    @Schema(description = "用户 ID", example = "USER-123")
    private String userId;
    
    @Schema(description = "商品列表")
    private List<OrderItemRequest> items;
}

@Data
@Schema(description = "订单响应")
class OrderResponse {
    @Schema(description = "订单 ID", example = "ORD-001")
    private String orderId;
    
    @Schema(description = "订单状态")
    private String status;
    
    @Schema(description = "总金额")
    private BigDecimal totalAmount;
}

通过这些注解,Swagger 可以自动生成交互式的 API 文档。


五、深入思考

5.1 历史背景

架构文档的发展反映了软件工程方法的演变。

早期阶段(1960s-1980s)

  • 1960s-1970s:文档主要是纸质手册,形式单一
  • 1980s:结构化文档标准出现,如 IEEE 1016

标准化阶段(1990s)

  • 1990 年:IEEE 1471 标准提出架构描述框架
  • 1995 年:UML 诞生,提供了标准化的建模语言
  • 1998 年:"4+1" 视图模型被广泛接受

敏捷时代(2000s)

  • 2001 年:敏捷宣言强调"工作的软件胜过详尽的文档"
  • 2000s:轻量级文档方法兴起,如 wiki、博客
  • 2005 年:Swagger 等项目推动 API 文档自动化

现代发展(2010s 至今)

  • 2010s:Docs as Code 理念普及
  • 2014 年:C4 模型提出,简化架构建模
  • 2015 年:ADR 方法被广泛采用
  • 2020s:AI 辅助文档生成,自动化程度提高

关键人物

  • Philippe Kruchten:"4+1" 视图模型的提出者
  • Simon Brown:C4 模型的创造者
  • Michael Nygard:ADR 方法的推广者
  • Dan North:敏捷文档实践的倡导者

5.2 未解决的问题

文档自动化的边界

目前,部分文档可以从代码中自动生成(如 API 文档)。但架构决策、设计理由等高阶信息仍然需要人工编写。AI 能否辅助甚至自动生成这部分文档?

文档与代码的一致性保证

即使有工具和流程,文档与代码的不一致仍然是常见问题。能否开发出实时检测不一致的工具?

文档的价值量化

如何衡量文档的投资回报?什么样的文档投入是合理的?

全球化团队的文档

分布式团队如何维护统一、准确的文档?多语言文档如何保持同步?

文档的知识图谱

能否将分散的文档整合为知识图谱,实现智能检索和关联推荐?

5.3 延伸阅读

《Documenting Software Architectures》 - Paul Clements et al.

架构文档的权威指南,详细介绍了视图和文档方法。

《Software Architecture for Developers》 - Simon Brown

介绍 C4 模型和实用的架构文档技巧。

"Just Enough Documention"(文章) - Various authors

探讨敏捷环境中文档的平衡点。

《Writing Effective Use Cases》 - Alistair Cockburn

用例编写的经典著作。

arc42 官方网站 - https://arc42.com/

提供免费的架构文档模板和资源。


六、实验笔记

实验一:为一个系统编写架构文档

目标:练习使用 "4+1" 视图模型编写架构文档。

步骤:

选择一个你熟悉的系统(开源项目或公司内部系统)

收集系统的相关信息

编写以下视图:

a. 逻辑视图:核心领域模型

b. 进程视图:关键流程的序列图

c. 开发视图:模块结构和依赖

d. 物理视图:部署拓扑

e. 场景视图:2-3 个关键用例

编写架构概述和决策记录

请他人审阅文档,收集反馈

根据反馈修改文档

预期结果:

  • 完整的架构文档(至少 10 页)
  • 5 种视图的图表
  • 至少 3 条 ADR
  • 审阅反馈和修改记录

思考题:

哪个视图最难编写?为什么?

审阅者提出了哪些你没有想到的问题?

文档编写过程中,你发现了系统的哪些问题?

实验二:建立文档自动化流水线

目标:实践 Docs as Code 的理念。

步骤:

选择一个项目,建立文档基础设施

配置以下自动化:

a. 从代码注释生成 API 文档(Swagger/Javadoc)

b. 从 PlantUML/Mermaid 源文件生成架构图

c. 使用 MkDocs/Docusaurus 构建文档站点

d. 配置 CI/CD 自动构建和发布文档

编写文档贡献指南

演示文档的更新流程

预期结果:

  • 自动化文档构建流水线
  • 在线文档站点
  • 文档贡献指南
  • 演示视频或截图

思考题:

自动化带来了哪些好处?还有什么不能自动化的?

如何鼓励团队成员维护文档?

文档的质量如何保证?


七、本章小结

架构文档是架构师与利益相关者沟通的关键工具,它通过多种视图展现系统的不同方面。

核心要点:

视图模型:

- 逻辑视图:功能和领域模型

- 进程视图:运行时行为

- 开发视图:代码组织

- 物理视图:部署结构

- 场景视图:用例串联

文档原则:

- 面向受众:为特定读者编写

- 多视图:从不同角度描述

- 适度详细:刚好足够

- 保持更新:与系统同步

- 易于访问:方便查找

文档模板:

- arc42:全面的 12 章模板

- C4 模型:四层简化模型

- ADR:架构决策记录

现代工具:

- PlantUML/Mermaid:文本绘图

- Swagger/OpenAPI:API 文档

- MkDocs/Docusaurus:文档站点

- Git:版本控制

常见陷阱:

- 文档与代码脱节

- 过度追求完美

- 单一文档试图满足所有人

- 忽视文档的可发现性

文档的最佳实践:

  • 文档靠近代码
  • 自动化生成可能的部分
  • 文档纳入开发流程
  • 定期审查和更新
  • 提供清晰的导航

八、习题

基础题

解释 "4+1" 视图模型中每个视图的目标受众和关注点。

什么是 C4 模型?它的四个层次分别是什么?

架构决策记录(ADR)应包含哪些要素?

列举三种可以从代码自动生成的文档类型。

什么是"刚好足够"的文档?如何判断文档是否过多或过少?

进阶题

为一个微服务系统设计文档结构:

a) 列出需要的文档类型

b) 说明每种文档的目标读者

c) 描述文档之间的关系

d) 指出哪些部分可以自动化

比较以下文档方法的优缺点:

a) Wiki vs 静态文档站点

b) UML 图 vs PlantUML

c) 手动 API 文档 vs Swagger

设计一个文档维护流程,包括:

a) 文档的责任分配

b) 文档更新的触发条件

c) 文档质量的检查机制

d) 过期文档的处理策略

挑战题

研究文档即代码(Docs as Code)的实践:

a) Docs as Code 的核心理念是什么?

b) 实施 Docs as Code 需要哪些工具和实践?

c) 与传统文档方法相比有什么优势和劣势?

d) 在一个实际项目中实施 Docs as Code,报告经验和教训

探索 AI 在架构文档中的应用:

a) AI 可以辅助哪些文档工作?

b) 现有的 AI 文档工具有哪些?

c) AI 生成文档的准确性和可靠性如何保证?

d) 设计一个 AI 辅助的架构文档系统原型

7/10架构文档
0%