写给2025年的我:在保持真我与适应社会之间找到平衡点

在这个复杂多变的世界里,每个人都以自己独特的方式存在着,而我,则被周围人贴上了“憨”、“固执”这样的标签。面对这些评价时,我的内心经历了从最初的困惑不解到后来逐渐接受的过程。起初,我试图去改变自己,让自己看起来更加圆滑、世故,但很快我发现,这样的尝试不仅让我感到疲惫不堪,更重要的是,它违背了我的本心——那个渴望真实表达自我的灵魂。

点头不是共识:需求评审为什么总是事后翻车

博客分类: 

每个做过需求评审的人大概都经历过这个场景——产品经理对着投影仪把PRD过了一遍,问了句"大家有什么问题吗?",沉默,没人说话。"好,那就这样。"散会。

然后写代码写到一半,问题冒出来了。前端说这个交互跟另外一个模块冲突,后端说这个数据结构改不动,测试说这个场景根本没法验证。所有人突然都有意见了,但不是在评审会上。

这不是个例。在金融业务这种需求复杂度高的场景里,我见过太多次"全员通过"的需求评审最终落地时面目全非。问题不在某个角色,不在某个人,问题出在需求评审这个仪式本身——它制造的共识感是假的。

 

全员点头到底说明了什么

 

先搞清楚一件事:评审会上大家为什么都在点头。

最表层的原因——大部分人根本没消化。产品经理30分钟讲完40页PRD,信息密度像子弹,你能记住的只有自己那块冰山一角。但没人举手说"我没听懂"。这跟技术评审会上没人敢说"这个架构我没看明白"是同一种心理。沉默被解读为同意,点头被当成认可。会议室比你想的更像剧场,每个人都在演"我在认真听"。

从Redux到Signal,状态管理为什么换了三代还是不满意

前端开发有一个有趣的规律:每隔两三年,社区就会宣布一个新的状态管理"最佳实践"。Redux曾是不可撼动的标准,然后MobX说响应式才是正道,Dva试图让Redux更人性化,Zustand说状态管理不该这么啰嗦,Jotai说应该是原子化的,现在Signal又告诉你要从原语层面重新思考这个问题。每一次更迭都伴随着"旧方案已死"的宣言,和一波迁移重构。

但有一个问题始终没人回答:如果每个新方案都比上一个好,为什么我们还是不满意?

经历过Redux到Dva再到Zustand的完整迁移,我发现每一次换库的时候,团队都觉得这次终于对了。每一次,半年后又会发现新的别扭。这种循环让人不得不怀疑——问题可能根本不在库里。

 

Redux的铁律和代价

 

Redux的核心思想并不复杂:单一数据源,纯函数更新,不可变数据。这三条铁律在2016年前后确实解决了一个真实痛点——复杂应用中状态变化的不可预测性。组件树里的状态到处飞,回调层层传递,谁能改、谁不能改、改了之后谁是新的,没人说得清。Redux用一套严格的规则堵住了这个口子。

你招的不是最优秀的人,是最像你的人

博客分类: 

每个技术团队都有个共同的幻觉:我们在招最优秀的人。

JD写的是"追求卓越",面试聊的是"技术深度",评级用的是"超出预期"。所有的信号都在告诉你,你们在建立一个精英团队。但你有没有认真看过你团队里的人——他们解决问题的思路是不是惊人地相似?他们认同的技术方案是不是高度一致?他们对"好代码"的定义是不是几乎一模一样?

这不是因为相似的人恰好都最优秀。这是因为你在招聘的第一步,就已经把"和我像"编码成了"优秀"。

 

你以为的标准,其实是你的倒影

 

技术面试有一个很少被质疑的前提:面试官能够客观地判断候选人的技术能力。但事实是,大部分技术面试的"客观标准",不过是面试官自身经验的主观投射。

举个很常见的场景:两个候选人,能力相当,但一个和你用了同样的技术栈、同样的架构思路,另一个用了不同的方案解决了同样的问题。你觉得谁更强?大概率你会觉得前者"更扎实"、"理解更深",后者"还行但细节不够"、"方向有点偏"。这不是你在有意偏袒——是你的大脑在用"熟悉度"作为"质量"的代理指标。

向后兼容的谎言:版本号救不了你的接口

每个设计接口的人都对自己说过同样的话——"加个字段就行了,老的调用方不受影响。"

三个月后,你发现老调用方也在读新字段,但逻辑完全不是你预期的。半年后,当初保证"兼容"的那个人转岗了。一年后,没人动得了任何一个字段,接口文档变成了考古现场——一半字段没人用,另一半的含义靠口头传承。你在注释里看到 `// 这个字段别删,XX团队在用`,去找XX团队,他们说早就不用了,但不敢确认,要再查查。

