有些失败,我会记很久。
一件事情没有做好。
一次重要的机会没有抓住。
一个项目最后没有达到预期。
一次尝试没有得到结果。
有时候甚至只是一次表达失误。
事情已经过去了。
但脑子里还会不断重放:
“当时为什么这么做?”
“我怎么会犯这么低级的错误?”
“如果当时换一种方式,是不是结果就不一样?”
然后开始责怪自己。
能力不够。
判断错了。
执行力差。
准备不足。
是不是自己真的不行?
这种状态持续久了以后,我发现一个很奇怪的问题:
失败本身可能只发生了一次,但自责会让它重复发生很多遍。
而且每重复一次,都没有产生新的信息。
只是让自己越来越相信:
“我是一个失败的人。”
后来我突然想到:
如果这是线上系统发生了一次严重事故,我会怎么处理?
我不会坐在服务器旁边骂:
“你怎么这么没用?”
我会打开日志。
看监控。
还原现场。
分析时间线。
寻找触发条件。
定位根因。
检查影响范围。
制定修复方案。
然后:
写一份事故复盘报告。
为什么面对系统,我可以这么理性?
面对自己,却经常只剩下自责?
失败不是身份,而是一次系统事件
这是我后来特别想改变的一件事情。
以前失败以后,我很容易把:
事情失败
变成:
我失败了。
最后甚至变成:
我是一个失败的人。
这其实发生了一次非常危险的“类型转换”。
Event
↓
Failure
↓
Self Judgment
↓
Identity
一个具体事件,最后被转换成了对整个人的定义。
但如果换成工程视角:
System
↓
Incident
↓
Impact
↓
Root Cause
↓
Fix
↓
Prevent
失败只是:
一次系统事件。
它可以很严重。
可以造成损失。
可以暴露能力问题。
甚至可能意味着原来的方案根本不成立。
但它依然只是:
一个事件。
不是你的身份。
事故复盘最重要的第一原则:先还原事实
程序员做事故复盘的时候,第一件事情不是讨论:
“谁的问题?”
而是:
到底发生了什么?
时间是什么?
发生了什么操作?
系统处于什么状态?
哪个指标开始异常?
什么时候出现第一个错误?
影响了哪些用户?
持续了多久?
这叫:
事实还原。
放到人生里也一样。
比如:
“我做副业失败了。”
这句话其实信息量非常低。
可以继续拆:
什么时候开始?
投入了多少时间?
投入了多少钱?
原本期待什么结果?
实际结果是什么?
做了哪些动作?
获得了哪些反馈?
哪个环节最早出现偏差?
什么时候决定继续?
什么时候决定停止?
你会发现:
一旦开始写事实,自责就会减少。
因为你的大脑开始从:
“我是怎么回事?”
切换成:
“这件事情到底发生了什么?”
第二步:区分“事实”和“解释”
这是我觉得最有价值的一步。
例如:
“没人喜欢我的内容。”
这到底是事实,还是判断?
事实可能是:
发布了10篇文章,平均阅读量低于预期,没有获得预期的咨询。
“没人喜欢”其实已经是一个解释。
再比如:
“我不适合做副业。”
也不是事实。
事实可能是:
连续尝试三个月,没有形成稳定收入。
再比如:
“我的能力已经不值钱了。”
依然是解释。
事实可能是:
原来负责的某类工作需求减少,部分工作已经可以被AI辅助完成。
这两者差别非常大。
因为:
事实可以分析。
而一个笼统的自我判断,通常只能让你难受。
第三步:建立事故时间线
很多失败之所以让人痛苦,是因为我们只记得最后那个结果。
“失败了。”
但真正重要的信息,可能隐藏在过程里面。
所以我现在会尝试建立一个简单时间线:
T0
产生想法
T1
开始行动
T2
第一次获得反馈
T3
发现异常
T4
继续投入
T5
问题扩大
T6
最终停止
T7
复盘
然后问:
第一个可以被改变的节点在哪里?
这个问题非常重要。
因为真正有价值的复盘,不是找到:
“最后为什么失败?”
而是找到:
“如果让我重新来一次,我最早应该在哪个地方做出不同选择?”
很多失败,其实不是最后一步失败
比如一个项目最后失败了。
表面上看:
“产品没人用。”
但继续往前看:
可能是:
用户问题判断错了。
用户问题判断对了,但目标用户错了。
目标用户对了,但验证太晚。
验证太晚以后,又投入了大量开发成本。
最后才发现:
根本没人需要。
所以真正的问题可能不是:
“产品做得不好。”
而是:
在没有验证需求之前,就投入了大量资源。
这就是事故复盘的价值:
把结果往前追。
第四步:区分直接原因和根本原因
技术事故里经常有一个陷阱。
服务器挂了。
然后发现:
数据库连接池满了。
于是结论:
“数据库连接池配置不合理。”
问题解决了吗?
不一定。
继续往下追:
为什么连接池会满?
因为某个接口响应时间突然增加。
为什么响应时间增加?
因为一个查询没有走索引。
为什么没有走索引?
因为数据量增长以后,原来的设计没有重新评估。
这时候才开始接近:
根因。
人生失败也是一样。
比如:
“我这次面试失败了。”
直接原因:
面试表现不好。
再往下:
为什么表现不好?
准备不足。
为什么准备不足?
没有提前了解岗位。
为什么没有了解?
因为默认认为自己经验够。
再往下:
为什么会有这种默认?
因为过去很长时间里,我习惯用经验解决问题。
于是真正值得修复的可能不是:
“这次面试准备少了。”
而是:
“我对自己的经验产生了过高的确定性。”
这就是根因和表象的区别。
第五步:不要急着寻找“谁的错”
事故复盘最容易变成:
甩锅大会。
人生复盘也一样。
“都是环境不好。”
“都是别人影响的。”
“都是公司不给机会。”
“都是运气不好。”
或者反过来:
“全都是我的问题。”
这两种极端其实都不利于复盘。
因为真正需要问的是:
哪些因素我可以控制?哪些因素我不能控制?
可以拆成三个区域:
我能控制
↓
我能影响
↓
我无法控制
例如:
市场变化:
可能无法控制。
行业环境:
只能部分影响。
自己的选择:
可以控制。
自己的准备:
可以控制。
投入多少资源:
可以控制。
什么时候停止:
可以控制。
什么时候调整方向:
可以控制。
这样一拆:
自责会逐渐变成责任。
这是一个非常重要的变化。
自责和责任,其实不是一回事
自责说:
“都是我不好。”
责任说:
“这里有一部分是我可以改进的。”
自责攻击的是:
自己。
责任关注的是:
行为。
自责希望:
惩罚过去的自己。
责任希望:
改善未来的系统。
所以我越来越觉得:
真正成熟的复盘不是:
“我要狠狠记住这次教训。”
而是:
“我要让系统发生一次真实的变化。”
第六步:给失败做“损失评估”
事故复盘里必须看影响范围。
人生也一样。
有时候我们会因为一个小失败,产生巨大的心理损失。
比如:
一次面试失败。
就觉得职业生涯完了。
一篇文章没人看。
就觉得自己不适合写作。
一个项目失败。
就觉得自己没有创业能力。
但如果真正做一次损失评估:
实际损失:
时间:20小时
金钱:500元
机会成本:一些
经验:增加
认知:增加
能力:增加
你会发现:
事情可能没有想象中那么严重。
当然,也有一些失败的损失确实很大。
这时候更应该认真分析。
但:
损失大小应该由事实决定,而不是由情绪决定。
第七步:把失败转化成“系统补丁”
复盘做到这里,还没有结束。
因为:
知道原因 ≠ 问题被解决。
真正重要的是:
下一次怎么办?
比如:
这次项目失败,因为没有提前验证需求。
那么补丁可能是:
以后任何新项目
↓
先找3~5个真实用户
↓
确认问题是否真实存在
↓
再投入开发资源
这就不是一句:
“以后注意。”
而是一条:
新的系统规则。
再比如:
这次因为准备不足错过机会。
补丁:
重要机会出现
↓
建立机会Checklist
↓
至少提前48小时准备
↓
完成模拟
↓
再进入正式场景
再比如:
这次因为高估自己导致判断失误。
补丁:
重大决策
↓
写出自己的假设
↓
寻找反例
↓
找一个外部反馈
↓
再执行
这才叫:
从失败中提取系统升级。
最好的复盘,不应该只有“改进项”
还有一个东西经常被忽略:
保留项。
因为一次失败不意味着所有东西都错了。
比如:
方向可能错了。
但执行方式可能是对的。
结果可能不好。
但某个能力已经得到验证。
项目没有成功。
但获得了一批真实用户反馈。
一次机会没有拿到。
但发现了自己的能力缺口。
所以复盘应该同时问:
什么应该删除?
什么应该修改?
什么应该保留?
什么应该加强?
而不是:
“以后我什么都不要做了。”
失败之后最危险的行为:停止部署
这是我后来特别警惕的事情。
一次失败以后:
“算了。”
“以后不搞了。”
“我还是老老实实工作吧。”
“我不适合。”
然后整个系统进入:
FAILED
↓
ROLLBACK
↓
STOP
问题是:
Rollback是恢复,不是永久停止。
真正成熟的系统应该是:
FAILED
↓
ROLLBACK
↓
ANALYZE
↓
PATCH
↓
REDEPLOY
失败以后恢复。
分析。
修改。
再部署。
这才是迭代。
我现在特别喜欢一句话
失败是数据,不是判决。
这句话对我来说非常重要。
因为一旦把失败当成数据,你就会开始问:
数据是什么?
样本多大?
有没有偏差?
哪一个变量出了问题?
哪个假设被证伪?
哪个假设还没有验证?
下一次应该测试什么?
但如果把失败当成判决:
“我不行。”
那整个分析过程就结束了。
当然,也不能把所有失败都“正向解释”
这里我也越来越警惕一种东西:
失败美化。
不是每一次失败都值得继续。
不是所有失败都是成长。
不是坚持就一定有意义。
有些失败是在告诉你:
这个方向可能不成立。
有些失败是在告诉你:
这个成本太高。
有些失败是在告诉你:
你需要换一种方式。
有些失败甚至是在告诉你:
应该停止。
所以复盘的目的不是:
“怎么证明这次失败其实很好?”
而是:
“这次失败到底告诉了我什么?”
然后根据证据决定:
CONTINUE
继续
PIVOT
转向
PAUSE
暂停
STOP
停止
这四种结果都可以是有效的复盘结论。
给自己建立一份“人生事故报告”
如果以后再遇到一件让我很难受的失败,我希望自己能够先写这样一份东西:
【事故名称】
发生了什么?
【影响范围】
损失了什么?
【预期】
原本希望发生什么?
【实际】
实际发生了什么?
【时间线】
问题从哪里开始?
【直接原因】
表面发生了什么?
【根本原因】
为什么会发生?
【可控因素】
哪些是我能改变的?
【不可控因素】
哪些不是我的责任?
【保留项】
什么其实没有问题?
【修复项】
下一次需要改变什么?
【预防措施】
以后如何避免重复?
【下一次实验】
下一步准备做什么?
【结论】
继续 / 转向 / 暂停 / 停止
我觉得这张表最大的价值不是:
帮我把失败分析得多专业。
而是:
把情绪和事实分开。
写给未来自己的代码注释
// 发生故障,不要先责怪系统
// 先保存现场
incident = capture();
facts = collect(incident);
timeline = reconstruct(facts);
rootCause = analyze(timeline);
impact = evaluate(incident);
controllable = classify(rootCause);
patch = design(controllable);
if (patch.isValid()) {
deploy(patch);
}
// 不要把一次失败
// 转换成自己的身份
failure != identity;
// 失败应该产生新的信息
// 信息应该产生新的规则
// 新规则应该改变下一次行为
failure
→ data
→ insight
→ patch
→ iteration;
写在最后
以前失败的时候,我最想做的事情是:
忘掉它。
现在我越来越觉得:
真正应该忘掉的,是那些反复攻击自己的话。
而真正应该留下的,是:
事故现场。
发生了什么。
为什么发生。
哪里判断错了。
哪里做得不够。
哪些因素不是自己能控制的。
哪些地方需要改变。
下一次怎么做。
这些东西才是真正属于自己的经验。
因为一个人真正的成长,可能不是:
从此以后再也不失败。
而是:
每失败一次,都能让系统升级一点。
如果第一次失败之后,我只是觉得:
“我不行。”
那这次失败只产生了痛苦。
如果我能够继续往下追:
“我为什么失败?”
“我的哪个假设错了?”
“我的哪个能力存在缺口?”
“我的哪个流程需要修改?”
“下一次我准备怎么验证?”
那么这次失败就开始产生:
数据。
数据经过分析,变成认知。
认知经过行动,变成新的能力。
新的能力再进入下一次实践。
这才是真正的:
失败 → 复盘 → 重构 → 迭代。
40岁以后,我越来越觉得:
我们没有办法保证自己以后不犯错。
也没有办法保证每一次选择都正确。
真正能够建立的,是另外一种能力:
出错以后,能够快速恢复;失败以后,能够认真复盘;发现问题以后,能够修改自己的系统。
所以以后再遇到失败,我希望自己少问一句:
“我怎么这么差?”
多问一句:
“这次事故,究竟暴露了我的哪个系统问题?”
然后把它写下来。
不是为了惩罚过去的自己。
而是为了:
让未来的自己少踩一次同样的坑。
我是语霖。
执笔为语,心落成霖。
记录一个40岁程序员重新设计人生系统的过程。
我越来越相信:
人生真正的稳定,不是永远不出Bug。
而是:
每一次Bug发生以后,我们都有能力把它变成下一版系统的代码。