别让经验把你坑了:老程序员的"去芜存菁"
Posted on 三 21 10月 2026 in Journal
| Abstract | 别让经验把你坑了:老程序员的"去芜存菁" |
|---|---|
| Authors | Walter Fan |
| Category | Journal |
| Version | v1.0 |
| Updated | 2026-10-21 |
| License | CC-BY-NC-ND 4.0 |
大纲
展开看看
- 一个教训:想当然以为"一个 master 及副本都挂了,落在其他 master 上的 key 照样能读",据此写了一堆代码——结果
cluster-require-full-coverage=yes下整个集群停摆,代码全白写。 - 经验主义的坑:经验不是知识,是"在某个条件下验证过的结论"。坑在于条件变了,你还在用旧结论。
- 为什么老手更容易栽:越熟练越省力,大脑默认走捷径;经验攒得越多,重新求证的"心理成本"越高。
- 去芜存菁:把脑子里的经验分成三类——仍然成立的、要加前提的、已经过期的,定期清一遍。
- 从根上改:一条指导原则(经验只能提出假设,不能代替验证),四个具体动作。
- 一张清单:下断言前先过一遍,防止凭记忆开口。
前段时间我在一个 Redis Cluster 的场景里栽了个不大不小的跟头。当时脑子里有个“常识”:集群是分片的,每个 master 管一段 key,那么一个 master 连它的副本一起挂了,顶多是它那段 key 读不了,落在其他活着的 master 上的 key,总该照样能读吧? 基于这个想当然,我写了一堆代码——把一批 key 挨个算出它落在哪个 slot、归哪个 master,再逐一去验证谁还能读、谁读不了,准备做一套“部分降级可用”的逻辑。
写完去真机上一跑,傻眼了:挂掉那段的 key 读不了是意料之中,可所有其他 master 上的 key 也全读不了,整个集群直接 CLUSTERDOWN。翻配置才想起来,cluster-require-full-coverage 默认就是 yes——只要有一段 slot 没有活着的节点覆盖,Redis 宁可让整个集群停摆,也不提供“只有半拉 key 空间可用”的服务。我那套精心计算 key 归属、逐一验证的代码,从第一行起就是白写的:集群根本不会给我“部分可用”这个选项。
这件事把一个老问题又摆到我面前:经验是把双刃剑。 它让你反应快、下判断省力,同时也在悄悄让你放弃求证——越熟的东西越懒得查,越懒得查就越容易把一个“听着很合理”的推断当成“板上钉钉的事实”。分片、各管一段、互不影响,这套直觉太顺了,顺到我没停下来问一句:Redis 真是这么设计的吗?这篇就想说清楚这个坑长什么样、为什么干得越久越容易踩,以及怎么给自己脑子里那堆经验做一次认真的“去芜存菁”。
经验不是知识,是"某个条件下验证过的结论"
先把概念掰开。我们平时混着说的“经验”,严格讲是这么个东西:
经验 = 在某一组特定条件下,被反复验证过的因果结论。
重点在“特定条件”这四个字。你当年得出“这么干准没错”的时候,背后有一整套默认前提:那个版本、那套配置、那种规模、那个场景。推断本身听着合理,错的是你把前提当成了不存在,直接把直觉当成了事实。
回到我那次踩的坑。“分片系统,各管一段,互不影响”这套直觉,在很多系统里确实成立——一个分库挂了,其他分库照常读写,是再正常不过的事。我就是把这套在别处成立的经验,原封不动地套到了 Redis Cluster 上。偏偏 Redis 在这里做了一个和直觉相反的设计:它认为一个“只有部分 key 空间可用”的集群,比一个干脆停摆的集群更危险(因为你可能在不知情的情况下读到残缺的数据),所以默认选择整体 FAIL。我的经验没错,错在它成立的前提——“分片之间互不影响”——在 Redis Cluster 的默认配置下根本不成立。
这就是经验主义最阴险的地方:它给你的推断往往在别处是对的,只是对的那个世界,不是你眼下这个。 它不像语法错误那样会当场报错,而是让你顺顺当当写完一堆代码,直到真机一跑才告诉你:前提错了,整片地基是歪的。
为什么干得越久,越容易在这上面栽
你可能以为经验越多越不容易出错。恰恰相反,在“轻信经验”这件事上,老手的风险比新手还高。原因有三个,一个比一个隐蔽。
第一,大脑天生爱走捷径。 这不是毛病,是节能设计。一件事做过几百遍,它就从“需要动脑的思考”降级成“不过脑子的反射”。开车的老司机不会每次都想“先踩离合再挂挡”,正是因为这套动作沉到了肌肉里。省力的代价是:当路况变了、规则改了,你还在用那套反射,而且根本意识不到自己在用。
第二,经验攒得越多,重新求证的“心理成本”越高。 新人查一个问题,心态是“我本来就不懂”,查起来没有包袱。老手去查一个自己“早就会”的东西,心里那道坎很高——万一查出来跟自己讲了十年的不一样,等于承认自己错了十年。于是潜意识里就倾向于不查,用一句“这我熟”把求证挡在门外。我那次 Redis 的坑,就是被“分片系统这我熟”这种底气放行的——熟到压根没想起去确认一个默认配置。
第三,你的经验常常被别人的经验污染。 技术圈里很多“常识”是口口相传的二手结论,源头是谁、在什么条件下成立,早就没人追究了。你以为那是自己的经验,其实是你在某篇博客、某次分享、某个同事嘴里听来的,连它当初成立的前提都没见过。二手经验比一手经验更危险——一手的至少你亲历过条件,二手的连条件都是模糊的。
三条叠加,结果就是:经验越丰富的人,越需要主动给自己的经验“上验证”,因为自动验证的机制在你身上已经关掉了。
去芜存菁:把脑子里的经验分成三类
“去芜存菁”不是一句口号,它得落成一个动作:把你脑子里那些张口就来的结论拎出来,一条条过一遍,分进三个筐。
| 类别 | 判断标准 | 怎么处理 |
|---|---|---|
| 仍然成立 | 前提没变,近期还验证过 | 留着,但记住它的前提 |
| 要加前提 | 结论对,但只在特定条件下成立 | 补上前提再用,别裸着用 |
| 已经过期 | 条件早变了,结论不再成立 | 删掉,并警惕自己惯性复用 |
我那条“分片系统各管一段、互不影响”的经验,就该从“仍然成立”降级到“要加前提”:它在很多分片系统里对,但在 Redis Cluster 的默认配置(cluster-require-full-coverage=yes)下不成立。补上“这取决于集群怎么配”这个前提,它就从一个会坑人的断言,变回一条有用的知识。
怎么找出哪些该重新分类?几个信号很好使:
- 你讲这句话的时候用的是“肯定、绝对、一定”这类词。 越斩钉截铁,越值得回去查一眼它的前提还在不在。
- 这条结论你已经很多年没真正验证过了。 “一直都是这么干的”本身就是个危险信号。
- 你发现自己拒绝查证,理由是“这我熟”。 这句话一出现,基本就该去查了。
这件事不用等到出事才做。我的习惯是,每当要在文章里、在设计评审里、在给同事的建议里下一个“肯定句”,就顺手问自己一句:这条结论,我是真验证过,还是只是记得它? 记得,和验证过,是两回事。
从根上改:一条原则,四个动作
光知道有坑没用,得从习惯上改。先立一条指导原则,它能管住上面所有情况:
经验只能帮你提出假设,不能替你完成验证。 经验让你快速猜到“大概是这样”,但“确实是这样”必须靠当下的调查来确认——尤其是你要据此下结论、做决策、给别人建议的时候。
把这条原则拆成四个能落地的动作:
-
下断言前,先把它当成假设。 凡是要写进文档、讲给别人、作为决策依据的“肯定句”,先在心里给它降一级:这不是结论,是个待验证的假设。源码翻一眼、文档查一句、环境里跑一下——验证的成本通常比你想象的低得多,低到没有理由跳过。
-
区分“我验证过”和“我听说过”。 给脑子里的每条经验标个来源:是自己亲手撞出来的,还是从别处听来的二手货?二手的默认不可信,用之前补一次一手验证。来源模糊的经验,等同于没有经验。
-
主动去找反例,而不是只找佐证。 人下意识只会去找支持自己的证据(确认偏误)。反过来用:故意问一句“什么情况下这条会不成立”。我那次只要问自己一句“Redis 真的允许集群部分可用吗”,去翻一眼默认配置,那套白写的代码根本不会动手。一个主动找来的反例,胜过十条顺手捡来的佐证。
-
把踩过的坑沉淀成清单,而不是沉淀成情绪。 栽了跟头,别光懊恼“我怎么又犯了”。把它写下来:当时凭的是哪条经验、错在哪个前提、下次在哪个环节能拦住。情绪会淡,清单不会。下面这张就是我从这次 Redis 的事里沉下来的。
一句话:
经验负责让你跑得快,调查负责让你不跑偏。 两个都要,但顺序不能错——先用经验提假设,再用调查定结论,永远别让经验越俎代庖。
下断言前的核对清单
把前面那套拆成一张随手能过的清单。下次准备开口下结论、写进文档、或者在评审里拍板之前,花十秒走一遍:
- [ ] 这是验证过的结论,还是记得的印象?
- [ ] 它当初成立的前提是什么?现在那个前提还在吗?
- [ ] 这条经验是一手(我亲历)还是二手(听来的)?二手的查了吗?
- [ ] 我有没有主动找过反例——“什么情况下它不成立”?
- [ ] 我要下的断言里有没有“一定、绝对、肯定”?有的话,是不是太满了?
- [ ] 如果这条被别人当真照做,代价有多大?代价越大,越该多查一步。
最后一条是权重。查证是有成本的,不可能每句话都刨到源码。判断标准是代价:一句随口的闲聊说错了无伤大雅,但一个要写进文章、进设计、进线上决策的断言说错了,影响会一路放大。代价越大的断言,越值得你压住那句“这我熟”,多走一步调查。
总结:经验提假设,调查定结论
把这件事压成一句话:经验不是用来省掉调查的,是用来让调查更快命中的。
我那套为“集群部分可用”写的代码,错不在“分片各管一段”这条经验本身——它在很多系统里确实成立。错在我凭着“这我熟”,跳过了确认一个默认配置这一步,结果整片地基是歪的。老手最该警惕的,恰恰是这种被熟练感放行的断言:它们来得太顺,顺到你忘了它们也需要验证。
去芜存菁不是一次性的大扫除,是一个随身带的习惯:每次要下肯定句,先问自己是验证过还是只是记得。记得就去查。查的成本,几乎总是比栽跟头的成本低。
在这个变化快到前提天天在改的时代,能救你的不是“我经验丰富”,而是“我经验丰富,但我每条都肯回头再查一眼”。
全文思维导图
@startmindmap
<style>
mindmapDiagram {
node {
BackgroundColor #F8F9FA
RoundCorner 10
Padding 10
FontSize 13
}
:depth(0) {
BackgroundColor #1E3A5F
FontColor white
FontSize 18
FontStyle bold
}
:depth(1) {
FontSize 15
FontStyle bold
}
:depth(2) {
FontSize 13
}
}
</style>
* 经验主义的危害
** 一个教训
*** 以为分片各管一段互不影响
*** 为"部分可用"白写一堆代码
*** 其实默认整体停摆
** 经验的本质
*** 是特定条件下验证过的结论
*** 坑在前提变了还在套用
** 老手为何更容易栽
*** 大脑爱走捷径
*** 重新求证心理成本高
*** 二手经验污染
** 去芜存菁
*** 仍然成立
*** 要加前提
*** 已经过期
** 从根上改
*** 原则 经验只提假设
*** 下断言先当假设
*** 分一手二手
*** 主动找反例
*** 坑沉淀成清单
** 核对清单
*** 验证过还是记得
*** 前提还在吗
*** 代价越大越要查
@endmindmap

本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。 欢迎在我的个人网站 https://www.fanyamin.com 访问原文并评论。