跳到主要内容
阅微漫记
返回

人生 Debug:如何在不确定的环境里,做「防御性编程」

不要假设世界永远按照你的计划运行

以前写代码的时候,我有一个习惯。

刚开始工作的时候,写一个功能,总是假设:

用户会按照设计操作。

参数一定正确。

接口一定正常。

数据一定存在。

网络一定稳定。

依赖服务一定可用。

所以代码经常是:

user.getName();

直接调用。

因为我默认:

user 一定存在。

name 一定存在。

数据一定完整。

但是随着经验增加,我慢慢发现:

真正线上稳定运行的系统,很少建立在“理想情况”之上。

成熟工程师写代码时,会提前考虑:

如果用户传了空值怎么办?

如果接口超时怎么办?

如果数据库没有数据怎么办?

如果第三方服务挂了怎么办?

如果有人恶意输入怎么办?

于是代码开始变成:

if(user != null){
    return user.getName();
}else{
    return defaultName;
}

这就是:

防御性编程。

它不是因为程序员悲观。

而是因为:

现实世界一定会出现异常。

后来我发现:

人生其实也是一样。


一、过去的我,总是假设人生运行在“理想环境”

年轻的时候,我们很容易这样设计人生:

毕业
 ↓
找到稳定工作
 ↓
不断成长
 ↓
升职加薪
 ↓
收入增加
 ↓
生活越来越好

这套路径没有错。

但它隐藏了一个假设:

世界会持续稳定。

可是现实不是这样。

行业会变化。

技术会变化。

公司战略会变化。

组织结构会变化。

身体状态会变化。

家庭阶段会变化。

甚至你自己,也会变化。

以前喜欢的东西,可能后来不喜欢。

以前擅长的能力,可能后来价值下降。

以前认为重要的目标,可能后来发现不是自己真正想要的。

所以很多时候,人生遇到的问题不是:

“我不够努力。”

而是:

我的人生系统,没有考虑异常情况。


二、没有防御机制的人生,容易出现单点故障

在软件系统里面,一个非常危险的问题叫:

Single Point of Failure(单点故障)。

意思是:

整个系统依赖一个节点。

这个节点一旦失败,整个系统瘫痪。

比如:

一个数据库。

一台服务器。

一个核心服务。

如果没有备用方案:

它就是系统最大的风险。

人生里也有大量类似问题。

比如:

收入单点故障

收入
 ↓
唯一工资来源
 ↓
公司
 ↓
岗位

如果这个节点出现变化:

整个系统受到影响。


能力单点故障

职业价值
 ↓
某项技术
 ↓
某个平台

如果技术环境变化:

能力价值下降。


价值感单点故障

自我认可
 ↓
工作评价
 ↓
领导反馈

如果工作环境变化:

容易产生巨大心理波动。


社交单点故障

人际关系
 ↓
公司同事

离开组织以后:

连接突然减少。


很多时候,人真正焦虑的原因不是变化本身。

而是:

系统没有备用路径。


三、防御性编程的第一原则:不要相信输入

程序员都知道:

外部输入永远不可信。

用户输入。

网络请求。

第三方接口。

文件内容。

都需要验证。

为什么?

因为你无法控制外部环境。

人生也是一样。

很多痛苦来自于:

把外部世界当成确定条件。

比如:

“公司会一直需要我的能力。”

这是一个未经验证的输入。

“我的行业十年后还会这样。”

这是一个未经验证的输入。

“现在的收入水平会一直保持。”

这是一个未经验证的输入。

“孩子未来一定按照我的规划成长。”

也是一个未经验证的输入。

不是说这些一定会错。

而是:

它们不应该被当成系统基础假设。

更成熟的方式是:

给这些输入增加验证机制。


四、给人生增加“参数校验”

代码里面:

收到输入

↓

检查是否合法

↓

通过

↓

执行逻辑

人生也一样。

比如:

