1
00:00:00,100 --> 00:00:06,432
本内容改编自小山学堂《学 AI 产品，从入门到精通》，为二次演绎配音版。

2
00:00:06,382 --> 00:00:12,151
这一集是工程可行性的最后一集，主题是质量底线和文档沉淀。

3
00:00:12,151 --> 00:00:14,531
先说本集解决什么问题。

4
00:00:14,531 --> 00:00:20,781
前面几集解决的是能不能跑起来，这一集解决的是跑起来之后别烂掉。

5
00:00:20,781 --> 00:00:34,254
你可能已经体验过这种场面，让智能体连着做十个功能，回头一看，样式散成一片，注释等于没写，改个问题猜三轮，三个月后连某个功能当初为什么这么设计都想不起来。

6
00:00:34,254 --> 00:00:37,512
这些都不是能力问题，是纪律问题。

7
00:00:37,512 --> 00:00:40,348
再说为什么产品经理要关心。

8
00:00:40,348 --> 00:00:51,923
因为技术债不是工程师一个人的事，它会以最直接的方式反映在产品上，改一个按钮要动八个文件，修一个显示问题要两周，新需求排期越来越长。

9
00:00:51,923 --> 00:00:57,415
你在需求评审上省下的半小时，最后会以十倍的返工还回来。

10
00:00:57,415 --> 00:00:59,242
顺便交代结构。

11
00:00:59,242 --> 00:01:15,664
前两节讲样式和注释，都属于代码层面的质量底线；中间两节讲调试纪律和交付纪律，一条管怎么修问题，一条管怎么拒绝将就；最后一节讲文档沉淀，把决策从对话里捞出来，存进仓库。

12
00:01:15,664 --> 00:01:18,333
还有一句我想放在开头说。

13
00:01:18,333 --> 00:01:25,424
这一集的所有规则，本质都是同一句话，把选择权留在人手里，把纪律交给流程。

14
00:01:25,564 --> 00:01:28,038
先看一个很典型的现象。

15
00:01:27,988 --> 00:01:33,601
让智能体连着做十个功能，你会攒出八个长得差不多的按钮样式。

16
00:01:33,601 --> 00:01:38,408
它不是不会复用，是每一轮对话都不知道你已经有什么。

17
00:01:38,408 --> 00:01:41,149
素材分析了三个结构性原因。

18
00:01:41,149 --> 00:01:43,024
第一，看不见。

19
00:01:43,024 --> 00:01:53,504
新开一轮对话，上下文里只有这次给的几个文件，项目里已经有一个主按钮样式这件事，它无从得知，于是按需求现写一个。

20
00:01:53,504 --> 00:01:55,319
第二，更省事。

21
00:01:55,319 --> 00:02:06,641
读懂一套现有样式要把相关文件全看一遍，还得担心改了影响别处；新起一个名字零风险、零阅读成本，这是它的最优解，不是你的。

22
00:02:06,641 --> 00:02:08,504
第三，不敢碰。

23
00:02:08,504 --> 00:02:20,415
需要一个带阴影的按钮时，它宁可再写一个新样式，也不去改原来那个，因为改动别人在用的样式属于高风险操作，它选择了安全但会增殖的做法。

24
00:02:20,415 --> 00:02:25,043
三个原因指向同一件事，它缺一份我们已经有什么的清单。

25
00:02:25,043 --> 00:02:31,052
把这份清单写进项目规则文件，它每轮都能看见，增殖才会停。

26
00:02:31,052 --> 00:02:34,346
已经乱掉的项目怎么收，分四步。

27
00:02:34,346 --> 00:02:44,201
第一步，盘点，先只看不改，让它扫全项目的样式，产出一张重复清单，这一步不许动代码，你先看清欠了多少债。

28
00:02:44,201 --> 00:02:54,718
第二步，定变量，把随手写死的数值收成档位，主色、语义色、圆角两三档、间距四档、控件高度，档位要少，少才守得住。

29
00:02:54,718 --> 00:03:04,802
第三步，分批合并，一次一种控件，先按钮验证，再卡片验证，再输入框，每批单独提交，出问题能单独回滚。

30
00:03:04,802 --> 00:03:14,670
第四步，设闸，把写新样式前先搜变量和公共组件、搜到就复用、搜不到才新建并说明搜过什么，写进规则文件。

