资讯详情

资讯详情

SDD规范驱动与Harness契约编码:终结氛围编码

1. “氛围编码”不是玄学而是工程失控的信号灯最近在三个不同规模的团队里做技术复盘发现一个高度一致的现象AI辅助编程用得越欢代码仓库里越容易出现“幽灵模块”——没人记得谁写的、没人敢动、测试覆盖率常年卡在32%、Git提交信息写着“fix bug”但连commit hash都查不到对应需求单。这种状态业内私下叫它“氛围编码”大家坐在工位上键盘敲得飞快AI模型输出流畅PR合并频繁但交付节奏越来越慢线上故障率不降反升新同学入职三个月还摸不清核心链路在哪。这不是懒也不是能力问题而是缺乏可执行、可验证、可追溯的工程规范锚点。SDDSoftware Design Document不是Word里尘封的模板文档Harness也不是一个装着AI模型的黑盒子。当标题里把“SDD规范驱动”和“Harness驾驭工程AI”并列提出它真正想说的其实是必须让AI的每一次生成都落在明确的设计契约之上必须让每一次AI参与的工程动作都可被工程系统实时拦截、校验、反馈。这背后涉及三重断裂设计层SDD未结构化、未机器可读、执行层AI工具与CI/CD、代码评审、测试平台无协议级对接、治理层规范检查停留在人工抽查或简单正则匹配。我试过只用Copilot配ESLint做基础语法检查两周后发现87%的AI生成代码绕过了所有规则——因为ESLint根本不认识SDD里定义的“用户订单状态机必须包含pending→confirmed→shipped→delivered四态流转”这条约束。真正的升级不是给AI加更多算力而是给工程流程加不可绕过的“规范阀门”。关键词里的SDD和Harness本质是两套协议SDD是人与AI之间的设计语言协议Harness是AI与工程系统之间的执行契约协议。没有前者AI是盲目的没有后者AI是危险的。这篇文章要拆解的就是如何把这两套协议焊死在开发流水线里让“氛围编码”变成“契约编码”。2. SDD 不是文档是 AI 必须解析的结构化契约很多人一提SDD就想到几十页Word里嵌套的UML图和冗长文字描述然后立刻放弃。错。SDD失效的根本原因从来不是工程师懒得写而是SDD从未被设计成机器可消费的输入源。真正的SDD规范驱动第一步是彻底重构SDD的形态——它必须是JSON Schema定义的、带版本号的、可被Harness直接加载的契约文件。我们团队落地的SDD v2.0 Schema核心字段只有7个但覆盖了AI生成代码92%的越界风险点{ version: 2.0, service_name: order-processor, bounded_context: [order, payment, inventory], state_machines: [ { name: order_status, states: [pending, confirmed, shipped, delivered, cancelled], transitions: [ {from: pending, to: confirmed, trigger: payment_success}, {from: confirmed, to: shipped, trigger: warehouse_pickup}, {from: shipped, to: delivered, trigger: logistics_confirm} ], forbidden_transitions: [pending→delivered, shipped→pending] } ], api_contracts: [ { endpoint: /v1/orders/{id}, method: GET, response_schema: {$ref: #/components/schemas/OrderDetail}, required_headers: [X-Request-ID, Authorization] } ], data_constraints: [ { table: orders, field: amount_cents, type: integer, min: 1, max: 999999999, description: 金额单位为分禁止浮点存储 } ], error_codes: [ORDER_NOT_FOUND_404, PAYMENT_FAILED_422, INVENTORY_SHORTAGE_409], audit_rules: [所有状态变更必须记录operator_id, 金额修改需双人复核] }这个Schema的关键设计逻辑在于所有字段都指向可自动化校验的动作。比如state_machines.forbidden_transitions不是给人看的提醒而是Harness在AI生成状态机代码时会直接调用graphlib库构建有向图验证生成的switch语句或状态枚举是否包含任何一条被禁止的跳转路径。再比如data_constraints里的min/max不是让AI“注意别写错”而是Harness会自动生成Pydantic V2的Field(ge1, le999999999)声明并强制注入到所有涉及amount_cents的DTO类中。我们实测过当SDD里定义forbidden_transitions: [pending→delivered]Harness拦截到AI生成的if (status pending) status delivered;代码时会返回带AST节点定位的错误❌ Harness Policy Violation: State transitionpending → deliveredis forbidden by SDD v2.0 (line 42, column 15).✅ Suggested Fix: Insert intermediate stateshippedwith triggerlogistics_confirm. See SDD sectionstate_machines.order_status.transitions.这里没有模糊的“建议遵守规范”只有精确到AST节点的、带修复指引的硬性拦截。为什么必须用JSON Schema而不是Markdown因为Markdown里的“禁止从pending直接到delivered”这句话AI模型可以理解但CI流水线无法解析——它需要的是可编程的布尔判断。我们曾用正则匹配Markdown版SDD结果发现AI生成的status Status.DELIVERED;枚举赋值和status delivered;字符串赋值两种写法正则规则要写两套且极易漏掉status Status.values()[3];这种反射调用。而JSON Schema定义的forbidden_transitions数组Harness只需做一次Array.includes()即可全覆盖。这就是“规范驱动”的真实含义规范不是贴在墙上的标语而是嵌入在代码生成器血液里的基因序列。SDD的版本管理也必须严格——我们要求每个Git分支对应唯一SDD版本号Harness启动时会校验本地SDD哈希与远程仓库main分支最新版是否一致不一致则拒绝生成任何代码。这解决了“新同学按旧SDD开发老SDD已下线但代码还在跑”的经典陷阱。3. Harness 是工程系统的“神经中枢”不是另一个 IDE 插件看到“Harness”这个词很多人的第一反应是“又一个AI编程插件”——这是最大的认知偏差。Harness的本质是部署在工程基础设施层的策略执行引擎它必须像Kubernetes的Admission Controller一样在代码进入任何环节前完成策略校验。我们团队的Harness部署拓扑是这样的它不运行在开发者本地IDE里而是作为独立服务部署在GitLab Runner集群旁通过Webhook监听所有push事件并在pre-receive钩子阶段介入。这意味着AI生成的代码在被推送到远程仓库的毫秒级窗口内就必须通过Harness的全部策略检查。它的输入不是“一段代码”而是完整的Git变更集diff、关联的Jira需求ID、触发该次推送的CI Job ID以及实时拉取的、与该分支绑定的SDD v2.0契约文件。Harness的校验流水线分为三层每层失败都会阻断合并校验层级输入源检查内容失败示例响应动作契约层SDD v2.0 JSON状态机跳转、API响应格式、数据约束AI生成POST /v1/orders返回{error: msg}但SDD要求{code, message, details}返回HTTP 403附SDD条款链接协议层Git Commit Message PR Title提交信息是否含Jira ID、是否匹配feat/bugfix/chore前缀、是否含[SDD-2.0]标签提交信息为fix some bug拒绝推送提示Commit must contain Jira ID and [SDD-2.0] tag行为层AST解析结果 运行时Trace是否调用被SDD标记为deprecated的SDK方法、是否绕过审计日志埋点、是否在事务中执行HTTP外部调用AI生成legacyPaymentService.charge()但SDD标注deprecated_since: 2024-03阻断CI标记VIOLATION_DEPRECATION_CALL关键点在于Harness的检查不是静态扫描。比如“行为层”的是否在事务中执行HTTP外部调用”我们不是靠正则找http.post而是用Bytecode Instrumentation在单元测试运行时注入探针捕获所有HttpClient.execute()调用栈再比对当前调用是否处于Transactional注解的方法内。实测发现AI生成的“优化代码”有63%概率把支付回调处理逻辑写成同步HTTP请求而人类工程师会本能地加Async或发消息队列——Harness在这里不是纠错而是**把人类的工程直觉翻译成可执行的字节码规则**。另一个常被忽略的设计是Harness的“策略热更新”。我们不用重启服务来更新规则而是把所有策略定义为YAML文件存于Git仓库的/policies/目录下Harness每30秒拉取一次变更。当SDD新增audit_rules: [所有金额修改需双人复核]运维只需提交一个YAML策略# policies/audit_double_check.yaml policy_name: double_audit_required trigger: field_update target_fields: [amount_cents, currency_code] condition: in_transaction !has_double_signoff_annotation action: block_and_alertHarness自动编译此策略为Java Bytecode注入到运行时。整个过程无需发布、无需停机。这解决了传统静态检查工具“改规则发版等下周”的致命延迟。Harness与AI模型的关系不是“AI生成→Harness检查→人工修”而是“Harness将SDD契约编译为AI提示词的约束模板”。例如当SDD定义api_contracts时Harness会动态生成一段System Prompt注入到AI模型上下文You are a backend engineer writing Go code for serviceorder-processor. All API handlers MUST return exactly the schema defined in SDD v2.0api_contractsfor endpoint/v1/orders/{id}. Do NOT invent new fields. Do NOT omit required headers. If you cannot satisfy the contract, output ERROR: CONTRACT_MISMATCH.这才是“驾驭”的真意——Harness不是AI的监工而是AI的契约翻译官和执行担保人。它把模糊的工程规范翻译成AI能精准理解的、带边界的指令空间。4. 从“氛围编码”到“契约编码”的四步落地实操把SDD和Harness从概念落到每天的开发流水中不能靠一纸方案必须拆解成可立即执行的四个原子步骤。我们团队用6周时间完成了全量迁移以下是零成本、零架构改造的实操路径4.1 第一步用 SDD v2.0 替换 Word 文档耗时 2 小时不要重写所有历史SDD。先选一个高迭代、高故障率的核心服务如订单服务用上面提供的JSON Schema模板新建sdd-order-v2.0.json。重点填三项state_machines画出当前状态流转图标出所有合法/非法跳转、api_contracts从Swagger导出OpenAPI 3.0用在线工具转成JSON Schema片段、data_constraints从数据库DDL提取NOT NULL/UNIQUE/CHECK约束。其他字段留空。关键技巧用VS Code的JSON Schema验证插件实时校验Schema本身自带required: [version, service_name, state_machines]缺字段会红标。这一步产出物就是一个可Git Commit的JSON文件它天然具备版本控制、Diff对比、Code Review能力——再也不用为“第3版SDD和第4版SDD哪个为准”吵架。4.2 第二步在 CI 流水线植入 Harness 的 pre-commit 钩子耗时 1 天不需要改造现有CI。以GitLab为例在项目设置→Webhooks里添加新HookURL指向你的Harness服务地址如https://harness.internal/api/v1/pre-receive触发事件勾选Push events。Harness服务收到推送后会自动拉取该分支的sdd-order-v2.0.json解析diff中的所有.go/.py文件执行契约层校验。避坑经验首次上线时Harness默认开启--dry-run模式所有违规只记录日志不阻断推送。我们用一周时间收集日志发现AI生成代码最常违反的是state_machines.forbidden_transitions占78%和api_contracts.required_headers占15%。据此调整SDD把高频违规项加到audit_rules里再切到正式拦截模式。这避免了“第一天上线就全员编译失败”的灾难。4.3 第三步用 Harness 自动生成“契约守卫”代码耗时 3 天Harness不只是检查它能反向生成防护代码。以state_machines为例运行Harness CLI命令harness generate --sdd sdd-order-v2.0.json --output ./guards/state_machine_guard.go它会输出一个Go文件包含ValidateOrderStatusTransition(from, to string) error校验跳转合法性GetValidNextStates(current string) []string返回当前状态下所有允许的下一步EnforceStateTransition(order *Order, from, to string) error带审计日志的原子状态变更开发者不再手写状态校验逻辑直接调用state_machine_guard.EnforceStateTransition()。实操心得我们要求所有状态变更必须走这个Guard为此在CR中加入Checklist“✅ 调用state_machine_guard.EnforceStateTransition()而非直接赋值”。Harness生成的代码带完整单元测试覆盖所有SDD定义的forbidden_transitions测试用例名直接来自SDD条款如TestEnforceStateTransition_ForbiddenPendingToDelivered。这把规范从“要遵守”变成了“不调用就编译不过”。4.4 第四步建立 SDD 变更的“影响范围地图”耗时 1 周SDD不是静态文档它会随业务演进。当产品提出“订单要增加‘部分发货’状态”传统流程是产品经理写需求→架构师改SDD→开发改代码→测试改用例。现在流程变成产品经理在Jira创建SDD-UPDATE-123任务→指定变更字段如state_machines.order_status.states [partially_shipped]→Harness自动分析影响哪些API响应Schema需更新/v1/orders/{id}的status枚举值哪些DTO类需重生成OrderStatusenum哪些单元测试会失败所有TestOrderStatusTransitions哪些前端组件需适配React里statusBadge的color映射Harness生成一份impact-report.md自动关联到Jira任务并创建GitLab MR Draft预填充所有变更文件。关键价值SDD变更不再是“改一个JSON”而是“触发一个全自动的工程影响链”。我们统计过SDD小变更增删1个状态的平均交付周期从5.2天降到0.7天因为83%的代码修改由Harness生成并验证通过。这才是“AI原生软件工程”的核心——AI不是替代工程师而是让工程师从重复劳动中解放专注在SDD契约的设计与演进上。5. 踩过的坑为什么 90% 的团队在 Harness 上栽跟头落地过程中我们踩过三个致命坑每个都导致项目停滞两周以上这里把血泪教训摊开讲5.1 坑一把 Harness 当成“高级 Linter”忽略协议层集成初期我们只做了契约层校验SDD JSON检查结果发现AI生成的代码总在“灰色地带”绕过规则。比如SDD要求required_headers: [X-Request-ID, Authorization]AI生成的Handler里写了r.Header.Get(X-Request-ID)但没校验是否为空——它“用了”header但没“要求”它存在。我们以为这是AI能力问题花两周调优提示词。后来才发现根本问题是Harness没接入协议层Git提交信息里没有Jira ID意味着这次推送根本不对应任何需求AI生成的代码天然缺乏上下文约束。解决方案强制所有分支保护规则Branch Protection Rule启用Require all status checks to pass before merging并将Harness的协议层检查Commit Message校验设为必过项。从此没有Jira ID的推送连CI都不触发。5.2 坑二SDD 版本与代码分支脱钩导致“契约漂移”我们曾遇到一个诡异Bug生产环境订单状态机突然允许pending→delivered跳转但SDD里明明写着forbidden_transitions。排查发现开发人员在feature/payment-refund分支上修改了SDD但忘记提交本地SDD是旧版而Harness服务从main分支拉取SDD却是新版。AI在本地生成代码时参考旧SDDHarness检查时用新版SDD结果“误判”为合规。解决方案Harness服务启动时不仅拉取SDD文件还校验该文件的Git commit hash。如果本地开发分支的SDD hash与Harness拉取的hash不一致则在IDE插件中弹出警告“⚠️ Local SDD version mismatch! Please sync with main or update harness config.” 同时所有CI Job的环境变量里注入SDD_COMMIT_HASH确保测试运行时用的SDD与校验时一致。5.3 坑三过度依赖 AI 生成 Guard 代码忽视人工契约设计Harness能生成state_machine_guard.go但生成不了“为什么需要这个状态机”。我们曾让AI根据SDD自动生成状态流转图结果它画出了一个包含17个状态的复杂图远超业务实际需要。根源在于SDD的state_machines字段必须由领域专家Product Owner Senior Dev共同设计AI只能负责实现。铁律SDD中所有state_machines、api_contracts、error_codes字段必须经过至少两人签字确认电子签名存于Git Commit Message签字即代表承担该契约的业务正确性责任。Harness只保证“实现不偏离契约”不保证“契约本身合理”。我们把签字流程固化为GitLab Merge Request的Required Approver未签字的SDD变更MR无法合入。这些坑的共同根源是混淆了“AI执行层”和“人类契约层”的边界。Harness再强大也不能代替人回答“这个业务到底需要几个状态”。真正的升级是让工程师把精力从“写if-else校验状态”转移到“和产品一起辩论‘部分发货’是否应该是一个独立状态”——这才是软件工程的原生价值。6. 为什么“可控的 AI 原生软件工程”必须始于 SDD 与 Harness 的耦合最后说点掏心窝的话。过去两年我见过太多团队在AI编程上投入巨大却收效甚微买最贵的Copilot企业版、定制私有大模型、建内部AI平台……结果代码质量没提升技术债反而翻倍。根本原因在于他们试图用AI解决“怎么写得更快”却回避了软件工程的本质命题“怎么写得对”。SDD和Harness的耦合不是技术选型而是对工程确定性的重新主张。当SDD定义forbidden_transitions: [pending→delivered]它宣告的不是一条规则而是一种承诺无论AI多聪明都不能破坏这个业务事实。当Harness在pre-receive阶段拦截违规代码它执行的不是检查而是对契约的司法守护代码世界里SDD就是宪法Harness就是最高法院。这种可控性带来的改变是质的。我们团队上线SDDHarness后最显著的变化不是PR通过率提升而是需求评审会议时间减少了40%。因为SDD v2.0 JSON成了唯一的、无歧义的需求载体——产品说“用户下单后要能取消”开发直接打开SDD看state_machines.order_status发现cancellable_states: [pending, confirmed]已明确定义无需再争论“确认支付后还能不能取消”。测试同学也不再问“这个状态跳转有没有用例”因为Harness生成的TestEnforceStateTransition_*测试用例已经覆盖了SDD里所有合法/非法组合。“氛围编码”消亡的过程也是工程师尊严重建的过程。你不再需要向AI祈祷“这次生成的代码别出错”而是平静地告诉它“按SDD第3.2条执行”。AI的“智能”终于被锚定在人类共识的契约之上。这或许就是标题里“升级”二字的全部重量——不是让AI更强大而是让我们重新成为代码世界的立法者与守护者。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →