Mysql

你的错误处理只是安慰剂

打开任何一个前端项目,全局搜索 `catch`,你会看到什么?一大片空荡荡的 catch 块,偶尔跳出几个 `console.error`,再偶尔冒出一行 `message.error('系统异常')`。后端项目也好不到哪去,try-catch 包着业务逻辑,catch 里面的处理方式跟前端如出一辙——记个日志,打个错误码,然后呢?然后什么都没有。

我把这种写法叫"安慰剂错误处理"。它的作用不是解决问题,而是让写代码的人觉得自己处理了问题。就好像感冒的时候吃维C,你做了点什么,但那点什么跟治愈没有关系。

更残酷的事实是:大部分错误处理非但没用,还在制造新的问题。

 

try-catch 不是错误处理,是错误藏匿

 

先说一个很多人不愿意承认的事:try-catch 是所有错误处理手段里最廉价的那一种。它的成本最低,所以它的价值也最低。

我见过太多这种代码:一个函数内部包了三层 try-catch,每一层都把异常吞掉,最外层返回一个 `{ success: false, message: '操作失败' }`。调用方拿到这个返回值,判断 `success` 为 false,然后弹个 toast —— "操作失败"。用户看到这四个字,内心毫无波澜,因为他已经见过一千次了。

复盘救不了你的团队

博客分类: 

又一起线上事故。凌晨三点的告警,值班同学爬起来处理,应急响应、回滚、止血,一气呵成。第二天上午,事故复盘会准时召开。PPT做得很漂亮,时间线梳理得清清楚楚,根因分析写得明明白白,action items列了七八条。所有人都认真地点了点头,表示"以后一定注意"。

三个月后,同一个系统,同一类事故,再次发生。

这个场景太熟悉了。每个经历过线上事故的技术人,大概都对这种循环不陌生。复盘会开了一轮又一轮,文档写了一篇又一篇,"改进措施"列了一条又一条,但该来的事故还是会来,该踩的坑还是会踩。

问题到底出在哪?

 

复盘变成了一场仪式

 

大部分复盘会的真实目的,早就不是"从错误中学习"了。它承担的职能更接近一种组织仪式——事故发生了,总得有个交代。复盘会就是一种交代:你看,我们重视了,我们分析了,我们有改进计划了。

这种仪式感会带来一个隐蔽的副作用:它让所有人都觉得事情正在被处理。管理者觉得团队在反思,团队觉得管理者在推动改进,大家心里都松了一口气。但"感觉在改进"和"真实在改进"之间,隔着一道巨大的鸿沟。

"能者多劳"是技术团队最隐蔽的陷阱

团队里总有那么一两个人,什么活都能干,什么锅都能扛。需求来了找他,线上出问题找他,新技术调研找他,代码评审也想拉他。他的日历永远排得最满,他的PR永远是别人等Review最久的那个。

大家都觉得这是"能力强、受重视"的体现。管理者也觉得,把重要的活交给靠谱的人理所当然——毕竟谁能放心把核心模块交给新人?

但我要说一个可能得罪人的判断:"能者多劳"不是在重用人才,是在消耗人才。而且这种消耗有一个特别迷惑人的地方——它看起来像是信任,感觉起来像是被需要,唯独结果不是被成全。

 

看起来是信任,实际上是惩罚

 

考虑一个很常见的场景。

项目要赶排期,核心功能必须本周上线。你会交给谁?当然是那个靠谱的资深工程师,因为交给别人你不放心,延期了你担不起。

线上出了Bug,排查要理解完整链路。你会交给谁?还是那个人,因为只有他能从数据库一路追到前端渲染。

新人入职需要导师,你会选谁?又是他,因为他技术好、有耐心、能讲清楚。

看起来这个人得到了最大的信任,承担了最重要的工作。但仔细想想,他得到了什么?更多的工作。更满的日历。更少的写代码时间。更晚的下班时间。而那些干得一般的人呢?他们的工作量反而更少,因为没人找他们。

前端性能优化的尽头是架构问题

每次聊性能优化,话题总是很快滑向具体的技术手段:懒加载、代码分割、图片压缩、Tree Shaking、虚拟列表……这些当然有用,但我想说一个可能让不少人不太舒服的判断——当你在做这些"优化"的时候,大概率已经晚了。 真正决定性能天花板的,不是你用了多少优化手段,而是系统架构在最初就给你画了多高的天花板。