31
00:03:14,670 --> 00:03:18,408
不设这道闸，三个月后你还要再收一遍。

32
00:03:18,408 --> 00:03:24,562
还有一条判据特别好用，判断该不该合并，只问一句，这个差异叫什么。

33
00:03:24,562 --> 00:03:39,153
叫得出名字的留着，次要按钮、危险操作、触摸目标下限，这些是设计决策；叫不出名字的合掉，两个差两像素的圆角、两个肉眼分不出的蓝，它们不叫什么，是当时随手写的。

34
00:03:39,153 --> 00:03:41,064
三个坑也要避开。

35
00:03:41,064 --> 00:03:57,210
一把梭全量重构，它会给一个改了六十个文件的改动，你审不完也不敢发；顺手改视觉，会让你分不清页面变样是合并出的问题还是它的审美发挥；变量定太细，定出十二档圆角、九种灰，等于没定。

36
00:03:57,210 --> 00:04:02,535
有一句话我觉得比那条判据更好记，差异不是罪，没理由才是。

37
00:04:02,535 --> 00:04:08,015
同一件事反过来讲就是，它不会复用你没告诉它存在的东西。

38
00:04:08,164 --> 00:04:10,565
代码只能表达做了什么。

39
00:04:10,515 --> 00:04:18,280
为什么存在、为什么这样实现、调用时要注意什么，这些信息只有写进注释才能跨时间留存。

40
00:04:18,280 --> 00:04:24,145
而写好注释这四个字，智能体执行不了，必须给出固定结构和示例。

41
00:04:24,145 --> 00:04:26,128
结构就是三要素。

42
00:04:26,128 --> 00:04:27,835
第一，背景。

43
00:04:27,835 --> 00:04:32,691
这个函数为了解决什么业务问题、在什么场景下被调用。

44
00:04:32,691 --> 00:04:38,412
没有背景，读代码的人只能看到实现，看不到它为什么存在。

45
00:04:38,412 --> 00:04:40,564
第二，设计意图。

46
00:04:40,564 --> 00:04:46,128
为什么这样实现，选择这种方案的理由，以及放弃了哪些备选方案。

47
00:04:46,128 --> 00:04:49,842
版本记录里找不到这些，注释是唯一载体。

48
00:04:49,842 --> 00:04:51,826
第三，关键约束。

49
00:04:51,826 --> 00:04:57,775
调用方须知，副作用、依赖关系、边界条件这些非显而易见的注意点。

50
00:04:57,775 --> 00:05:01,429
少了这条，下一个调用者就会踩坑。

51
00:05:01,429 --> 00:05:04,169
素材给了一个很清楚的对比。

52
00:05:04,169 --> 00:05:17,979
同一个合并聊天记录的函数，差的注释只写一句，合并两个聊天记录列表，返回合并后的结果，这等于把函数名又念了一遍，读一眼代码就能得到同样的信息。

53
00:05:17,979 --> 00:05:42,863
好的注释写三件事，背景是前端每次会话恢复会带上本地缓存的历史消息，服务端也保留一份持久化记录，两者可能因网络中断出现分叉；设计意图是以服务端记录为权威，只追加本地独有的消息，不做全量替换，避免覆盖掉服务端已有的回复元数据；约束是本地传来的系统角色消息一律丢弃，不合并入结果。

54
00:05:42,863 --> 00:05:49,906
三个月后你想知道为什么以服务端为权威、为什么丢弃系统消息，答案都在里面。

55
00:05:49,906 --> 00:05:52,851
这里有个判断标准可以直接用。

56
00:05:52,851 --> 00:05:58,404
未来接手的人，没有这条注释，还能理解当初为什么这样做吗。

57
00:05:58,564 --> 00:06:03,538
注释有了结构，还要有保护规则，否则它重构一轮就没了。

58
00:06:03,488 --> 00:06:05,627
第一条是注释保护。

59
00:06:05,627 --> 00:06:13,584
重构时禁止以注释太长、代码自解释、顺便清理为理由，删除背景和设计意图注释。

60
00:06:13,584 --> 00:06:19,485
实现变了导致注释不准确时，必须同步更新内容，而不是删掉。

