先写规格再写代码:OpenSpec让团队告别乱改与返工
接到一个改代码的需求你的第一反应是什么大部分人下意识打开IDE找到相关文件开始读代码、改代码。但我观察到的那些配合成熟的团队第一动作恰恰相反——他们先按下一个暂停键打开一个文档把代码改动之前要说清楚的东西先写下来。这套动作在圈子里被概括成一个词OpenSpec。说得直白一点OpenSpec不是某个高深框架也不是必须引入的第三方依赖它更像是一套开发纪律任何一个代码改动不管大小先产出规格说明再动手写实现。这个“先写说明、后写代码”的顺序就是优秀团队和普通团队之间一道很微妙的分水岭。代码是最贵的一环也是最不该第一环出现的环节。这篇文章我想把我在实际项目中践行OpenSpec的经验、碰过的壁、总结出来的流程模板完整分享出来给那些正在为“乱改代码、反复返工、评审扯皮”头疼的团队一个可以直接抄作业的参考。1. 为什么先写规格而不是直接改代码1.1 代码回答不了“为什么”很多人觉得代码本身就是最好的文档读源码就懂了。这句话对单人项目、短生命周期脚本勉强成立但对一个多人维护、存在了三五年的老系统来说基本是句空话。举个我遇到过的例子。有次排查一个线上订单状态异常的问题代码里有这么一段逻辑看起来是某个历史需求临时加的判断注释写着“fix bug”。但这个bug到底是什么bug为什么要在这一层处理影响范围多大代码本身完全不会告诉你。最后翻了Git提交记录翻到半年前的某个commit才从提交信息里拼出一点线索。要知道那个commit的提交信息写的还是“update order status”根本看不出真实意图。代码只能回答“现状是什么”它很难回答“为什么现状是这样”、“当初为什么选这个方案”、“这个分支还有没有存在的必要”。这些信息一旦缺失后人改代码就只能靠猜。猜对了运气好猜错了就是线上事故的伏笔。所以优秀团队在改代码之前写规格本质上是在补一份“决策上下文”——把代码里看不出来的那部分信息用文档形式固化下来。1.2 改代码是贵的改文档是便宜的经济学里有个概念叫转换成本。改一份规格文档几分钟、几十分钟的事但改代码、提PR、走评审、合入主干、触发构建、回归测试整个链条跑下来成本是文档的上百倍。更可怕的是改错方向——代码写完了才发现跟需求对不上前面所有工作量全部作废还得背上技术债。把这两者做个对比就非常直观改动位置成本量级出错后果规格文档低分钟级别改一版就好没什么代价接口设计中小时级别涉及调用方改造成本代码实现高天级别推翻重写浪费严重已发布版本极高周级别线上回滚、数据修复、用户投诉所以我一直给团队强调一个观念把问题消灭在规格阶段是性价比最高的质量手段。早期发现的逻辑漏洞改的只是一个句子晚期发现的逻辑漏洞改的是一整片代码。1.3 先对齐“做什么”再讨论“怎么做”团队协作中最大的浪费不是某个人写代码写慢了而是两个人做出了完全不一样的东西还都以为自己做的是对的那个。这就是典型的语义错位——需求方说“加个导出”心里想的是导出全部字段开发者理解成“加个导出”做出来只导出了核心几个字段测试拿着单子一验发现跟预期对不上来回扯几轮。OpenSpec的方式是把这个对齐动作前置。所有人都先围绕一份规格说明达成共识要改什么不改什么边界在哪里验收标准是什么。这些在文档阶段谈清楚成本极低。一旦进入编码环节任何人都不许带着自己的“理解”自由发挥。这不是压制创造力而是确保创造力用在正确的方向上。1.4 规格是评审的“公共语境”代码评审为什么容易流于形式最大的原因是评审者不了解背景。评审者看到一堆diff不知道前因后果就只能看看命名、看看格式提一些不痛不痒的建议。真正有价值的评审——业务逻辑是否正确、边界条件是否覆盖、设计方案是否最优——反而没人提因为大家没有公共的讨论基础。有了规格说明评审的语境就完全不同了。评审者先读规格再对照代码自然能看出“实现是否忠实地覆盖了规格里的每一条行为约定”。我个人的经验规格先行之后评审意见的质量明显上了一个档次不再是一堆“建议重命名变量”而是真正在讨论逻辑问题。2. 一份合格的规格说明到底写什么2.1 不是设计文档是行为契约很多团队不是没写过文档而是把规格说明写成了设计文档一上来就大谈技术架构、类图、数据库表结构。方向偏了。OpenSpec瞄准的是一份“行为契约”它回答的问题是这个改动之后系统对外表现的行为会发生什么变化。技术实现细节当然可以写但应该放在行为约定之后作为辅助说明。读者先理解了“要达成什么行为”再看“用什么技术手段实现”这才顺畅。一上来就讲底层设计读者脑子里没有“为什么需要这个设计”的锚点读起来非常累。我用的模板保持着相对固定的结构写多了以后基本是肌肉记忆# 变更标题 变更类型: 功能新增 / 缺陷修复 / 性能优化 / 重构 影响范围: 涉及模块、服务、接口 作者: 日期: ## 背景与动机 为什么需要这个改动解决什么用户问题当前方案的痛点在哪 ## 范围目标 做什么不做什么边界在哪目标行为是什么 ## 行为变化 改动前后系统行为有什么不同用户可感知的差异是什么 ## 接口与数据 涉及哪些接口参数怎么变数据结构有没有调整存储逻辑变不变 ## 兼容性与风险 会不会破坏现有功能有没有历史数据需要处理有没有依赖方受影响 ## 测试计划 怎么验证这个改动核心用例是什么边界情况怎么覆盖这个模板不需要多么花哨但每个字段都有它的用途。评审的时候大家就是逐条对着这个结构过效率非常高。2.2 一个好例子订单导出功能光说模板太抽象我用一个常见场景举个例子给订单管理后台增加一个批量导出功能。背景与动机运营同学每天都需要导当天的订单明细做对账现在只能手动一页页复制既慢又容易漏。希望提供一个批量导出按查询条件筛出结果一键导出Excel。范围目标支持按时间范围、订单状态筛选后导出导出字段与列表展示字段保持一致只支持Excel格式暂不做CSV避免范围膨胀不做定时导出、不做导出历史管理明确不做防止被加料行为变化后台订单列表页新增“导出”按钮点击后按当前筛选条件生成文件并在右下角弹出下载任务。单次导出上限5000条超过时提示缩小筛选范围。接口与数据新增后端接口/api/orders/export支持start_time、end_time、status参数导出任务异步执行完成后生成临时文件供下载临时文件保留24小时后自动清理。兼容性与风险查询逻辑可复用现有列表查询逻辑但需注意新增的临时文件存储目录权限配置导出大批量数据时需要关注内存占用流程上先走文件流写入避免整表加载到内存。测试计划验证按时间筛选导出、按状态筛选导出、空结果导出、超过5000条提示、导出中重复点击按钮、导出后文件的字段完整性。看到这个规格一个完全不了解订单模块的开发者也能很清楚地知道要做什么、做到什么程度、有哪些坑要避开。规格文件替代了大量口口相传的信息损耗。2.3 写规格时最容易犯的三个错误第一个错误是只写“做什么”不写“为什么”。这样的规格其实没什么生命力过一段时间作者自己都忘了当初为什么这么设计。第二个错误是过度细节化。每条规格写得像需求说明书事无巨细把每个按钮的文案、每个交互细节都固化下来。这会带来两个问题一是写起来负担极重坚持不下去二是读起来负担极重评审者很难抓重点。规格的颗粒度应该保持在“行为契约”层面而非“UI验收清单”层面。第三个错误也是最隐蔽的是不敢写“不做什么”。很多人觉得多做点总比少做好于是把一些模棱两可的需求也塞进来。结果就是工作量不断膨胀工期失控。明确写下“不做什么”是对整个团队负责。3. 从规格到代码一次完整的闭环实操3.1 第一步写下动机期间不要碰方案OpenSpec流程的第一步很多人会忍不住直接跳到设计。我会强制自己先只回答一个问题为什么要做这次改动背景、痛点、诉求原原本本写下来。这个阶段禁止写具体技术方案甚至不建议想技术方案。原因是方案思考会反过来扭曲对问题的理解。人一旦心里有了一个方案就会下意识把问题往这个方案上靠容易忽略其他可能性。先老老实实把问题定义清楚后面再谈解决方案。实际操作中这个阶段的产出通常只要几百字写清楚“现状哪里不对”“期望变成什么样子”就可以了。3.2 第二步拉人对齐允许所有人拍砖规格写出来之后不是直接拍板进开发而是拉一次简短的对齐评审把这个规格交给大家。我习惯的做法是把规格贴在群里或者评审文档里给24小时的阅读期然后约一个不超过30分钟的会议。会议的重点不是“过一遍内容”而是直接奔着问题去哪些边界没覆盖、哪些行为描述有歧义、哪些地方超出了当前版本范围、有没有更好的方案。每个人可以发表意见但有一条规则意见必须落到规格文件上要么改措辞要么增删条目。口头说说的意见会后就会被忘掉等于白说。这个环节我见过两种极端一种是谁都不说话另一种是全员沉浸式抠细节。我一般会跟团队说评审是找问题不是认可你有问题说问题没问题就过。对改动范围大的规格我还会要求核心干系人书面确认哪怕只是一行“我同意这个方案”。3.3 第三步方案细化给行为找到技术落点问题澄清之后规格进入技术设计阶段。这一步的核心是把“行为契约”映射到具体的代码改动位置哪个模块、哪个接口、哪个数据结构要变新增什么删除什么。不一定要写代码级别的细节但改动的范围要想清楚。我常用的做法是在规格文件里追加一个“实现方案”部分简单描述技术思路即可。这里的关键是养成关联的意识每一条行为变化都应该能找到对应的技术落点。找不到落点的行为是空谈有落点却不在规格里的行为是隐患。举个例子那个导出功能的规格里有一条“异步生成文件”技术落点就是新增一个任务队列或者复用现有的异步任务框架。这些落点写清楚后开发时就是按图索骥不用边写边想应该改哪里。3.4 第四步规格定稿之后编码才启动规格定稿是编码工作的“开工许可证”。只要规格还没有定稿任何人都不允许提前写实现代码哪怕只是搭架子也不行。这是我踩过大坑之后的切身教训有一次团队里一个开发觉得需求简单没等规格确认就直接上手改改完发现需求方想要的是另一种交互方式全部推翻。定稿的标准很简单相关干系人都看过有异议的条目已经解决并被记录。规格文件在版本库里归档后续所有的编码、测试都以这个版本为基准。3.5 第五步编码与PR规格对照落地真正写代码的时候不需要再纠结“我要做什么这个逻辑放哪”这些都已经在规格里定了。开发者的注意力可以全部集中在具体实现的质量上命名、封装、异常处理、性能细节。提PR的时候有一个习惯我一直保持着在PR描述里贴上规格文件的链接或者路径如果实现了过程中对规格里有偏移的地方改了接口参数、调整了数据格式必须在PR里明确标注并说明理由。这样评审者一眼能看到实现与规格的差异而不是从diff里慢慢猜。有个细节值得注意实现过程中的规格变更其实是一种很常见的状态需求理解深化后原定方案可能需要调整这很正常。但调整要走流程先改规格再改代码让规格始终是代码的上游。一旦允许代码反过来随意改规格整个体系的信用就崩塌了。4. 常见问题与排查技巧实录4.1 “紧急修复根本没时间写规格”这是听到过最多的反对声音线上故障十万火急谁有时间写规格我的回答是发生故障时的第一目标是止血止血本身可以不走完整流程简化到傻瓜式的“最小规格”就行——背景、改动点、影响范围、回滚方案几百字。这个最小规格不是走形式它有一个实实在在的作用帮你在高度紧张的状态下想清楚改动的影响边界。很多紧急修复翻车不是修错了而是修的时候没想全影响面。写这个用不了十分钟但这十分钟能逼你把影响范围过一遍脑子。事后必须补一份完整规格归档记录故障的真实原因、修复方案、后续预防措施。这样做的好处是防止同一个坑踩第二次。4.2 “写了规格没人看团队流于形式”规格文件写完往仓库里一推然后就没有然后了。这个问题非常典型根源多半在于规格没有嵌入开发流程。如果写不写规格对开发没有影响那自然会沦为形式。破解方法就是把规格和流程绑死PR必须附带规格链接没有规格的PR不进入评审评审时先评规格再评代码定稿规格自动关联需求单、里程碑代码合入后规格即成为该功能的档案后续任何改动都必须更新它说白了形式主义的大锅不是团队懒而是流程没有给规格留出不可跳过的位置。一旦规格成为流程必经节点没有人会再把过程走过场。4.3 “规格太详细成了写作文大会”规格写得太长每次都像写毕业论文这种团队也很难坚持。要警惕一个倾向规格的详细程度越高维护成本越大迭代速度越慢。规格不是越详细越好而是越准确越好。我根据变更规模和影响面来“分级对待”影响单个模块内部的小改动两三段带格式的说明就够了跨模块、涉及接口变更的改动走完整模板涉及架构级决策的改动单独开专项设计评审。规格是工具不是负担怎么有效怎么来。4.4 规格与代码漂移了怎么修代码和规格不一致几乎每个团队都会遇到。漂移的原因是代码改了规格没同步更新。这类问题没有银弹唯一的办法是“常态化纠正”每次review发现不一致就当场修订规格每个迭代末尾花一点时间核对关键模块的规格与代码发现失联就补上。坚持几个迭代团队会养成同步更新的肌肉记忆。我个人问过一个团队里的资深开发为什么不喜欢更新规格。他说改代码是有明确反馈的改完就生效改规格没有即时反馈总觉得是白干活。这个心理很真实所以我后来规定规格同步也是评审通过条件之一建立起“改了代码不更新规格就扣分”的约束。时间久了大家就意识到维护文档和写代码一样是对未来负责。4.5 不写规格的时候长什么样做个对比经历过有规格和没规格两种状态我对这个是深有体会没有规格的状态是需求口头一说开发凭理解开工实现过程中发现理解错了返工重来开发完成了测试按自己的理解验验出跟需求不一致来回撕扯上线一段时间后新开发接手读代码读到一头雾水不知道当初为什么这么写需求方和开发组为了“当初是不是这么说的”各执一词没有证据。有规格的状态是需求讲清楚写下来对齐确认开发按规格实现遇到疑问翻规格规格没写的地方先补规格再动手测试按规格写用例规格覆盖不到的地方说明测试盲区接手维护的人先看规格几分钟就理解了设计意图和限制条件争议发生时翻规格谁写的、什么时候写的、当初怎么定的一目了然。这两套状态我都真实经历过从混乱走向秩序的感觉就是团队开始“变得可预测”。代码质量不只是靠技术更是靠流程逼出来的。5. 落地OpenSpec的几个实操建议5.1 开始时要小步快跑先跑通再说一上来就想把所有项目、所有改动都纳入规格流程很容易引发团队反弹。建议先挑一个中等规模的功能改动从头到尾走一遍流程写规格、评审、定稿、开发、验收。团队的真实感受会告诉你这套流程适不适合哪些环节需要调整。流程需要先长出来再优化。5.2 模板要放在仓库里而不是聊天软件里规格模板应该跟代码放在同一个版本库里一级目录放一个specs/下面按日期和主题建子目录写成Markdown。这样做的好处格外实际规格跟代码同源管理改起来能追踪PR时可以直接引用路径评审记录、修改历史全都沉淀在版本库里。如果规格散落在聊天记录或网盘里那基本等于没写。目录结构可以参考specs/ 2025-06/ order-export/ README.md cancel-refund-refactor/ README.md 2025-07/ user-center-migration/ README.md5.3 定义“规格完成”的强制标准我习惯用一连串问题做完成的自我检查每个问题回答“是”才能走到下一步是否所有人都知道这次改动的背景是否明确列出了范围和边界是否描述了变更前后的行为差异是否标明了风险和兼容性考虑是否有人对当前版本明确表示了异议如果任何一个问题是否定的那规格还不到火候。写规格不需要特别的工具不需要重量级平台。一个模板、一个评审习惯、一个流程约束就够了。核心不在于工具多好而在于团队是否认可“先对齐、再编码”这个基本原则。在我的实践里OpenSpec真正带来的改变不是“文档变多了”而是“返工变少了”“疑问变少了”“扯皮变少了”。有一次我们做了一个跨模块的重构按照规格流程一步步走最终一次评审通过实现过程和设计完全一致上线后没有任何回归问题。放在以前这种规模的重构通常要来回磨合好几轮。这件事让我确定了规格先行不是繁琐的流程而是对团队成员时间和精力的最大尊重。作为亲历者我建议你先别纠结这门方法叫什么名字从身边最近的一次需求开始在写第一行代码之前先花二十分钟把“为什么改、改什么、不做什么、风险在哪”写下来。然后拿着这份说明去问一下使用方、相关同事听听他们怎么说。做完这一步你会立刻体会到原来改代码之前做的那件事省下来的远不止一个晚上的加班时间。