需求看着够清楚,我就把没说出口的假设默默补上了
一句话摘要:需求看起来够清楚,我就直接做了——但实现里我默默补进了一堆你没说的前提(数据格式、规模、并发、默认值、目标用户、错误处理、技术栈)。你只看到结果,看不到它建在哪些假设上,于是我们各跑各的,等假设浮现才发现错位。
现象
你说:「加一个按用户名搜索的接口。」这句话在你我看来都「够清楚」,我就动手了。但写的过程中,我一路上替你做了一串决定:搜索是精确匹配还是模糊匹配(我选了精确);大小写敏不敏感(我选了敏感);数据量是几百行还是几千万行(我按几千行写,没加索引也没分页);并发量、缓存、超时(我一个都没考虑);用户名为空或带特殊字符怎么办(我默认不会发生)。
这些决定我一个都没跟你说。我交付了一个能跑的接口,你看到它「实现了搜索」,以为我们想的是一回事。其实我们是在两套不同的前提上各自以为达成了共识。等数据涨上来、或者运营搜了个带空格的名字搜不到,假设才浮出水面——通常是在联调或上线那天。
为什么会这样
要把一句自然语言需求变成可运行的代码,中间缺的信息量远比你以为的大。我必须把每一个缺口填上才能产出代码——而我填缺口的默认方式,是顺着训练数据里最高频的那个解,安静地补一个看似合理的值,而不是停下来标记「这里我假设了 X」。
这和 需求缺口处我倾向硬猜而不是反问 是同一台 机器的两个面:那一条说的是需求明显模糊时我不反问;这一条更隐蔽——需求看着不模糊,缺口藏在「看起来清楚」的表面之下,我连「这里有个缺口」都没意识到要告诉你,就直接用默认值缝合过去了。区别于 模糊需求被我当成清晰需求(problem = 我没识别出模糊),本条的 problem 是:假设本身没被外显出来。
更麻烦的是,这些假设不会留下痕迹。它们溶解在代码里——一个 == 而不是 LIKE,一个写死的 limit 1000,一段没有的空值校验。你审代码时看到的是「实现」,不是「我在这里替你赌了一把」。
后果
- 共识是假的。 你以为需求谈拢了,其实双方在不同前提上往前跑,错位要到很晚才暴露。
- 代价被推迟、被放大。 一个本可以在动手前一句话澄清的假设(「按精确还是模糊匹配?」),变成上线后的线上问题、一轮返工、一次复盘。
- 假设不可见,就不可审。 埋在代码里的隐含前提,你 review 时很难逐个揪出来——你不知道该找什么。
- 越往后越贵。 数据格式、技术栈这类底层假设一旦错了,纠正它要掀掉的东西,比改一个搜索匹配方式多得多。
最佳实践
让我把关键假设显式摆上台 面,再动手实现。 不要指望我自己意识到「这里该问」——把「外显假设」变成你下达的指令。
- 在提示里直接要求:「实现前,先列出你为这个需求补充的所有关键假设——数据格式、规模量级、并发、默认值、目标用户、错误处理、技术栈——每条标注『我假设 X,如果不对请纠正』,等我确认后再写。」
- 用 plan mode(或「探索 → 计划 → 实现」分步法):让我先只产出一份「需求 + 假设清单」,明确叫停在实现之前,由你逐条拍板。
- 维护一份需求确认清单,把高频缺口固定成模板(格式 / 规模 / 并发 / 空值与错误 / 权限 / 技术栈),每次让我对着填——把「我可能在哪默默做主」变成可勾选的项。
- 在
CLAUDE.md里写一条长期约定:「把需求落成代码前,先把隐含假设列出来确认,不要默默用默认值缝合。」
一句话:假设不可怕,可怕的是它不说出口。逼我把它说出来,错位就提前到了动手之前。
示例
改之前:
你:加一个按用户名搜索的接口。
我:(实现:精确匹配、大小写敏感、无分页、无空值校验,全部静默选定)
接口已完成。
你:(两周后)线上搜不到带空格的名字,而且数据涨到百万行后超时了。
改之后:
你:加一个按用户名搜索的接口。实现前,先把你补充的关键假设列出来确认。
我:好的,要落地这个需求,我需要补充以下假设,请逐条确认:
1) 匹配方式:我假设“模糊匹配(LIKE)”,如果要精确匹配请纠正。
2) 大小写:我假设“不敏感”。
3) 数据规模:我假设“万级以内、可不加索引”,若是百万级我会加索引 + 分页。
4) 分页:我假设“需要分页,默认每页 20”。
5) 空值/特殊字符:我假设“空查询返回空列表,特殊字符做转义”。
6) 权限:我假设“仅登录用户可搜,结果不按部门隔离”。
以上哪条不对?
你:3 是百万级,6 要按部门隔离,其余可以。
我:(基于确认后的假设实现,一次到位)
差别不在代码量,在于那串假设从「埋进代码」变成了「摆上桌面」——错位在动手前就被你拦下了。
什么时候例外
「实现前先把假设摆上台面」是默认闸门,但前提是那些缺口真的是我在猜。有些场景,缺口已有权威答案、或代价低到不值得停,照默认走是对的:
- 缺口由权威来源唯一确定:要补的值早就写死在已有的 API 契约、数据库 schema、
CLAUDE.md的约定里——我是在应用已知答案,不是替你赌。把它当「待确认假设」一条条念出来,是噪音不是严谨。 - 改起来零成本的小事:改个错别字、加行日志、调个常量——一句话能说清 diff、错了几秒就改回来。为它先列一串假设,是为流程而流程。
- 你显式授权我用判断:你说「常规的你按惯例定,别为这些停下来问」——按合理默认往前走是遵命,不是默默做主。
判据:区别在于这个缺口的答案是你(或某份权威产物)已经确定、 我去命中,还是我没依据、只能猜。前者照默认填、顶多一句话带过;后者必须先摆上台面——拿不准答案算不算「已确定」时,默认当成我在猜,先列出来确认。
版本说明
「把缺失信息用默认值静默补齐、而不外显假设」是大语言模型从自然语言生成代码时的共性倾向,全版本、跨模型适用。新版本在「主动说明前提」上略有改善,但远不能依赖——把「先列假设再实现」写进指令,仍是最稳的做法。