61
00:06:19,485 --> 00:06:22,226
第二条是代码删除声明。

62
00:06:22,226 --> 00:06:31,252
删除任何已有功能代码前，必须明确告知并说明理由，禁止以顺手清理、看起来没用为理由静默删除。

63
00:06:31,252 --> 00:06:37,550
认为某段代码该移除时，先标一个待办标记写明原因，拿到许可再删。

64
00:06:37,550 --> 00:06:40,339
素材里有个很典型的情景。

65
00:06:40,339 --> 00:06:46,372
它重构时发现一段兼容旧数据格式的代码，看起来没用，想顺手删掉。

66
00:06:46,372 --> 00:06:53,307
正确做法不是删，也不是原样留着，而是标注建议移除并说明理由，等确认。

67
00:06:53,307 --> 00:06:58,127
因为看起来没用和确认没用，中间隔着的正是线上事故。

68
00:06:58,127 --> 00:07:02,370
还有一条配套规范是错误处理，禁止空捕获。

69
00:07:02,370 --> 00:07:11,492
所有异常捕获和错误分支必须有实质性处理，日志记录加用户可见的错误提示，或者合理的降级逻辑。

70
00:07:11,492 --> 00:07:18,788
只打印一行日志、直接跳过、写一句忽略，都属于静默吞错，一律不允许。

71
00:07:18,788 --> 00:07:25,915
原因很实在，静默吞错会让问题在离现场很远的地方爆发，排查成本成倍上升。

72
00:07:26,068 --> 00:07:27,784
接下来讲调试。

73
00:07:27,734 --> 00:07:33,119
智能体遇到报错的第一反应是猜一个原因改改看，不行再猜一个。

74
00:07:33,119 --> 00:07:37,398
这一节立最核心的一条规矩，禁止猜测性修复。

75
00:07:37,398 --> 00:07:46,388
条款原文是，无法确认根因时，必须先通过日志、断点或测试脚本验证假设，禁止试着改一下看看。

76
00:07:46,388 --> 00:07:54,177
后端在终端打详细日志，前端在浏览器控制台打日志，无论什么问题，第一步都是加日志。

77
00:07:54,177 --> 00:07:57,181
素材里有个特别生动的例子。

78
00:07:57,181 --> 00:08:05,451
聊天输入框在中文输入法下，用户按回车确认候选词时，半截拼音被当成消息发了出去。

79
00:08:05,451 --> 00:08:19,044
猜着改的路径是这样的，先猜是回车事件没拦截，加一层判断；再猜是输入法合成状态没处理，再加一层；改了三轮，动了几十行，问题可能还在，还引入了新问题。

80
00:08:19,044 --> 00:08:30,547
先加日志的路径是这样的，在按键事件里打印出合成状态和事件类型，一眼就能看到合成中的按键也被当成确认处理了，一次改对。

81
00:08:30,547 --> 00:08:36,136
加日志的两分钟，买断的是猜错三轮的返工，还有被掩盖的根因。

82
00:08:36,136 --> 00:08:38,960
修复之前还要回答三个问题。

83
00:08:38,960 --> 00:08:41,244
第一，链路是什么。

84
00:08:41,244 --> 00:08:58,664
素材里那个未读数不更新的问题，链路是删除消息、更新会话摘要、重算未读数、推送列表刷新，排查发现重算未读数只在收到新消息时触发，删除路径根本没走到它，只盯着报错点是看不到这条链路的。

85
00:08:58,664 --> 00:09:00,755
第二，会波及谁。

86
00:09:00,755 --> 00:09:06,885
重算时机的改动会波及会话列表、应用角标、多端消息同步三处。

87
00:09:06,885 --> 00:09:09,938
第三，同一个坑还有没有别处。

88
00:09:09,938 --> 00:09:17,209
标记已读和撤回消息走的是同一条链路，同样漏了触发重算，这次一起修干净。

89
00:09:17,209 --> 00:09:25,286
修完之后还有最后一步，声明影响范围，一句话加三处清单，让人知道该回归测试哪些地方。

90
00:09:25,286 --> 00:09:28,135
交付前还有两道硬性检查。

91
00:09:28,135 --> 00:09:31,873
第一，禁止用假数据绕过真实接口。

