陈默盯着屏幕上那行红色的异常信息,已经整整三个小时了。Java后端最常见的运行时异常,新人入职三天就会碰到的东西。可就是这么个基础错误,在日志里出现了十三次,每次调用栈都不一样。他翻了一遍又一遍,从控制层追到业务层,再追到数据层,每次都停在同一个位置,一个不该为空的引用了另一个不该为空的引用。
显示器右下角的时间跳到了凌晨两点十七分。书房里只有机械键盘的敲击声和机箱风扇低沉的嗡鸣。陈默把腿蜷起来,椅子往后滑了半米,盯着天花板的吊灯发呆。吊灯没开,头顶只有书桌上一盏台灯的光,把整个房间切成明暗两半。他闭上眼睛,在脑子里过了一遍调用流程。
用户的请求进来,经过参数校验,然后走到业务逻辑层。业务逻辑层调了一个内部服务,那服务返回的结果理论上不可能为空。但日志显示,在一种边界条件下,那个返回值就是空了。而下游代码没有做防御性检查,直接调用了空对象上的方法。逻辑是清晰的。问题是那个内部服务为什么返回了空值。
陈默睁开眼,又看了一眼堆栈。他切换到日志面板,搜索那个内部服务的输出。三月份的日志量已经很大了,光是今天凌晨就有几万条。他按时间倒序翻,找到对应的时间窗口。二点零三分,有一条警告级别的日志,来自那个内部服务。他点开一看,是数据库连接池超时的告警。
陈默盯着屏幕自言自语地说:「第三行,第三行,你到底藏在哪里。」
他又看了一遍,还是没找到。
他对自己说:「冷静,从头来。」
他喝了口茶,然后说:「如果我是这个bug,我会藏在哪?」
陈默拿起桌上的保温杯,喝了口已经凉透的茶。他把椅子拉回桌前,开始梳理根因。不是算法问题,不是业务逻辑问题,是基础设施层的连接池不够用了。线上环境流量涨了,连接池参数没跟着调。数据库连接拿不到,服务返回空,上游代码没做检查,一路抛出异常。
他在公司内部的维基上找到一个现成的模板,开始写技术方案文档。写了三行,又删掉。不对,参数调大只是一时之计。真正的问:「题是监控没有覆盖到连接池水位。」如果监控到位,在连接池使用率达到百分之七十的时候就该告警了,不会等到超时才暴露出来。
他的手机突然震了一下,是老张发来的微信:「还在忙?」
陈默回复:「有个线上bug,正在查。」
老张说:「严重吗?」
陈默说:「不算严重,但明天评审会之前得修好。」
老张说:「需要帮忙就说。」
陈默说:「不用,已经定位到了,在改。」
老张说:「那你早点弄完早点睡。」
陈默说:「你也是,这么晚还不睡。」
老张说:「被孩子吵醒了,顺便看看邮件。」
陈默发了一个握手的表情。他放下手机,心情莫名好了几分。
他打开开发工具,在代码里找到那个出问题的内部服务,看了下连接池配置。最大连接数设置了二十个,当前线上流量大概需要四十五个并发连接才够。二十个远远不够。调大到六十个,同时加上连接池使用率的监控告警。另外,上游调用方加上空值检查,返回空值时抛出带明确业务含义的异常,而不是让栈一路冒上来。
陈默在键盘上敲了几行,停下来,又删掉了几行。他总觉得哪里不对。这个问:「题暴露出来的不只是连接池配置不当。」更深层的问题是,整个团队在编码规范上没有统一的标准。有人做防御性检查,有人不做。有人写空值检查,有人觉得没必要。代码评审的时候也没人注意到这个问题,因为大家都是赶着上线。但这话不能写在技术方案里。技术方案只解决问题,不批评人。
他重新开始写,这次写得很快。凌晨三点十二分,修复方案初稿完成了。陈默把文档保存到内部系统,打算明天上班后发给组长审核。他知道组长会怎么回复,先夸一句效率高,然后挑几个格式上的问题让他改,最后在组会上说:「这个案例是典型的线上问:「题响应范本。」」他在公司待了六年,对这套流程熟得不能再熟。
陈默站起来,走到窗边。二十三层的高度,能看到浦东零星的灯火。半夜的上海不像白天那样拥挤,高架路上偶尔有一辆车驶过,尾灯拖出一道:「暗红色的线。」远处陆家嘴的几栋大楼还亮着景观灯,轮廓清晰可见。他看了看窗户上自己的倒影。五个小时前刚过三十五岁生日,头发还算是浓密的,但两鬓已经能看到一些白茬。眼镜片后面的眼睛有些发红,眨一下会有轻微的刺痛感。
回到桌前,屏幕上的异常信息还挂在那里。他看了眼日志采集系统,确认这轮异常的完整调用栈都已经被抓取到了,然后才关掉日志面板。还剩下一个问:「题没想明白。」这个异常第一次出现是在晚上十一点十三分,到现在三个多小时了。按说线上流量高峰期应该已经触发了告警,但告警系统没有发出任何通知。他检查了告警配置,发现这个服务的告警阈值设置的是每分钟超过一百次才触发。十三次,远不到告警线。
陈默叹了口气。告警阈值是去年定的,那时候这个服务的流量只有现在的十分之一。阈值没跟着流量一起调整,等于说:「现在的监控系统对这个错误是失明的。」他把这个发现也写进了方案里,作为第二个待办项。
电脑风扇转得急了一些,嗡嗡的声音在安静的夜里格外清晰。陈默看了眼系统资源监控,处理器占用率不高,倒是内存吃了不少。他顺手关了几个不用的开发工具窗口,风扇转速慢慢降了下来。他揉了揉眼睛,重新看了一遍堆栈信息。十三次异常,分布在十三个不同的请求上。受害用户不多,但每一个都收到了五百错误页。
如果他今晚没有主动上线看日志的话,这个问题可能要等到明天白天,用户投诉量上升之后才会被发现。想到这里,陈默觉得有点累。不是身体上的累,是一种说:「不上来的、闷闷的感觉。」他决定今天晚上一定要把根因定位清楚,把修复方案做到位。至少,明天开会的时候,他能把完整的技术分析摆在桌上,而不是只给一个结论。
凌晨三点二十八分。书房的窗外,浦东的夜色依然安静。远处有一架飞机闪烁着信号灯,缓缓地朝浦东机场的方向降落。陈默拿起手机
朋友圈里满屏的中秋祝福,他却一条都不想发。成年人的社交网络就是这样,热闹是给别人看的。
,看了眼微信。妻子林薇在十一点多发了一条消息,说你先睡吧,别太晚了。他回了一个手势,然后把手机放回桌上,继续盯着屏幕上的代码。那个空值的调用链路,他还要再走一遍。键盘的敲击声又响了起来。
他从桌面上翻出笔记本,用笔把调用链路画了一遍。纸上出现了六个模块的连线,从用户请求入口一直到数据库访问层。他用红笔标出了异常发生的位置,又用蓝笔标出了连接池所在的位置。两条线的距离在架构图上只隔了两个模块,但在运行时环境中,跨过了网络调用、线程切换、连接复用好几层抽象。
陈默想起刚工作时带他的老程序员说过一句话,线上问:「题百分之八十出在边界上。」连接池的边界、流量的边界、数据量的边界。正常路径大家都测试过,边界条件才是埋雷的地方。今天这个雷正好卡在评审会的前一个晚上。他想起赵恒的做事风格,那个组长对线上事故零容忍。上次组里有个同事因为一个少写了大括号导致的问题被通报批评,赵恒在组会上把代码拷到大屏幕上,逐行分析错误原因,讲了整整一个下午。在场所有人都不敢出声,会议室里只有赵恒的声音和键盘敲击的回响。
陈默端起保温杯又喝了一口,茶已经彻底凉了,苦涩的味道:「在舌尖化开。」他没有去续热水,把杯子放回桌上,手指在键盘上停了片刻。他打开那个内部服务的源代码,从头到尾读了一遍。四百多行的类,逻辑不算复杂,但耦合了好几个外部依赖。连接池只是其中一个环节,如果数据库响应变慢,或者网络延迟增加,即使连接池没满,这个服务也可能出现超时。他又想到,如果并发量继续增长,六十个连接也可能不够用。到时候还需要再做一次调整。但那是以后的事了,先把眼前的问:「题解决掉。」
他在方案里又加了一行,建议在连接池客户端增加重试机制,第一次超时后等待两百毫秒再试一次。这个改动不复杂,但能覆盖很大一部分由瞬时抖动引起的问题。他写完这一条之后,觉得方案总算完整了。三个小时前还在折磨他的那些红色报错,现在在脑子里已经变成了一条清晰的问题链。从表层现象到根因到修复措施,每一环都扣上了。他又通读了一遍方案,确认没有遗漏,然后把文档保存在本地。
他看了下时间,凌晨三点四十一分。距离天亮还有两个多小时。窗外的浦东依然安静,远处陆家嘴的灯光稀疏了一些,有些写字楼已经关掉了景观照明。陈默把笔记本合上,靠在椅背上。肩膀和脖子的酸痛比刚才更明显了,他转了转脖子,颈椎发出咔的一声轻响。他闭上眼睛休息了两分钟,再次睁开的时候,视线里的红血丝比之前又多了几条。他决定不再继续看代码了,让眼睛休息一下,等待林薇醒来。
他发现自己盯着同一行代码看了至少五分钟,脑子里却什么都没想进去。不是看不懂,是太困了,困到思维开始打结。他摇了摇头,想让自己清醒一点,但效果不大。他又端起咖啡喝了一口,凉的,苦的,但他需要一个外在的刺激来保持清醒。他想起读书的时候,期末考前也是这样,靠冷咖啡和熬夜撑过去。那时候觉得毕业就好了,不用再熬夜了。结果毕业了,熬夜变成了常态,只不过从复习变成了debug。
他又看了一遍堆栈,这次不是从前往后看,从后往前看。从最下面的方法调用开始,一个一个往上追溯。每一个方法他都打开源码确认一遍。第一层没问题,第二层没问题,第三层要注意一下那个边界条件,第四层有一个潜在的并发问题,但不是这里。他一个方法一个方法地往上走,像是考古一样层层剥离,最后回到了第三行。还是这里。所有线索都指向同一个位置,但到了那里就断了。
书房的门被轻轻推开了。陈默没有回头。他知道是谁。林薇站在门口,穿着一件浅灰色的睡衣,头发有点乱。她没说话,靠在门框上看着他。键盘声响了一分钟,陈默才转过头来。他看到她的眼睛还没完全睁开,显然是刚从睡梦中醒来。
他对林薇说:「她揉了揉眼睛,说嗯,几点了。」陈默说:「快四点了。」林薇走进来,在书桌对面那张平时给女儿换尿布用的矮凳上坐下。凳子很矮,她坐着的时候膝盖快顶到胸口了,整个人缩成小小的一团。她问:「还在忙那个空指针的问题。」陈默说嗯,线上出了个bug,定位花了不少时间。
林薇伸手拿过他桌上的保温杯,拧开盖子闻了闻,皱了下眉。她说凉的,我给你倒点热的。她站起来,拿着杯子去了客厅。陈默听到饮水机咕噜咕噜响的声音,过了一会儿,林薇端着热茶回来了。她把杯子放在他手边,说给。陈默接过来,喝了一口。温度刚好,不烫嘴也不寡淡。他喜欢喝温茶,林薇记得。卧室和厨房之间的那条路她走了无数遍,闭着眼睛也不会撞到任何东西。即使半夜起来,她也能准确地找到水杯、找到开关、找到茶叶罐的位置。住了四年的家,每个角落都被身体记住了。
林薇看着陈默,忽然说了一句让陈默怔住的话:你快乐吗?」陈默愣了一下。他从来没想过这个问题。他说:「陈默沉默了很久,最后说:
他忽然想起刚转行做程序员那年,父亲来上海看他。父亲一辈子在工厂里修机器,手上全是老茧和机油洗不掉的印子。他带父亲去他们公司参观,父亲看着满屋子年轻人对着电脑敲键盘,沉默了很长时间。回去的路上父亲说了一句话,他到现在都记得很清楚。父亲说:「那时候他不理解父亲为什么说这句话,现在他隐约有些懂了。」父亲看不懂他的工作,就像他可能也看不懂AI时代的工作一样。害怕有一天,女儿长大了,做着他完全不懂的工作,用着他完全不懂的工具,而他只能像当年的父亲一样,站在旁边看着,什么都做不了。他摇了摇头,把这个念头甩出去。想这么多没有用。先把bug修好,先把今天的活干完,先把眼前的日子过好。至于未来,未来来了再说。
林薇问:「你盯着屏幕多久了。」陈默说:「从九点多吧。」林薇说那六个小时了,你的眼睛不疼吗。陈默说有点。林薇叹了口气,沉默了片刻,然后说:「你们公司其他人也这样吗。」陈默说:「差不多。」林薇说:「你以前在那两家公司的时候也这样。」陈默说:「那时候比现在还晚。」这是实话。第一家公司做电商,大促期间通宵是常态。第二家做金融系统,上线窗口都在凌晨。现在这家虽然也忙,但至少周六日基本能保证休息。
林薇走到陈默身后,两只手搭在他肩膀上,轻轻按了按。陈默的肩膀很硬,肌肉僵得像一块木板。她说你颈椎又不好了,上次体检那个医生说:「你颈椎生理曲度变直了。」陈默说:「知道」林薇说:「还不注意。」陈默没接话。林薇的手在他肩膀上按了一会儿,力道适中,酸痛感消退了一些。她按了大概两分钟,手指从肩膀移到后颈,轻轻揉捏了几下。陈默觉得那几块僵硬的肌肉在她的按压下终于松开了一些。
安静了片刻,林薇问:「起他正在做的那个项目。」陈默说还在开发阶段,不过方向基本定了,做一个面向企业的AI应用平台,帮客户快速落地大模型应用。林薇问就是你上次说的,给企业搭积木那种。陈默笑了一下,说差不多。平台提供一些预置的模块,客户可以根据自己的需求组合。核心是降低AI应用的门槛,让不会写代码的人也能搭建自己的智能应用。
林薇说:「你今天晚上真的打算一直坐到天亮吗?」
陈默说:「bug修完就去睡。」
林薇说:「你每次都这么说。」
陈默不说话了。他知道她说得对。
林薇走过来,站在他身后,说:「你知道:「小朵今天跟我说了什么吗?」」
陈默说:「她还不会说话吧。」
林薇说:「她用眼睛说的。她晚上醒了一次,没哭,就睁着眼睛看天花板。我抱着她哄了一会儿,她看了我一眼,像是在问:「爸爸去哪了。」」
陈默沉默了。
林薇说:「我没有告诉她你在加班。我说爸爸在隔壁,明天早上就能看到他了。」
陈默说:「对不起。」
林薇说:「我不是要你说对不起。我只是想让你知道:「有人在家等你。」」
陈默说:「我知道。」
林薇说:「你知道就好。面煮好了,过来吃吧。」
林薇在矮凳上坐下来,歪着头看他。她问:「那你现在在做什么。」陈默转回屏幕,指了指开发工具里打开的文件,说我做底层这一块。推理引擎的调度模块,负责把用户的请求路由到不同的模型服务上。林薇说:「听起来挺复杂的。」陈默说还行吧,做了半年了,架构已经定型了,现在主要是优化性能和修bug。
林薇安静了一会儿。书房里只有电脑风扇转动的声音。她忽然问:「陈默愣了一下,什么意思。」林薇说:「我有时候看新闻,到处都在说AI要替代程序员,替代设计师,替代翻译。但你每天干的事情,不就是修这些别人的代码都修不好的bug吗。连你们公司内部自己的服务都还会出空指针这种问题,AI能解决得了这个?」
陈默想了想,说AI能解决一部分问题吧。但至少现阶段,还解决不了我今天遇到这种。林薇问:「为什么。」陈默说因为这个问题不是代码层面的,是系统层面的。连接池配置不合理,监控阈值没跟上,编码规范不统一。这些问题不是一个AI模型能看出来的,因为它不知道业务背景,不知道当初为什么这么配置,不知道:「团队的工作习惯。」
林薇点了点头,说那不就是说:「:「AI替换不了你。」」陈默笑了,说今天替换不了,明天也够呛。他顿了顿,又说不过长远来看,AI肯定会改变我们写代码的方式。以前程序员花很多时间在写重复的代码上,以后这部分可能就不需要了。但系统设计、架构决策、问题诊断这些事情,还是需要人来判断。林薇重复了一下这个词,说判断。你刚才说:「的是判断。」陈默说嗯。林薇说:「那不就是你们项目的名字吗。」陈默点点头,说对,平台的名字就叫判断权。意思是说:「AI提供参考,人类做最终判断。」
林薇沉默了一会儿,说我觉得这个名字起得好。陈默看着她,有些意外,说你突然对这个感兴趣了。林薇站起身来,走到窗边,说不是突然感兴趣。就是睡不着的时候会想,你每天在公司忙到这么晚,到底在忙什么。今天正好看到了,就问问。
她停了片刻,继续说:「以前小朵还没出生的时候,你至少还能赶在晚饭前到家。现在经常是我和妈先吃,你的饭热了又热。」上周末你说陪我们去商场给小朵买衣服,结果刚出门就接到公司电话,你在小区门口站了四十分钟,回来的时候一整个下午都在书房改代码。小朵那件衣服最后还是我自己去买的。陈默听着,没有辩解。他知道林薇说:「的都是事实。」他确实很久没有准时下过班了。
窗外依然是深夜。林薇站在窗前,背影对着陈默。她问:「那就是我们这一代程序员要解决的问题了。」陈默想了想,说:「对,但也不是我一个人能解决的。」林薇转过身来,笑了笑,说:「行了,不跟你讨论哲学问题。你什么时候弄完?」陈默说:「快了,再把方案完善一下就睡。」
林薇问:「快天亮了吧。」陈默看了眼时间,说四点半了,天快亮了。林薇说那你再忙半小时,然后去睡。我去给你煮碗面。陈默说不用了,我不饿。林薇说:「不饿也吃一点。」她说完就走出了书房,带上了门。陈默听着她的脚步声往厨房的方向去了。他听到她打开冰箱的声音,然后是水流声,锅碗碰撞的轻响。卧室里传来女儿小朵翻了个身的声音,然后又安静下来。
陈默转回屏幕,把注意力重新放回代码上。他忽然想起林薇刚才问的那个问题,如果有一天AI真的比人强了,做判断的会不会就不是人了。他在心里默念了一遍这句话。这个问题他其实想过,不止一次。在公司内部讨论会上,在产品方案评审会上,在跟同事吃午饭的时候,这个话题被反复提起。没有人能给出确定的答案。他摇了摇头,把这念头搁到一边,继续看代码。
他一个人坐在书房的黑暗中。台灯是他唯一的光源,照亮了桌子上一小块区域,之外全是模糊的暗影。他想起刚才和妻子的对话,想起她说:「那句话时的表情。」你什么时候会被替代。这个问题像一颗种子,被妻子不经意地种进了他的脑子里,然后开始生根发芽。
他试着回想自己入行这十几年的经历。从刚毕业时连git都不会用的菜鸟,到能独当一面的后端工程师,中间熬了多少个这样的夜晚他已经数不清了。他学会了很多东西,有些是技术上的,有些是职场上的,有些是做人方面的。但所有这些经验,在AI面前会不会变得一文不值?他不知道。
他想起前两天在技术论坛上看到的一个帖子,有人用ChatGPT生成了一段生产级别的代码,下面跟帖一片惊叹。他当时也觉得厉害,但没有多想。现在回想起来,那个帖子像是一个信号。一个他一直在忽略的信号。他打开手机想搜一下那个帖子,但想了想又放下了。现在看了也睡不着。而且他怕自己看了之后更焦虑。
他靠在椅背上,看着天花板上的裂纹。那条裂纹还在那儿,他一直没有补。就像他一直没有认真面对那个问:「题一样。」但今晚妻子帮他问:「出来了。」你什么时候会被替代。他闭上眼睛,「长长地呼出一口气。然后他睁开眼,重新面对屏幕。先把今晚的bug修了再说。那些问题,」明天再说。
他坐在黑暗里想了很久。想父亲的背影,想妻子的眼神,想女儿的笑脸。想自己这十几年到底走了多远,又还剩多少路要走。想那些深夜修过的bug,那些上线前的焦虑,那些被客户骂的日子。想这一切到底值不值得。他没有答案,但他知道:「他还会继续写代码。」因为他已经走了这么远。
林薇走了之后,陈默把修复方案又过了一遍。他打开代码,在内部服务的调用方加上了空值检查。如果返回值为空,就抛出一个带详细上下文的自定义异常,错误信息里包含请求参数、时间戳和原始异常的原因。然后他打开了连接池的配置文件,把最大连接数从二十改成了六十。又加了一行配置,设置连接空闲超过三十秒后自动回收。他仔细检查了每一行改动的语法,确认没有引入新的问题。然后他保存了文件,重新编译了一次,编译通过。
改完代码之后,他登录了公司的监控管理后台,调整了告警规则。告警阈值从每分钟一百次改成每分钟十次。连接池使用率超过百分之七十就发一条警告,超过百分之九十触发紧急告警推送到手机上。他又检查了一下这个服务的其他告警项,确认没有类似的阈值过时问题。改完之后,他看了眼时间。凌晨五点十二分。
陈默关上电脑,站起来伸了个懒腰。这时候,他才注意到窗外天已经亮了。他忽然想笑——自己花了整整一个晚上,就为了修一个空指针。但在这一行代码背后,是整个行业正在发生的变化。他拿出手机,打开搜索引擎,在搜索框里打了一行字:ChatGPT 能写代码了吗?然后他按下了搜索键。结果还没有出来之前,他先去了女儿的房间。
还有一件事。他打开团队维基,在编码规范页面上加了一行,所有外部服务调用必须做非空校验,违规项纳入代码评审检查清单。改完之后,他盯着这行字看了很久。他知道:「这条规范推行下去会有阻力。」有人会觉得这是小题大做,有人会说项目紧没时间改,有人会说:「以前不也这么过来的吗。」但他还是加上了。他想起赵恒在组会上说过的一句话,规范不是用来限制人的,是用来保护人的。当时他觉得这话有点官方,现在想想,确实是这个道理。
他提交了变更,在提交信息里写,修复线上异常,根因为数据库连接池配置不足,同步调整监控阈值及新增编码规范。然后,他点击了提交。屏幕上弹出一个绿色的提示,提交成功。他盯着那行绿色的字看了几秒钟,确认不是幻觉。
陈默靠在椅背上,长长地呼出一口气。三个小时前还在折磨他的那行红色异常信息,现在看起来已经没那么刺眼了。他关掉了开发工具,关掉了日志面板,关掉了监控后台。屏幕上的窗口一个个消失,最后只剩下一张干净的桌面壁纸,是小朵百天的时候拍的照片,胖乎乎的小手抓着一个布偶兔子。他看到照片里小朵的笑脸,嘴角不自觉地跟着弯了一下。
他想起了很多事。想起自己第一份工作,月薪三千五,住在公司附近的隔断间里。隔断间的墙是石膏板做的,隔壁打电话他听得一清二楚。那时候他每天加班到九十点,不觉得累,因为觉得自己在学东西。后来换了几家公司,工资涨了,房子换大了,但他再也没有那种学到新东西的兴奋感了。工作变成了重复。写代码,修bug,开会,写文档,上线,再写代码。像一个循环,永远没有终点。他有时候会想,如果有一天他不用再写代码了,他会做什么。他想过去开一家小面馆,在小区门口,只卖一种面。想过回老家种地,但老家已经没有地了。想过很多种可能,但没有一种是确定的。他唯一确定的事情是,他想看着女儿长大。想看到她第一次走路,第一次说话,第一天上学。想在她需要父亲的时候,他能在她身边。不是为了别的,只是因为他自己的父亲没有做到这一点,他想做到。
他站起来,活动了一下肩膀和脖子。关节咔咔响了几声,肩膀的酸痛比之前更明显了些。他做了几个伸展动作,然后走出书房。客厅的灯开着,林薇在厨房里煮面。锅里的水翻滚着,白色的蒸汽升起来,模糊了抽油烟机上的不锈钢表面。空气里有西红柿和葱花的味道。林薇头也不回地说:「马上好了。」
林薇把面端到餐桌上,说:「加了两个鸡蛋,你多吃点。」
陈默说:「你也吃一点。」
林薇说:「我不饿,你吃吧。」
陈默吃了几口面,说:「好吃。」
陈默说:「小朵今天醒了吗?」
林薇说:「醒了一次,喝了奶又睡了。」
陈默说:「昨天晚上我回来的时候她已经睡了。」
林薇说:「她睡前一直看门口,可能在等你。」
陈默吃完面,把碗端到厨房。林薇正在给小朵换尿布。
陈默说:「我来吧。」
林薇说:「你不是要睡觉吗?」
陈默说:「不差这几分钟。」
他接过小朵,把她抱在怀里。小朵半睁着眼睛看了他一眼,然后又闭上了。
林薇说:「她认得你。」
陈默说:「当然认得,我是她爸。」
林薇笑了,说:「你抱她的姿势还是不对,手要托着脖子。」
陈默调整了一下姿势,说:「这样?」
林薇说:「差不多了。」
陈默没说话,低头吃面。
林薇说:「你下次早点回来,她还没睡的时候,陪她玩一会儿。」
陈默说:「好。」
林薇说:「不是说说而已。」
陈默说:「我知道。我尽量。」
林薇说:「不是尽量,是做到。」
陈默看着她,说:「好,我做到。」
林薇笑了,说:「这还差不多。」
林薇笑了,说:「每次都说好吃。」
陈默说:「因为每次都好吃。」
林薇说:「你今天怎么这么会说话?」
陈默说:「修完bug心情好。」
林薇说:「那我以后多让你修bug。」
陈默说:「不用修bug也心情好。」
林薇看着他,说:「你今天是不是被什么东西触动了?」
陈默说:「可能是被你那个问题触动了。」
林薇说:「什么问题?」
陈默说:「你什么时候会被替代。」
林薇沉默了一会儿,说:「我不是那个意思。」
陈默说:「我知道。但这个问:「题早晚要面对。」」
林薇说:「不管你做什么决定,我都支持你。」
陈默说:「我知道。」
窗外的天开始亮了。林薇说:「天亮了。」
陈默说:「嗯,新的一天。」
陈默没去餐桌,而是拐进了卧室。卧室里亮着一盏小夜灯,暖黄色的光。女儿陈小朵睡在婴儿床里,睡得正香。小朵六个月大,睡觉的姿势很不老实,一只小脚丫从被子里伸了出来,五个脚趾头微微蜷着。她的呼吸很轻很慢,鼻翼随着呼吸一张一合,小嘴微微张着,嘴角有一点点口水印。睡梦中她忽然皱了一下眉头,像是做了什么梦,然后又舒展开来,嘴角弯了弯。
陈默伸手把她的小脚丫轻轻塞回被子里。小朵被碰了一下,小腿蹬了蹬,但没有醒。她翻了个身,把头埋进被子里,继续睡。陈默蹲在那里看了她几分钟。他说:「不上来那是什么感觉。」就是觉得很安静。刚才脑子里还在转的那些代码、日志、告警阈值,这会儿全都不见了。只剩下小孩子平稳的呼吸声。和凌晨在书桌前盯着屏幕的时候完全不同,那个世界里到处都是问题和异常,这个世界里只有呼吸和温度。
他站起来,轻手轻脚地走出卧室,把门虚掩上。林薇已经把面端到餐桌上了。一碗西红柿鸡蛋面,上面撒了一把葱花,还有一个煎得两面金黄的荷包蛋。蛋煎得很好,边缘焦焦的,中间的蛋黄还是半凝固的状态。陈默在餐桌前坐下,拿起筷子。林薇在他对面坐下,问小朵没醒吧。陈默说没有,睡得很沉。
林薇说白天玩累了,下午带她去小区花园里转了一圈,看到别的孩子玩滑梯,高兴得直拍手。陈默吃了一口面。面条煮得刚好,不软不硬,汤底酸酸甜甜的,是林薇最拿手的做法。他说好吃。林薇笑了,说是啊,也不看看是谁煮的。陈默低头吃面,林薇就坐在对面看着他吃。窗外天色开始变亮了,从深黑色变成了深蓝色,远处的楼顶轮廓线开始变得清晰。对面那栋楼有几户人家也亮了灯,大概是早起的人开始了一天的生活。
林薇说:「天亮了。」陈默抬起头,看向窗外。东方天际线泛出一层浅浅的灰色,上海市区的灯光开始一盏盏熄灭。他说六点了,一夜过去了。林薇说:「你吃完饭去睡吧。」今天周末,不用去公司吧。陈默说不用,但我下午约了同事讨论方案。林薇说:「那上午好好睡一觉。」陈默点了点头。
他吃完了面,把碗筷收到厨房水槽里。林薇已经回了卧室,抱着小朵喂奶。小朵半梦半醒地含着奶嘴,两只小手攥成拳头,放在林薇胸口。晨光从窗帘的缝隙里透进来,在地板上拉出一道:「细细的光线。」房间里的家具轮廓在这个光线里变得柔和了很多。婴儿床的围栏上挂着几个布偶,有一个兔子耳朵已经被小朵咬得变了形。
林薇轻声说:「快去睡吧。」陈默说马上。他转身去了书房,把桌上的资料整理好,合上笔记本电脑。他看了眼屏幕上的提交信息,提交成功四个字还是绿色的。他按了下电源键,屏幕暗了下去。
书房里安静了。窗外晨光越来越亮,不知道谁家的闹钟响了,远远地传来,又消失了。小区里开始有人声,早起的人出门了,楼下传来汽车发动的声音。这些声音交织在一起,组成了上海清晨的底色。陈默躺到客厅的沙发上,拉过一条毯子盖在身上。肩膀还酸,但眼睛闭上之后,脑子里终于安静了。那些代码、异常、日志,全都退到了后面。
他听见卧室里林薇哼着摇篮曲,声音很轻很柔。小朵咿咿呀呀地回应了几声,然后安静下来。陈默翻了个身,把脸埋进沙发靠垫里。沙发上有小朵奶香的味道:「。六点十七分。新的一天开始了。他的呼吸慢慢变得平稳,肩膀的酸痛在毯子的温度里一点点化开。」那些代码和异常已经不再在他脑子里打转了。耳边只剩下林薇的摇篮曲和小朵含混的梦呓,两种声音交织在一起,比任何代码都流畅。
他站在婴儿房门口,一步都没有跨进去。怕吵醒她。但他也不想走。他就这样站着,靠在门框上,看着女儿。忽然觉得自己今晚那几个小时其实也没那么重要了。那个bug明天修也可以,后天修也可以,天不会塌下来。但此刻站在这里看女儿睡觉,这个瞬间错过了就是错过了。
他想起有一次下班回来比较早,天还亮着。林薇在厨房做饭,他抱着小朵在客厅玩。小朵那时候还不会说话,但已经会发出各种咿咿呀呀的声音。他把她放在沙发上,她翻了个身,仰着头看他,然后笑了一下。那个笑容没什么特别的,婴儿都会笑,但他就是记住了。那个瞬间,工作群里还在@他问问题,他看了一眼手机,没有回复。
那一刻他觉得,有些事情比工作重要。因为他不想等到女儿长大了,才发现自己错过了她的整个童年。他不想变成那种父亲。他想起自己的父亲。父亲是个老实人,一辈子在一家工厂里干活,每天早出晚归。他小时候很少见到父亲,因为父亲下班回来的时候他已经睡了,父亲上班去的时候他还没醒。他现在理解父亲了,父亲是为了养家。但他不想让小朵也经历同样的童年。
他性格固执,但骨子里很温柔。平时沉默寡言,急躁时也会拍桌子,沉稳下来又能笑着自嘲。
夫妻之间有一种默契,朋友之间有一种信任。这些年他学会了在不同关系中切换角色。
他决定不再逃避,选择面对一切。坚持还是妥协,成了他每天都在思考的问题。他不想再放弃了。
由此可见,这说明了所有事件背后的逻辑。简单来说,选择决定了方向。
总而言之,每个选择都有代价。说到底,没有白走的路。归结起来,一切都是最好的安排。
他预感到了什么,桌上的文件散发着不祥的气息,仿佛在暗示着什么。一切都暗示着即将到来的变化。
但谁也没想到,结局在意料之外。剧情突然转折,他以为看到了终点,却发现只是另一个起点。
他站起身走到窗前,抬手指尖轻触玻璃。转身回来时脚步重了许多。
声音里带着温度。话语的重量压下来,冰冷的质感从耳朵落到指尖。
窗外的树暗示着生命的韧性。风雨过后依然挚立,仿佛在告诉他坚持下去。
空气中漂浮着咖啡和雨水的味道。天色暗下来,氛围变得沉重。
从远景看,城市在天际线处模糊。拉近到中景,办公室的灯光闪烁。近处是他紧锁的眉头。
他穿着洗得发白的衬衫,袖口磨出了毛边。皮鞋擦得很干净。
内卷让人喘不过气。努力奋斗是为了不被淘汰,累到极致又觉得一切都没意义。躺平还是继续卷?每个人都在挣扎。
千禧年后的互联网泡沫,金融危机,移动互联网的黄金十年。如今ChatGPT来了,新一轮变革开始了。