有人告诉你:

“这个行业已经没有机会了。”

以前可能直接焦虑。

现在可以增加一个验证流程:

信息来源?
↓

数据是什么?
↓

时间范围?
↓

适用于什么场景?
↓

和我的情况有什么关系?

再比如:

有人告诉你:

“40岁以后程序员没有价值。”

这个输入需要校验。

问题不是:

相信或者不相信。

而是:

拆开来看。

哪些岗位受到影响?

哪些能力仍然有价值?

哪些能力需要升级?

哪些路径需要调整?

这就是:

人生参数校验。


五、防御性编程不是害怕失败,而是降低失败成本

很多人听到“防御”,容易想到:

保守。

不冒险。

不要尝试。

但工程里的防御性设计,并不是这样。

好的系统不是:

永远不出错。

而是:

出了错,也不会造成灾难。

比如:

银行系统。

它不是假设:

“用户永远不会输错密码。”

而是设计:

密码错误怎么办?

账户锁定怎么办?

异常登录怎么办?

风险交易怎么办?

它接受:

错误一定存在。

然后设计:

错误发生后的影响范围。

人生也是一样。

真正的问题不是:

“我要不要尝试?”

而是:

“如果尝试失败,我有没有恢复能力?”


六、给人生设计“降级方案”

软件系统经常有:

Fallback。

备用方案。

当主路径失败:

切换备用路径。

比如:

支付系统。

如果微信支付不可用。

可能切支付宝。

如果支付宝不可用。

可能使用银行卡。

系统不会因为一个服务异常就停止。

人生也应该如此。

例如:

职业系统

主路径:

当前工作

备用路径:

行业能力
+
个人品牌
+
人脉网络
+
副项目

财务系统

主路径:

工资收入

备用路径:

储蓄
+
投资
+
额外收入
+
技能变现

能力系统

主路径:

当前技术能力

备用路径:

业务理解
+
系统设计
+
沟通能力
+
内容输出
+
AI工具能力

防御性设计的核心:

不是准备逃跑。

而是:

让自己拥有更多选择。


七、不要把所有资源投入同一个方向

这是投资里面常说的:

不要把所有鸡蛋放在一个篮子里。

软件架构里叫:

避免高度耦合。

人生也是。

很多人年轻时没有问题。

因为单一路径增长很快。

但是到了某个阶段:

风险开始集中。

比如:

所有时间投入工作。

所有学习围绕岗位。

所有关系来自公司。

所有收入来自工资。

所有身份来自职业。

这个系统效率很高。

但是:

抗风险能力很低。

因为:

任何一个变化,都可能影响全部。

所以我越来越重视:

资源隔离。


八、给自己建立几个“隔离层”

软件系统里,会通过隔离减少故障传播。

人生也需要。

我现在越来越倾向于建立几个隔离层:


第一层:现金流隔离

目标:

不要让一次职业变化影响基本生活。

例如:

建立安全储备。

降低固定支出。

增加收入来源。


第二层:能力隔离

目标:

不要让一个技术方向决定全部价值。

例如:

从:

“会某个技术的人”

升级到:

“能够解决复杂问题的人”。


第三层:身份隔离

目标:

不要把全部自我价值绑定一个角色。

不是:

“我是一个程序员,所以……”

而是:

“我是一个持续学习、创造价值的人。”

程序员只是当前版本。


第四层:情绪隔离

目标:

不要让一个事件影响整个系统。

比如:

工作受挫。

不要自动推导:

人生失败。

这是典型的:

异常传播。


九、给重大决策增加“异常处理”

代码里:

关键流程都会有:

try-catch。

不是因为期待错误。

而是:

提前定义错误处理方式。

人生重大选择也一样。

比如:

换工作。

创业。

转型。

搬家。

投资。

都可以问:

如果结果不好怎么办?

如果收入下降怎么办?

如果方向错误怎么办?

如果半年没有结果怎么办?

