12 KiB
项目开发实践指南(VIBECODING GUIDE)
本文档是基于"踩过的坑"沉淀下来的项目工作方式约定,适用于本仓库及后续所有同性质的项目。 它的姊妹文件是
SELF_CONSTRAINTS.md—— 那是 Agent 每次开工前必须自查的硬约束清单。 本文回答 "为什么这么做";SELF_CONSTRAINTS.md回答 "具体不许做什么"。
0. 三条核心教训(本指南的来由,优先级严格递减)
-
版本控制必须从第 0 天开始。 不是 "等做出点东西再说",是写第一行代码之前先初始化仓库、写好 ignore 规则、提交一个空骨架。 理由:高频改动 + 频繁推翻是 AI 协作的常态,没有版本控制兜底就等于在悬崖边裸奔。
-
文档必须在写代码之前定下来。 需求、架构、路线图、开发规范、目录结构、命名规范、模块边界 —— 这些不是"做完之后补的",是"做之前定的"。 理由:一旦上下文被代码细节占满,后续每个新会话都只能 freestyle,项目会朝不可逆的方向漂移。
-
架构 > UI > 用户体验。 最致命的不是界面丑、不是体验差,而是模块互相纠缠到无法定位问题。 一个出问题就能立刻指认 "是 X 模块的责任" 的项目,比一个好看但耦合一团的项目,存活率高一个数量级。 理由:耦合一旦发生,AI 协作模式会迅速放大它 —— 因为每次新会话都看不全全貌,只会在原有耦合上继续添乱。
这三条的优先级是严格递减的:先有版本控制,再有文档,再谈架构;架构稳了之后才轮到 UI 和体验。
1. 项目启动 Checklist(Day 0)
下列每一项都必须在写第一行业务代码之前完成。顺序即优先级。
1.1 仓库与版本控制
- 初始化版本控制并立即建立 ignore 规则(语言 / IDE / 系统三类至少齐全)
- 提交一个 空骨架 commit(README + ignore 规则 + 空目录结构),作为"零点参照系"
- 约定分支模型(最简:主干 + 短命的功能分支;不要等到分叉时才想)
- 约定 commit message 风格(推荐 Conventional Commits,至少要求动词开头 + 一句话原因)
1.2 文档骨架(必须先于代码存在)
在 .project.agents/docs/context 下建立以下文件,哪怕只有大纲也比没有强:
| 文件 | 角色 | 上下游关系 |
|---|---|---|
PRD.md |
产品需求(要做什么) | 上游 |
ARCHITECTURE.md |
架构(怎么拆) | 上游 |
ROADMAP.md |
路线图(什么时候做哪一块) | 由需求 + 架构推导 |
CONVENTIONS.md |
开发规范(命名、目录、提交、风格) | 上游 |
UIUX.md |
视觉与交互细节(仅有 UI 的项目需要) | 上游(与需求并列) |
| 派生文档(实现 spec / 资产清单等) | 屏幕级实现 / 资产清单 | 派生,由上游产生 |
判断标准:如果一个新会话的 Agent 只读需求 + 架构 + 开发规范就能正确开始一个任务 —— 文档就算合格。
1.3 Agent 协作配置
- 在
CLAUDE.md写明项目级规则(已有,保持更新) - 在本文件 +
SELF_CONSTRAINTS.md中固化经验 - 在
.project.agents/settings.json中配置必要的 hook / 权限(不要散落到根目录或全局)
2. 架构原则
2.1 三条硬规则
-
单一职责到模块级 每个模块只回答一个问题。 反例:"一个模块既管数据持久化,又管网络请求,又管 UI 状态" —— 这种模块必须拆。
-
依赖方向单向 高层依赖低层,UI 依赖业务,业务依赖数据;反向依赖一律禁止,遇到就用接口/事件/回调倒置。 依赖关系必须能画成一张有向无环图(DAG),且这张图要在
ARCHITECTURE.md里画出来。 -
跨模块只走"接口契约" 模块 A 想用模块 B 的能力,只能通过 B 暴露的接口/协议,不能 reach into B 的内部实现。 接口契约必须在
ARCHITECTURE.md中显式声明(哪怕只是函数签名清单)。
2.2 判断架构是否健康的三个问句
随时可以用这三个问句自检:
- 指认问题:现在出 bug 了,我能否在 30 秒内指出"这是哪个模块的责任"?
- 替换实现:如果要把模块 X 整体换掉(换数据库、换框架),改动是否能控制在 X 内部 + 一个接口适配层?
- 新增功能归属:用户要加一个新功能,我能否立刻说出它"属于哪个模块、或需要新增哪个模块"?
任何一个回答不出来,架构就有问题,先停下修架构,再写代码。
2.3 反耦合纪律
- 不在新功能开发时顺手重构无关模块(重构走单独 commit + 单独会话)
- 不在 UI 层做业务判断(UI 只接收状态、发送意图)
- 不让数据模型自己跑业务逻辑(模型类保持瘦,业务放 Service / UseCase)
- 不要"为了少写一个文件"把两个模块塞进同一个文件
3. 项目架构文档生成流程
这是从零到 ARCHITECTURE.md 的标准流程。每一步都有产出物,下一步必须基于上一步的产出物。
Step 1 — 需求收敛(产出 PRD.md)
- 列功能清单,按 核心 / 增强 / 可选 三档分类
- 每个核心功能写一句 "用户故事"("作为 X,我想 Y,以便 Z")
- 冻结 MVP 范围:圈出 MVP 包含哪些核心功能,其余明确标 "Out of MVP"
Step 2 — 领域建模(产出 ARCHITECTURE.md §1 领域模型)
- 列出所有名词实体(用户、订单、会话…)
- 标注每个实体的字段、关系、生命周期
- 标记哪些是持久化实体,哪些是瞬态状态
Step 3 — 模块划分(产出 ARCHITECTURE.md §2 模块清单)
对照领域模型与需求功能清单,拆分模块。每个模块写一张卡片:
## 模块名:<Name>
- 职责:一句话
- 不负责:明确写出"不做什么"(防止职责蔓延)
- 输入:从哪些模块/外部来
- 输出:暴露给谁
- 关键类型/接口:列签名(不写实现)
- 持有状态:有没有自己的状态?
经验:如果一个模块的"不负责"写不出来,说明它的职责还没想清楚,回到 Step 2。
Step 4 — 依赖图(产出 ARCHITECTURE.md §3 依赖图)
- 画出模块间依赖箭头(推荐 Mermaid,纯文本可 diff)
- 手动验证 DAG:从任一节点 DFS 不应回到自己
- 标出"接口边界":哪些依赖是接口注入,哪些是直接调用
Step 5 — 路线图(产出 ROADMAP.md)
按依赖图的拓扑顺序排开发节奏:
- 先做被依赖最多的底层模块
- 每个 milestone 必须能独立通过编译/构建并跑出某种"可见行为"
- 写明每个 milestone 完成的"验收标准"(不是"做完了",是"做完了之后能演示什么")
Step 6 — 开发规范(产出 CONVENTIONS.md)
- 命名(类型 / 文件 / 目录 / 资产)
- 代码风格(缩进 / 注释策略 / 错误处理边界)
- 提交规范
- 测试策略(哪些必须有测试,哪些不要求)
Step 7 — 派生文档(产出实现 spec / 资产清单等)
只有上面 6 步都齐了,才能开始写派生文档。
派生文档必须显式引用上游章节("对应 ARCHITECTURE.md §2.3 的 XxxService 模块"),方便后续 diff 校验。
4. 文档变更协议
文档不是写完就锁死的,但变更必须沿着上下游传播:
| 变更点 | 必须同步更新 |
|---|---|
| 需求加/删/改功能 | 架构模块清单、路线图、派生文档 |
| 架构调整模块边界 | 依赖图、开发规范(如有命名调整)、派生文档 |
| UI/UX 改视觉 token | 派生文档(实现 spec / 资产清单),不影响架构 |
| 加新模块 | 架构 §2 + §3、路线图、开发规范(如新目录) |
权威链:PRD.md > ARCHITECTURE.md > UIUX.md > CONVENTIONS.md > 派生文档。
派生文档永远不能反向修改上游。如果在派生文档中发现矛盾,回去改上游,再让派生文档重新对齐。
代码与架构漂移 > 24 小时即违规。
5. 实施日志(execution log)
写代码 / 执行路线图期间,每完成一个可独立验收的"部分",必须在 .project.agents/log 写一份日志。日志是给"下一个会话的我"看的 —— 让接手的会话能在不读所有代码的情况下知道:刚才完成了什么、哪些提交、下一步是什么。
5.1 何时写日志
- 完成一个路线图 milestone
- 完成一个 milestone 内独立可验收的子任务
- 完成一次非平凡的重构 / bug 修复
- 当前会话即将结束时(兜底,把上下文沉淀下来)
判断标准:如果这段工作下一个会话需要知道,就写。
5.2 日志文件命名
.project.agents/log/YYYY-MM-DD-<slug>.md
<slug>= 简短动词 + 范围,kebab-case- 同日多份日志按写作顺序累积(不覆盖、不合并),文件名加序号后缀:
-1、-2…
5.3 日志内容模板
# <一句话标题:完成了什么>
- **日期**:YYYY-MM-DD
- **关联**:路线图 M<N> / 子任务名 / 关联文档
- **会话上下文**:(可选)本会话从哪开始接手的
## 做了什么
- bullet 1
- bullet 2
## 提交
- `<short hash>` <commit subject>
(若本段未提交:明确写"未提交,工作树状态:…"并说明原因)
## 状态变更
- 架构文档:是否动过?动了哪一节?
- 需求/UI 文档:是否触发回归?
- 测试:跑了什么,结果
## 下一步
- 接下来要做的第一件事(具体到任务名)
- 已知阻塞 / 待澄清项
5.4 与提交的关系
日志不替代 commit message,commit message 仍按 CONVENTIONS.md 写;日志是提交的索引与解释。
5.5 不写日志的情况
- 还没完成一个"可独立验收"的部分 —— 不要"写日志凑数"
- 纯文档调整 —— commit 自身已足够说明
- 实验性探索(最终被回滚的内容)—— 用 commit message 记录即可
6. 出问题时的排查流程
bug 来了不要直接钻进代码。按下列顺序:
- 复现并定位现象:能在哪个入口 / 哪个调用稳定复现?
- 回到架构图:这个现象涉及哪些模块?沿着依赖图圈出可能责任方。
- 审查接口契约:跨模块调用是否符合
ARCHITECTURE.md中声明的接口?输入输出是否符合契约? - 缩小到单模块:把嫌疑缩小到一个模块后,再读该模块代码。
- 修复并回写经验:如果发现是架构层面的漏洞,修完代码后必须更新
ARCHITECTURE.md或CONVENTIONS.md。
反模式:bug 一来就 grep 关键字、改一行试一下、再改一行试一下 —— 这是死亡螺旋,必须用流程压下去。
7. 反模式清单("看到这些立刻警觉")
- 出现语义为空的模块名(
Manager/Helper/Util/Common/Misc/Tools)且行数 > 100 行 - 一个文件 import 超过 10 个本地模块
- 改一个 UI 改动需要动 3 个以上其他模块
- 同一份业务逻辑在两个地方各写了一遍
- PR 描述写"顺便修了 X"
- 新增功能时发现"无处归属",于是塞进入口文件或主组件
- 文档与代码不一致超过 24 小时
- 出现没有在
ARCHITECTURE.md中登记的新模块/新依赖方向
任何一条出现,先停下来回到本指南或架构文档,不要继续往前推。
8. 本项目当前阶段
本节随项目演进,不是规则的一部分。由 Agent 在每个 milestone 后更新。
- 当前状态:前端底座(
abacus-static-framework)已完成治理落地(Retrofit),src/framework/**只读、业务只写src/subsystem/**;前后端共享约束单源化于工作区docs/(../../../docs/coding-standards.md)。 - 下一步合规动作:新业务子系统按
docs/coding-standards.md §7(AI 生成工作流)开发;任何新增模块、目录或依赖方向先回写本仓库ARCHITECTURE.md,再写代码。