性能问题从来不是前端单方面的问题。但很多团队把它当成了前端的问题,于是前端工程师就像一个装修工人,在毛坯房里拼命贴墙纸——墙纸再好看,承重墙没打好,房子一样不牢。

 

优化手段的天花板

 

先承认一个事实:常规的性能优化手段确实能解决一部分问题。一个从没做过任何优化的项目,加上代码分割和懒加载,首屏时间砍一半不稀奇。图片做个WebP转换、加个CDN,LCP直接降几百毫秒。这些是低垂的果实,摘了就是摘了,没人否认。

但问题是,这些优化有上限。你的首屏要从3秒优化到1.5秒,代码分割和懒加载就够了。但如果你要从1.5秒到800毫秒,甚至到500毫秒以内,单靠前端手段就力不从心了。因为剩余的耗时大头不在前端——它在网络请求、在服务端处理、在数据组装、在协议开销。

产品经理说的和工程师听到的为什么总是两回事

有个场景在金融科技公司几乎每周都会上演:产品经理说"这个需求很简单,就是加个按钮",工程师听到的是"又要改架构"。

会议室里的氛围瞬间凝固。产品经理觉得技术团队在找借口,工程师觉得业务方根本不懂技术。双方都没说错,但都没说对。

这不是沟通技巧的问题,是认知框架的断层。

 

信息在组织边界丢失

 

我观察过一个现象:同一个需求,产品经理在需求评审会上讲五分钟,工程师回去讨论要两小时。

不是工程师理解力差,是信息在跨部门传递时发生了质变。

产品经理说"支持用户自定义理财目标",他脑子里是一个完整的业务场景:用户设定目标金额和期限,系统推荐合适产品,定期提醒达成进度。这个场景在产品原型里是完整的,在用户故事里是清晰的。

但工程师听到的是什么?

前端听到的是:新增表单、字段校验、状态管理、埋点上报。后端听到的是:数据库表设计、接口规范、权限校验、数据迁移。全栈工程师听到的更复杂:前后端联调、缓存策略、异常处理、监控告警。

同样五个字,解析出来的工作量相差十倍。

这就是组织边界的代价。产品经理思考的是"用户价值",工程师思考的是"技术实现"。两者的抽象层级不在同一个维度,信息当然会失真。

依赖管理的迷局:为什么升级依赖总是危险的

每次看到 Dependabot 或 Renovate 提的 PR,我的第一反应不是"好,及时更新",而是"又来了,这次会炸在哪"。

这不是危言耸听。见过太多次:一个看似无害的小版本更新,导致生产环境莫名其妙地挂掉;一个"修复安全漏洞"的补丁,带来了更严重的 breaking change;一个"只是升级 devDependencies"的操作,让 CI 流水线跑不起来。

行业里有个有意思的现象:所有人都在说"依赖要及时更新",但实际操作中,大家都在拖延。不是因为懒,是因为怕。

这种恐惧是有道理的。

 

语义化版本的美丽谎言

 

Semantic Versioning(语义化版本)告诉我们:`major.minor.patch`三段式版本号清晰明了,patch 是 bug 修复,minor 是功能新增,major 才是破坏性变更。所以升级 patch 和 minor 是安全的,对吧?

对个屁。

去年金融业务的一次故障,就是因为某个依赖的 minor 版本更新。库的作者认为他只是"优化了内部实现",所以只升了 minor。但这个优化改变了某些边界情况下的行为,恰好触发了我们业务代码里一个隐式依赖的逻辑。

微服务不是银弹:大部分团队高估了自己的复杂度

博客分类: 

 

写在前面

 

前几天和一个创业公司的 CTO 聊天,他说他们团队 5 个后端开发,已经拆了 12 个微服务。我问他为什么要拆,他说"为了未来的扩展性"。然后我问他现在的 DAU 是多少,他说"几千"。

这让我想起很多年前见过的一个场景:一个刚起步的业务,还在验证商业模式,技术团队已经开始讨论服务网格和分布式追踪了。最后业务没做起来,技术架构倒是挺先进的。