92
00:09:31,873 --> 00:09:44,241
凡涉及模型调用的功能，交付前必须确认接口真的能访问；用户没给密钥时必须停下来要，禁止硬编码假响应或本地模拟绕过真实调用。

93
00:09:44,241 --> 00:09:47,173
第二，单元测试不过不得交付。

94
00:09:47,173 --> 00:09:52,738
核心业务逻辑、接口、数据处理函数、边界条件都要覆盖。

95
00:09:52,738 --> 00:09:57,233
这一节的所有条款可以压成四个字，证据先行。

96
00:09:57,233 --> 00:10:01,572
先拿到证据再动手，先声明影响面再交付。

97
00:10:01,708 --> 00:10:05,095
这一节讲一个特别容易被忽略的问题。

98
00:10:05,045 --> 00:10:12,785
你要一个完整的认证系统，它说先做一个简版的用户名密码登录，后续再加第三方登录。

99
00:10:12,785 --> 00:10:14,889
这个后续永远不会来。

100
00:10:14,889 --> 00:10:23,927
素材点出了真实动机，它说先做简版，往往与复杂度无关，它是想快速给你一个能跑的东西，来换取正反馈。

101
00:10:23,927 --> 00:10:29,937
先用临时方案、暂时用假数据、简单处理一下，背后是同一个模式。

102
00:10:29,937 --> 00:10:32,365
看时间线就很清楚了。

103
00:10:32,365 --> 00:10:44,095
第一天，简版上线，用户名密码登录能跑了，它承诺第三方登录后续再加，你也觉得挺合理，此刻补全只要零点五倍成本，可惜没人回头。

104
00:10:44,095 --> 00:10:55,177
第三十天，新需求源源不断，没人回头补，会话、权限、支付、通知四个模块开始直接依赖简版接口，补全成本升到三倍。

105
00:10:55,177 --> 00:11:04,456
第九十天，想补全时发现依赖已经长死，九个模块与简版耦合，重构成本高过重写，简版成了永久版。

106
00:11:04,456 --> 00:11:09,156
这就是一句后续再优化，在九十天里长成的东西。

107
00:11:09,156 --> 00:11:11,151
规则禁止两件事。

108
00:11:11,151 --> 00:11:24,720
一是禁止以任何理由简化实现，先用临时方案、后续再优化、暂时用假数据、简单处理一下，全部不接受；也禁止它主动规划分期、最小可用版本、阶段一二三。

109
00:11:24,720 --> 00:11:31,776
二是替代做法，评估一个功能只回答两个问题，完整做下来需要什么，有多复杂。

110
00:11:31,776 --> 00:11:39,132
确实太复杂时，明确列出需要你先做哪些前置决策，把选择权交还给人。

111
00:11:39,132 --> 00:11:44,120
已知有缺陷的方案，直接给正确版本，别先做一个将就的。

112
00:11:44,120 --> 00:11:46,908
这里有一条适用边界要说清楚。

113
00:11:46,908 --> 00:11:54,600
大型项目里这条规则可能显得激进，一个功能真需要两千行代码时，一次写完不现实。

114
00:11:54,600 --> 00:12:02,112
但正确动作依然成立，让它给出完整方案和真实工作量，由人决定是否拆分、怎么拆分。

115
00:12:02,112 --> 00:12:09,156
拆分是人的决策，降级是它的自作主张，这两者的区别就是这条规则的核心。

116
00:12:09,316 --> 00:12:11,369
最后一节讲沉淀。

117
00:12:11,319 --> 00:12:20,718
做了三十个功能，三个月后想查这个功能什么时候加的、当初为什么这样设计、中间改过几次方案，翻遍版本记录也找不到。

118
00:12:20,718 --> 00:12:27,893
解法是让智能体按严格模板维护三份文档，再加一份自动沉淀的方法论手册。

119
00:12:27,893 --> 00:12:30,453
四份文档各管一个维度。

120
00:12:30,453 --> 00:12:34,420
第一份，功能清单，回答这个功能怎么来的。

121
00:12:34,420 --> 00:12:46,487
它是功能点的唯一事实来源，状态从规划中到开发中到已完成或已取消，每个功能带一条历史沿革，记录初始需求、方案变更及原因、最终实现。