这不是向后兼容,这是技术债在穿正装。

 

兼容性承诺是一种债务

 

接口设计里最危险的一句话不是"我们重构吧",而是"我们保证向后兼容"。前者好歹意味着你在正视问题,后者意味着你在透支未来。

向后兼容不是免费的。每多兼容一个旧版本,你就多了一条隐形的约束链。这条链不会出现在代码评审里,不会出现在架构文档里,但会在每一次你需要修改字段含义、调整返回结构的时候跳出来,像一个极其礼貌的绑匪——"您不能动这个,还有调用方在用。"

会议是技术团队最体面的避难所

博客分类: 

周一早上打开日历,发现这一周已经被各种颜色的色块填满了。晨会、周会、评审会、对齐会、架构讨论会、需求评审会……还没坐下来写一行代码,一天就过去了。剩下的时间再打开 Slack 回几条消息,真正专注的时间碎片化到不可能做任何需要深度思考的事情。

这不是某个人的问题,是整个技术团队的通病。几乎所有技术管理者都抱怨过"会议太多",但有意思的是,抱怨完之后,大多数人还是继续安排会议、接受会议,甚至主动拉会。这种言行矛盾本身就值得琢磨。

 

信息同步?别自欺了

 

会议最常用的理由是"信息同步"或者"对齐"。但仔细想想,你上一次在会议中真正获得关键信息是什么时候?绝大多数会议的信息流向是单向的:一个人讲,其他人听。这叫广播,不叫同步。

更常见的情况是,会议的前十分钟在等人,中间二十分钟在重复上周说过的话,最后十分钟草草收场。真正有信息量的部分,可能五分钟就能说完。但五分钟的会议不符合惯例,也显得不够重视。

我曾经观察过一个现象:技术团队里信息传递效率最高的时刻,往往不是在会议中,而是在工位上随口问一句、在 IM 里发一条消息、或者在 MR 的 comment 里写一段话。这些非正式的信息交换反而更精准、更及时,因为它们是在具体问题的上下文中发生的,不是为了开会而开会。

缓存的一致性幻觉:为什么缓存越多数据越不可信

每个做过高并发系统的人,大概都经历过这样的时刻:线上出了个数据不一致的bug,排查一圈发现是缓存没更新。修完之后加个主动失效,觉得踏实了。过几天又出现,这次是另一个缓存层级。再修。再过段时间,用户反馈看到的金额对不上——你一查,三个缓存层级,两个过期时间不一样,一个还挂着CDN缓存头。

这不是段子,这是每天都在生产环境里上演的日常。

团队解决性能问题的第一反应永远是加缓存。页面慢?加个Redis。接口慢?加个本地缓存。前端渲染慢?加个HTTP Cache-Control。数据库扛不住?加个查询缓存。每一层缓存都在解决一个真实的问题,但每一层缓存也在制造一个你暂时看不见的新问题——等到它浮现的时候,往往已经是你最不想看到的形态。

 

缓存是性能的银弹,也是一致性的地雷

 

这里有个反直觉的事实:缓存从不制造bug,它只是把bug从"现在就暴露"延迟到"不知道什么时候暴露"。

一个没有缓存的系统,数据读出来就是最新的,哪怕慢一点,至少不会错。但当你开始在链路上堆缓存,你事实上引入了一个隐含假设:旧数据在一段时间内是可以接受的。这个假设在大部分场景下成立,但"在大部分场景下成立"和"在你的场景下成立"是两回事。

1on1已死,只是通知还没到你

博客分类: 

每个技术管理者都有个执念:1on1。书上说1on1,培训教1on1,入职第一天HR就跟你说"你的1on1频率是每周一次"。于是你信了,每周往日历上塞一个30分钟的会议邀请,拎着笔记本走进小会议室,然后——聊了30分钟的进度。

你是不是觉得这也没什么?毕竟了解项目进展也挺重要的。但问题是,你有没有想过,这30分钟的进度同步,和你早会上问的那句"这个需求什么时候能提测",到底有什么本质区别?

1on1正在变成一场管理者自我感动的仪式。你去了,你聊了,你觉得自己在"关心人"。但如果你把过去半年1on1的聊天记录拉出来看一遍,大概率80%的内容是项目状态、deadline确认、阻塞项梳理。剩下20%是"最近压力大吗"——然后对方说"还好",你说"注意休息",对话结束。

这不是1on1,这是换了个场地的工作汇报。

 

它是怎么一步一步变成周报会的

 

没有人一开始就打算把1on1搞成这样。每个新晋管理者第一次和下属1on1的时候,都带着真诚来的——"我想了解你的想法"、"有什么困难尽管说"。但很快,现实就开始纠正你的浪漫。

你的错误处理只是安慰剂

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

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

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

 

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

 

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

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

页面