微服务这几年被捧得太高了。很多团队在根本不需要的时候就开始拆服务,结果把自己搞得焦头烂额。今天想聊聊这个话题,不是说微服务不好,而是大部分团队真的不需要它,至少不是现在。

 

微服务的真实成本

 

 

开发成本的指数级增长

 

很多人以为微服务只是把代码拆开而已。实际上,从单体到微服务,你需要解决的问题是指数级增长的:

服务间通信:HTTP 调用、gRPC、消息队列,你得选一个。然后你会发现,本来一个本地函数调用,现在变成了网络请求。网络不可靠,你得处理超时、重试、熔断。原本简单的代码,现在要考虑各种边界情况。

BFF层的谎言:为什么大部分团队不需要它

最近在和几个技术管理者交流时,发现他们都在规划或已经落地了BFF(Backend for Frontend)架构。问为什么要做BFF,得到的答案惊人地一致:"解耦前后端"、"提升开发效率"、"这是最佳实践"。

但当我问:"你们团队有多少后端开发?前端开发呢?",答案通常是"后端6-8人,前端3-4人"。这让我意识到一个问题:大部分团队上BFF,可能不是因为真的需要,而是因为"别人都在用"。

我想聊聊这个话题,不是要否定BFF的价值,而是想说:很多团队高估了BFF的收益,低估了它的成本

 

BFF真正解决的问题

 

先说清楚,BFF不是伪需求。它在特定场景下确实有价值:

场景一:多端适配。你的后端API是为Web设计的,现在要支持移动端、小程序、IoT设备。不同端的数据需求、交互逻辑差异很大,用一套API很难搞定。这时候BFF可以为每个端定制API,后端保持稳定。

场景二:聚合调用。前端一个页面需要调用5-6个后端服务,串行调用太慢,并行调用又要处理复杂的依赖关系。BFF可以在服务端聚合这些调用,减少前端的复杂度和网络开销。

全栈工程师的最大误区:追求全能

最近看到一个问题:"全栈工程师是不是什么都要会?"下面的回答分成了两派,一派说全栈就是要前端后端数据库运维都精通,另一派说全栈是个伪概念,啥都会等于啥都不精。

两边都有道理,但我觉得都错了重点。

做了很多年全栈,从后端写到前端,再到带团队做架构,我的观察是:大部分人误解了全栈工程师的核心价值。全栈不是让你成为技术全才,而是给你一个完整的视角去理解系统、做决策、解决问题。

追求全能是个陷阱,追求全局观才是正道。

 

全能是个伪命题

 

先说个真实场景。

在金融业务中,经常会遇到性能问题。前端说页面慢是因为接口慢,后端说接口慢是因为前端请求太多,DBA说数据库压力大是因为查询写得烂,运维说服务器资源不够要扩容。

这时候如果你是个"全能型"全栈,你会怎么做?去优化前端的渲染逻辑、重写后端的查询语句、调整数据库索引、然后去研究服务器配置?

听起来很厉害,但实际上这是在用战术上的勤奋掩盖战略上的懒惰。

真正的问题可能是:这个需求本身就不合理,或者整个架构设计有问题。

代码审查的真相:大多数CR流程都在浪费时间

前几天团队来了个新人,看到我们的CR流程后很兴奋:"你们的Code Review好规范啊,每个PR都要两个Approver才能合并。"我笑了笑没说话。

因为我知道,这套看起来"规范"的流程,实际上每天都在发生这样的事情:开发者提交一个几百行的PR,半天没人review;着急上线就去钉钉群里@几个人;被@的人打开看一眼,觉得代码没大问题就点了Approve;测试环境跑了一遍没报错,代码就合并了。

整个过程看起来很严谨,实际上谁也不知道这段代码到底干了什么。

 

大多数CR都是形式主义

 

我见过太多团队把Code Review当成一种"仪式感"——必须要有这个环节,但没人在乎它到底有没有效果。

最常见的场景是:PR提交后,reviewer们象征性地打开看一眼,扫过去没发现明显的bug或者格式问题,就点了Approve。至于这段代码的设计是否合理、是否有更好的实现方式、是否会给系统带来潜在风险,没人去深究。

为什么会这样?因为review代码比写代码累。

页面