122
00:12:46,487 --> 00:12:50,249
取消的功能也不删，标出来并注明原因。

123
00:12:50,249 --> 00:12:53,879
第二份，变更记录，回答这次改了什么。

124
00:12:53,879 --> 00:13:05,850
按时间倒序，每条用表格记录问题或需求、根因或方案、改动范围、影响面、状态，类型分问题修复、新功能、重构、性能优化、文档。

125
00:13:05,850 --> 00:13:11,535
写之前必须读系统时间，禁止凭记忆填时间戳，禁止积压补写。

126
00:13:11,535 --> 00:13:15,441
第三份，发布说明，回答用户得到了什么。

127
00:13:15,441 --> 00:13:26,776
面向真实用户，语言风格和变更记录完全不同，每条描述必须能回答这对我有什么用，禁写调试功能、技术细节和用户无感知的改动。

128
00:13:26,776 --> 00:13:30,814
第四份，方法论手册，回答我们是怎么想的。

129
00:13:30,814 --> 00:13:43,530
它主动识别对话中的产品思路、决策逻辑和取舍偏好，提炼后写入，新对话自动继承，四段结构是产品原则、设计决策记录、用户体验偏好、反模式。

130
00:13:43,530 --> 00:13:45,958
为什么一定要放在仓库里。

131
00:13:45,958 --> 00:13:50,982
因为设计决策写在外部文档工具里也没用，智能体读不到。

132
00:13:50,982 --> 00:13:56,752
放在项目仓库内的文本文件，是唯一能让它自动获取上下文的方式。

133
00:13:56,752 --> 00:14:03,518
这句话我觉得是整节最关键的一句，文档的位置本身就是一种架构决策。

134
00:14:03,676 --> 00:14:07,952
最后给你一份可以马上用的判断清单，一共五条。

135
00:14:07,902 --> 00:14:11,676
第一条，样式收敛先盘后收再设闸。

136
00:14:11,676 --> 00:14:22,902
先只盘点不动代码，把在用的颜色和圆角收成一小套变量，然后一次一种控件分批合并，最后把先搜变量再写样式写进规则文件。

137
00:14:22,902 --> 00:14:28,455
判断该不该合并只问一句，这个差异叫什么，叫不出名字的合掉。

138
00:14:28,455 --> 00:14:30,967
第二条，注释写三要素。

139
00:14:30,967 --> 00:14:38,924
背景讲它为什么存在，设计意图讲为什么这样实现、放弃了什么，关键约束讲调用方须知。

140
00:14:38,924 --> 00:14:44,477
重构时禁止删除背景和设计意图，实现变了就同步更新。

141
00:14:44,477 --> 00:14:47,626
第三条，修问题先证据后动手。

142
00:14:47,626 --> 00:14:51,364
禁止猜测性修复，第一步永远是加日志。

143
00:14:51,364 --> 00:14:57,626
动手前回答三个问题，链路是什么、会波及谁、同一个坑还有没有别处。

144
00:14:57,626 --> 00:15:03,131
修完声明影响范围，交付前过真实接口和单元测试两道线。

145
00:15:03,131 --> 00:15:05,811
第四条，不接受分期交付。

146
00:15:05,811 --> 00:15:12,049
凡是先做简版、后续再优化、暂时用假数据这类说法，一律不接受。

147
00:15:12,049 --> 00:15:16,472
让它给出完整方案和真实工作量，拆不拆由你决定。

148
00:15:16,472 --> 00:15:21,797
记住那句判断，拆分是人的决策，降级是它的自作主张。

149
00:15:21,797 --> 00:15:24,657
第五条，把决策存进仓库。

150
00:15:24,657 --> 00:15:33,059
功能清单管生命周期，变更记录管技术细节，发布说明管用户感知，方法论手册管产品品味。

151
00:15:33,059 --> 00:15:35,895
写在仓库里，它才读得到。

152
00:15:35,895 --> 00:15:38,648
这五条背后是同一个态度。

153
00:15:38,648 --> 00:15:44,633
质量不是靠某一次认真换来的，是靠一道道设在动手之前的闸守住的。

154
00:15:44,633 --> 00:15:48,792
这一章到这儿收尾，下一章我们聊产品手感。