如果重新开始怎么办?

很多人不愿意问这些问题。

因为感觉像是在给自己泼冷水。

但实际上:

这是在提高系统稳定性。


十、防御性编程的最高境界:允许变化

以前我以为:

稳定意味着:

不要变化。

后来发现:

真正稳定的系统,恰恰允许变化。

比如:

互联网系统。

每天都有新请求。

新的用户。

新的数据。

新的问题。

但是系统依然稳定。

为什么?

因为它具备:

弹性。

扩展能力。

容错能力。

恢复能力。

人生也是。

真正的稳定不是:

我的工作永远不会变化。

我的收入永远不会下降。

我的计划永远不会调整。

真正的稳定是:

即使变化发生,

我依然能够重新组织资源。


十一、我开始给自己写“人生异常处理规则”

以前遇到问题,我靠临场反应。

现在我希望提前设计一些规则。

比如:

异常:
工作环境发生重大变化

处理:

1. 不立即恐慌
2. 收集真实信息
3. 评估影响范围
4. 检查备用方案
5. 再决定行动

比如:

异常:
长期没有成长感

处理:

1. 检查能力结构
2. 判断行业变化
3. 增加新能力输入
4. 创建小规模实验

比如:

异常:
情绪持续低落

处理:

1. 降低当前负载
2. 检查睡眠和身体
3. 减少刺激输入
4. 寻找支持
5. 必要时寻求专业帮助

这些规则的意义:

不是让人生变得机械。

而是:

减少自己在异常状态下做错误决策。


十二、人生不是写一次代码,而是长期维护系统

工作几年以后,我越来越理解:

真正复杂的软件系统,不是开发完成那一天。

而是上线以后。

因为:

用户会变化。

需求会变化。

环境会变化。

依赖会变化。

所以系统需要:

持续维护。

持续优化。

持续重构。

人生也是。

20岁的时候写了一版。

30岁的时候升级了一版。

40岁的时候发现:

很多代码需要重构。

一些模块需要删除。

一些能力需要重新设计。

一些架构需要调整。

这不是失败。

这是:

正常迭代。


写给未来自己的代码注释

// 不要假设世界永远稳定
// 外部输入永远需要验证

input = receive();

if (!validate(input)) {
    handleException();
}

// 不要让单点故障决定人生

if (dependency.count == 1) {
    addBackup();
}

// 不要追求没有失败
// 而是降低失败影响

try {
    experiment();
}
catch(Exception e) {
    recover();
    learn();
    iterate();
}

// 系统真正的稳定性
// 来自弹性,而不是静止

while(life.running){
    monitor();
    adjust();
    improve();
}

写在最后

以前我一直觉得:

人生最大的能力,是努力。

后来我发现:

努力当然重要。

但对于一个已经运行几十年的系统来说,

还有一种能力同样重要:

抗变化能力。

因为未来一定会出现:

没有预料到的问题。

没有计划中的变化。

没有准备好的挑战。

我们无法提前写完人生所有异常处理代码。

就像程序员无法预测所有线上问题。

但是我们可以做一件事情:

让自己的系统拥有更好的容错能力。

拥有多个收入来源。

拥有可以迁移的能力。

拥有持续学习的能力。

拥有健康的身体。

拥有稳定的关系。

拥有面对变化时重新调整的能力。

这些东西,就是人生里的:

防御性编程。

它不是让你活得更谨慎。

而是让你拥有更多选择。

因为真正强大的系统,

不是永远不会出错。

而是:

即使错误发生,也不会轻易崩溃。

我是语霖。

执笔为语,心落成霖。

希望用文字和声音,记录一个40岁程序员重新设计人生系统的过程。

我们下期接着聊。


分享这篇文章:

上一篇
人生 Debug:如何把一个模糊的人生目标,拆解成可执行的迭代版本
下一篇
如何给自己的人际网络做一次依赖关系梳理