创建 ARCHITECTURE.md
基于 matklad 的 ARCHITECTURE.md 指南,为项目生成高层架构文档。
核心原则
- 只写不常变的内容:不要试图与代码同步,每年回顾两三次即可
- 保持简短:每个经常贡献的人都要读它,越短越不容易因代码变化而失效
- 回答两个问题:「做 X 的代码在哪?」和「我正在看的这段代码是做什么的?」
文档结构
按以下顺序组织 ARCHITECTURE.md:
1. 鸟瞰概览
用 1-3 段简要描述项目要解决的问题。不是使用说明,而是让读者理解「为什么存在这个项目」以及核心领域概念。
2. 代码地图(Codemap)
描述粗粒度模块及其相互关系。这是文档的核心部分。
规则:
- 命名重要的文件、模块、类型,让读者用符号搜索找到它们
- 不要直接链接代码(链接会过时),改为鼓励读者使用符号搜索
- 描述模块「做什么」,不要描述「怎么做」(实现细节放到内联文档或单独文档)
- 像国家地图,不是各省地图集
- 反思结构:代码地图中想放在一起的东西,在
tree .输出中是否相邻?
示例片段:
## Codemap
### `src/parsing/`
将源码文本转为具体语法树(CST)。解析器是手写递归下降,不使用生成器。
关键类型:`Parser`、`SyntaxNode`、`SyntaxToken`。
### `src/hir/`
高级中间表示。从 CST 降级得来,是大多数语义分析的基础。
关键类型:`Module`、`Function`、`TypeRef`。
### `src/server/`
LSP 服务器实现。将 IDE 功能暴露给编辑器。
入口:`main_loop`。
3. 架构不变量
显式列出架构约束,尤其是「不做某事」的约定——这些从代码中很难发现。
示例:
- "model 层不依赖 view 层"
- "所有数据库访问只通过 repository 层,handler 不直接操作数据库"
- "不使用全局可变状态"
4. 层与系统边界
指出层之间、系统之间的边界。边界隐含了其背后实现的信息,并约束所有可能的实现。但仅靠随机阅读代码很难发现边界——好的边界「测度为零」。
5. 横切关注点
在代码地图之后,单独列一节说明跨模块的共性事项:
- 错误处理策略
- 日志 / 可观测性
- 测试方式
- 配置管理
- 并发模型
工作流
- 阅读项目:浏览
tree .、README、go.mod/package.json等,理解项目结构 - 识别模块:找出粗粒度模块(目录级别),理解各自职责
- 梳理关系:确定模块间的依赖与调用方向
- 发现不变量:找出架构约束,特别是「不做某事」的规则
- 撰写文档:按上述结构生成 ARCHITECTURE.md
- 精简:删除一切可能频繁变动的细节
模板
# Architecture
本文档描述 [项目名] 的高层架构。
## 概览
[1-3 段:项目解决什么问题,核心领域概念]
## Codemap
### `dir/`
[该模块做什么,关键类型/入口]
### `dir2/`
[该模块做什么,关键类型/入口]
## 不变量
- [架构约束 1]
- [架构约束 2]
## 横切关注点
### 错误处理
[策略]
### 测试
[方式]
注意事项
- 放在仓库根目录,与 README 和 CONTRIBUTING 并列
- 不超过 1-2 页(屏幕页),越短越好
- 避免描述实现细节,那是代码注释的工作
- 不要加指向具体代码行的链接,用名称让读者自己搜索