大家好,我是懒惰蜗牛。
在各种小中厂,辗转了也快10年了。
我带过新人,线上救过火,扛过无数个通宵,写需求基本不挑活儿。
大家对我的评价,用的词都是靠谱。工资不高不低,压力不大不小,有时候也有点自信,就算不是老大,也算是不可或缺的那一撮人。
直到去年,部门来了个22岁的应届生。
我负责带他。第一天我帮他搭环境,告诉他某个项目是那种典型的祖传代码 + 魔改框架 + 各种神秘脚本,按理说新人至少得踩三天坑。我心里其实已经准备好了,慢慢教,别急,他得适应我们这套历史产物。
结果那小子,自己搞定了大半。我刚准备教第二步,他回我一句,哥,这个地方我重跑过了,能起来,我先理下这个服务的调用链哈。
我当时想的是:嗯,聪明。会学。但也就这样了。真到线上出事,估计也是慌成狗。
我一直是这么想的。
直到几个月之后,一次线上事故,让我第一次认真地感到了恐惧,原来在老板眼里,我这种老员工,真的可以被替换掉。
一个普通得不能再普通的周四晚上,大家都快下班了。
我们的一个订单服务突然开始疯狂报警,CPU打满,接口延迟暴涨,线程池里的队列直接飙红。微信群里直接炸了锅。
说实话,这种场面我不知道见了多少次了。
我第一反应就是先重启,先稳住再说。
这个模块本身就有历史包袱,我之前也提过要重构,一直排不上优先级。撑过去就好。
翻译一下就是——老油条式处理:先灭火,回头再甩锅给历史代码,然后继续排期,然后就没有然后了。
但我之前提到的那个新人,真的干劲十足,看到这种场景,我估计他也是一股兴奋劲儿涌上心头。
走到我边上说,哥,能不能帮我dump下线程栈,我当时也没在意,因为其实我知道问题大概在哪里,不要影响我恢复服务就行,就帮他拉了dump日志,也不耽误事儿,还把各种日志信息也发给他了,想的是这哥跟当年的我真还差不多。
就喜欢刨根问题,就喜欢追溯问题的根源。
服务恢复大家也就安稳下班了,这种场景算是少见多怪了。
第二天来上班,那哥们找到我,说他大概知道问题在哪了。
他昨儿分析了线程栈日志,分析了内存占用信息,还在预生产环境模拟了一下他的设想。
大致就是问题不在于机器不给力,有个同步方法里用了一个过重的锁,所有请求都在那里互相等。
还有static的Map没有清理过期数据,等于是在放内存垃圾,长时间跑就涨上去了,最后直接把堆顶爆成高占用。
他试了下把锁拆小一点,Map加了个简单的清理逻辑,在预生产环境压测过,不影响原有逻辑。
那一刻我在工位前,脸是真的有点烫。
不是我不会这些工具。而是我必须承认一件更丢脸的事——
我已经很久没主动去深挖问题根因了。
我习惯了凭经验判断八成是哪里出事,然后用惯性动作把火压下去,再等下个版本找借口重构。
说难听点,我不是比他强,我只是比他懒得久。
那时我第一次意识到一件事:我如果还有价值,那价值不再是哪个类我熟,而是我能不能把混乱变成可复用的处理流程。
晚上回去躺在床上在想,我所谓的十年经验,到底是什么?
我开始盘点,我这所谓的十年经验,到底值钱在什么地方?
Spring Boot?他第一周就能写。
MyBatis?他两天就改需求了。
Redis?他甚至还整理了一个我们项目里所有key的命名规范,说有点乱。
微服务?咱那点微服务的知识,还不够他吃半年。
线上故障处理?老油条的处理方式,最后能得到什么?
业务?这些业务换个平台又起什么作用?
我以前一直很吃一套心理优势,我知道系统里有多少历史坑,我知道哪些类谁都不敢动,我知道凌晨三点要重启哪台机器比较稳,我知道哪个模块碰不得。
我曾经以为这是沉淀。
后来我发现,这叫习惯脏。
我很多时候并不是懂系统,我只是习惯系统的脏。
而这个习惯系统的脏,在老板眼里并不等于不可替代。恰恰相反,只能说明这个系统任何一个老员工都能把他继续撑着。
然后我看到了更残酷的现实,新人干活快,工资低。我干活也快,但工资高。
如果我们做的,都是同样层次的事情——写接口、加字段、改个if、补个try-catch。
那对不起,我是那个可以被更便宜的人替代掉的那一个。
我想明白了一句话,我所谓的十年经验,其实只是把一年的CRUD经验,重复了十年。
疼不疼?很疼。但也很清醒。
那一刻我第一次用老板的视角打量自己,问题突然变得特别具体:
如果我明天离职,我拿什么跟下一家公司谈我值现在这份钱?
我熟悉公司这套老系统?别人不在乎。我能改需求?新人也能。我能通宵”?老板会觉得谢谢,但也会觉得新人同样能。甚至更便宜。
我的价值,好像不能再放在谁写得快,而必须放在谁能让复杂系统恢复、稳定、可控。
这才是老板真正会买单的能力。
从那天起,想明白了一个现实问题,我拼不过22岁的体力,也没有一线大厂的光环履历,那我还能靠什么活下去?
就只有去补那些新人解决不了,但老板必须有人能解决的能力。
换句话说,我得变成那个线上出事,大家都慌,我能把现场兜住的人。
不想再当一个油腻的中年人了。
渐渐地我开始整理文章,捡起以前对技术的热情。
线程池到底是在防止什么灾难?
拒绝策略是不是随便选的?
CountDownLatch、AQS、锁竞争这些底层机制,真正在生产里是怎么救场的?
我把这些沉淀成了一个我自己的小套路,叫线程池三层校对法:业务强度→机器资源上限→拒绝策略闭环。因为我发现,很多事故不是因为不会多线程,而是因为线程池参数乱配。
我不满足于系统能跑了,源码也得梳理一下:
Spring是怎么解决循环依赖的?
ConcurrentHashMap为什么不是HashMap+锁那么简单?
synchronized为什么以前说慢、现在又说其实很快?JVM在里面做了什么优化?
我想以后再有人问我为啥修这个能救现场,我能说出原理,而不是我感觉可以。
为了重拾代码,我开始把这些啃下来的东西整理成文章,写成清单、步骤、甚至像演练脚本一样的东西。
外面看到的《Java100天成长计划》,很多人以为是我在分享经验。
其实是也不是。说句实话,我写这些,是因为我害怕,也是因为我还有那么一些热情。
我也非常清楚,如果我不把自己往不可随便替代的区域推,我就是下一个被优化的中年后端。
同样另一个我同样清楚的事是,这些东西一旦沉淀成SOP、Checklist、演练脚本,就不只是我的保命技能了,也可以变成带别人的方法。
我写这篇不是为了给你制造焦虑,我知道你已经够焦虑了。
我只是想很坦白地告诉那些跟我一样的人,在小厂干了三五年,自信自己是老员工、不可或缺的那些人——该醒醒了。
我们培训出身,没有大厂背书,我们年纪也不小了,熬夜体力也拼不过22岁那一批。
真正能保命的,从来就不是CRUD本身,而是复杂问题出现的时候,别人全乱套,你还能把现场兜住的那种能力。
这个能力,没人会免费喂到你嘴里。只能自己啃。我现在在做的事,就是边啃,边分享出来,让更多人少走弯路。
我在公众号【懒惰蜗牛工坊】长期写小厂后端的生存手记、普通程序员的技术自救路线、以及各种学习方法、路径。
我还在挣扎,还没上岸。如果你也一样,别客气,留个脚印,我们一起走。