第二章 · 有人在看¶
第二天早上,那封邮件有了第一个回复。
九点零四分,陈稳正在看一个新提的需求单,右下角弹出提示。他点开。
发件人:纪衡。
正文两个字。
收到。
下面是自动附加的签名:
签名比正文长。
陈稳把这封邮件读了一遍。两个字,一秒钟。他又读了一遍。
然后他往上滑,看了一下自己原来那封的长度。滚动条很短,拉到底要滑七下。
他把纪衡的回复留在屏幕上,没有关。
需求单看不下去了。他把光标移到邮件上,右键,标记为未读。然后又点回来,标记为已读。
他不知道自己在干什么。
"收到"是什么意思。
这两个字可以是"我知道了",可以是"写得不错",也可以是"别再发这种东西了"。它什么信息都没有,但又不是没有回复——如果不回复,那是没看见;回复了两个字,说明看了,但看完之后决定只给两个字。
他把这封邮件转发给了自己,加了个星标。他自己也说不清为什么。
十点,蒋辉在群里发了一张图。
是一张 PPT 截图,标题是《营销结算适配层上线复盘》。图上有四个色块,每个色块里一句话。第一个色块写着"上线成功,商户覆盖 11438",第二个写着"过程中发现与日终任务存在资源竞争,已协同结算组处理完毕"。
第三个色块:"建立跨组变更同步机制。"
第四个:"0 资损。"
蒋辉在图下面发了一行字:
复盘做完了 @全体成员 感谢结算组的支持 🙏
有六个人回了拇指。纪衡回了一个"👍"。
陈稳把那张图放大看。
四个色块,一共四十七个字。他昨天写的是三千一百字。
那个"已协同结算组处理完毕",说的是他凌晨三点起来 kill 事务。那个"建立跨组变更同步机制",是他改进项里的第三条,原文是"涉及结算核心表的变更,评审需结算组参与"。
蒋辉把它变成了一句听起来像是他提出来的话。
不是抄。他没有说这是他的想法。他只是把它放进了自己的复盘里,没有署名。
陈稳在输入框里打了几个字。
第三条是我改进项里的
他看着那行字。
然后删掉了。
因为如果他发出去,群里两百多个人会看到一个人在争一句话的归属。而蒋辉会立刻回一句"对对对,是陈稳提的,我表述不严谨",然后加个抱拳的表情。事情就结束了,蒋辉还会显得很坦荡。
而他会显得很小。
他把输入框清空,退出了群。
不是退群,是把窗口关掉。
十一点四十,老梁来找他。
老梁走过来的时候手里端着那个搪瓷杯,杯口那块磕掉的瓷朝外。他在陈稳工位旁边站了一下,说:
"下来抽根烟?"
陈稳不抽烟。老梁知道他不抽烟。
"好。"他说。
负一层的停车场角落有个楼梯口,是抽烟的人聚集的地方。这个时间没什么人,只有一根柱子后面有个人在打电话,说的是某个供应商的账期。
老梁把杯子放在栏杆上,掏出烟盒,抽了一根,没点。
"你那个复盘我看了。"他说。
"嗯。"
"写得很细。"
"应该的。"
老梁把烟在手里转了两圈。
"纪总也看了。"他说。
陈稳等着。
"他昨天跟我聊了一下。"老梁看着地面,"他说,写得太技术了。"
陈稳没有说话。
"原话是——"老梁停了一下,像是在确认自己有没有记错,"'这个人技术应该不错,但我看不懂他在讲什么。'"
停车场里有一辆车启动了,声音在混凝土里空空地响。
"他看不懂什么。"陈稳问。
"看不懂你为什么写那么长。"
"那是根因分析。"
"他不需要根因分析。"老梁把烟叼上,摸打火机,摸了两个兜才摸到,"他需要知道三件事:出了多大事,为什么会出,以后会不会再出。三句话。你写了三千字。"
"三句话说不清。"
"他不需要说清。"老梁点着火,深吸了一口,"他需要能往上讲。你那个东西他没法往上讲。他上面还有个人,那个人上面还有个人。你的三千字到第二层就没了。"
陈稳看着地面。地上有一片干掉的水渍,形状像一个不规则的省份。
"那第四条呢。"他说。
"哪一条。"
"改进项第四条。我说这周能做,日终任务窗口设写入禁入期。"
老梁弹了一下烟灰。
"没人回你吧。"
"没有。"
"因为没人知道那是什么意思。"老梁说,"你写'02:00 到 04:00 设为写入禁入期,网关层拦截'。纪总看到这句话,他不知道这值多少钱。你要是写'这个改动能让每年三次的凌晨事故变成零次,每次事故按人力成本算八千块',他就知道了。"
"那不严谨。"陈稳说。"三次是历史数据,不代表未来。八千块是我估的。"
老梁笑了一下。
"是。"他说,"你说的都对。"
他抽了两口,没再说话。
那个打电话的人挂了电话,从柱子后面出来,路过他们,看了一眼老梁,喊了一声"梁哥",走了。
老梁点了下头。
"我跟你说个事。"他说。
陈稳看着他。
"我在恒澜十一年。"老梁说,"这十一年,我做了七个系统。三个还在跑,两个被替了,两个死了。现在跑着的三个里面,有一个是全公司的钱都从那儿过的。"
他把烟灰抖掉。
"你猜我这十一年,最高的绩效是什么。"
陈稳没猜。
"B+。"老梁说。"一次。"
停车场很静。
"我不是跟你抱怨。"老梁说,"我是想说,我以前跟你一样,觉得东西做好了就够了。做好了自己会说话。"
他停了一下。
"东西不会说话。"他说。"东西是死的。只有人会说话。"
陈稳的手插在兜里。他摸到了裤兜里的胃药盒,很薄,里面的药片错动了一下,发出一点声音。
"那我要怎么做。"他说。
这句话说出来的时候,他自己听见声音里有一点不像自己的东西。太直了,太快了,像是在求人。
老梁看了他一秒。
"我不知道。"老梁说。
"……"
"我要是知道,我现在就不是这个绩效了。"
老梁把烟按在垃圾桶盖上的沙盘里,捻了两下。
"但你可以试试,把那三千字,改成三百字。"他说,"三百字发给纪总,三千字放在附件里。想看的人自己点。"
"那不就没人看了。"
"本来就没人看。"老梁端起杯子,"区别是,三百字他会看完。"
他往电梯口走了两步,回头。
"陈稳。"
"嗯。"
"你那个补偿脚本写得很漂亮。"老梁说,"分批两百,中间 sleep 五十毫秒,还避开任务窗口。我看了两遍。"
陈稳抬起头。
"但没人会看那个脚本。"老梁说。"包括我。我是特意去看的。"
电梯来了。老梁进去,门关上。
陈稳站在那儿,闻着停车场里剩下的一点烟味。
下午三点,他把复盘邮件重新打开。
三千一百字。他一句一句往下看,看哪些能删。
第一段时间线,五行。他试着改成一行:"02:35 告警,03:08 恢复,历时 33 分钟。"
删掉了四行。
第二段根因分析,八百字,还有那张 ASCII 画的锁等待链图。他看着那张图,看了很久。这张图他画了四十分钟,用空格对齐的,在等宽字体下才不会歪。
他把图删了。
改成一句:"营销结算模块在单事务内更新 11438 条记录,与日终对账任务争抢同一批行锁。"
三十九个字。
第三段影响面,他留了两个数:6102 落账,5336 回滚。删掉了 ID 清单的说明,改成"清单见附件"。
第四段改进项,四条。他试着按老梁说的改第四条:
- 日终任务窗口(02:00-04:00)设为写入禁入期,网关层拦截。 此项可消除同类凌晨事故,历史上每年约 3 次。
他看着"每年约 3 次"这几个字。
他去翻了历史工单。P1 以上、发生在凌晨、根因是写入争抢的——他一条一条查,查了四十分钟。
去年 4 次。前年 2 次。今年到现在 1 次。
三年七次,平均 2.33 次。
他把"约 3 次"改成"近三年共 7 次,年均 2.3 次"。
然后他坐在那儿,看着这行字。
这行字是真的。每一个数都能查到工单号。但他知道,写上"年均 2.3 次"和写上"约 3 次",读者的感受是不一样的。2.3 听起来像是一个小数,3 听起来像是一个事。
而如果他写"每年三次凌晨事故,每次平均影响 33 分钟",听起来又更严重一点。
同一件事,三种写法。都不算撒谎。
他把那行字删了,重新打了一遍,又删了。
这样来回了大概十分钟。
最后他写的是:
此项可消除同类凌晨事故。近三年共发生 7 次,年均 2.3 次,每次平均影响时长 30 分钟以上。
然后他往下滑,把全文从头看了一遍。
三百四十七个字。
四段变成了四行。他昨天写了四个小时的东西,现在剩下四行。那张 ASCII 图不在了,锁等待链不在了,他查了四十分钟才理清的那个循环嵌套不在了。
剩下的这四行,任何一个不懂技术的人都能看完。
他把光标停在发送键上。
停了一会儿。
他没有发。
他把这一版另存成了草稿,标题是"复盘(简)"。原来那封三千一百字的还在,标题是"复盘"。
两封邮件并列在草稿箱里。
他把窗口关了。
四点二十,他去接水。
茶水间里有个人在等咖啡机,背对着他,手里拿着一个笔记本电脑,屏幕开着,站着在看什么东西。
陈稳按了热水键。
"你是结算组的?"那个人说。
他抬头。是个女的,二十八九,短发,工牌挂在电脑包带子上,翻过去了看不见字。
"嗯。"
"陈稳?"
"你怎么知道。"
"你昨天那封邮件。"她把电脑合上,"抄送里有我。我在数据组,跨部门那条线。"
"哦。"
"写得挺好的。"她说。
陈稳没接话。这句话他今天听到第三次了,前两次说完后面都跟着"但是"。
她没有说但是。
咖啡机响了一声。她把杯子取出来,喝了一口,皱了一下眉,看了一眼机器上的按钮。
"这个机器的浓度调错了。"她说,"上次也是。"
"一直是这样。"
"没人调?"
"不知道。"
她点了点头,像是记下来了。
然后她说:"你那个锁等待链的图,为什么删了。"
陈稳的手停在杯子上。
"我没删。"
"你邮件里没有。"她说,"但你 MR 描述里也没有。我今天翻了你那个补偿脚本的提交,那个 commit message 里有一句话——'与日终对账任务争抢同一批行锁'。这句话是从一张图上抄下来的,我看得出来。因为它太概括了,概括得像是一张图的说明文字。"
陈稳看着她。
"图还在。"他说。"在草稿箱里。"
"为什么不发。"
"太技术了。"
"谁说的。"
他没有回答。
她又喝了一口咖啡,还是皱眉。
"那张图我想看。"她说,"你发我。不是为了帮你,我自己有个东西要用。"
"什么东西。"
"我在做一个跨系统的资源竞争分析。"她说,"你昨天那件事是个很干净的样本。一万一千条、单事务、和固定时间窗的任务撞车——这种事我找了三个月,一直只能找到别人转述的版本。第一手的没有。"
"为什么找不到。"
"因为写第一手的人,都被人劝着写短一点。"
她说完就走了,把咖啡端在手里。走到门口时她回头。
"易文。"她说,"数据组。"
"嗯。"
"那张图别删。"她说,"你要是不想发全公司,就发我一个人。"
她走了。
陈稳站在茶水间里,手里的杯子已经烫手了。他换了一只手拿。
回到工位,他把草稿箱里那封三千一百字的打开,把那张 ASCII 图截出来,单独存成一个文件。
然后他给易文发了一封邮件,只有附件,正文一行字:
图在附件。等宽字体打开。
晚上七点二十,他还在工位。
工区已经空了一半。运营那边有人在打游戏,声音很小。清洁的阿姨推着车过来,收走了他桌上的空水杯,看了一眼那盒胃药,没说话。
他打开了 IDEA。
第四条改进项,那个日终任务窗口的写入禁入。他说这周能做。
技术上不复杂。在数据访问网关那一层加一个拦截器,判断当前时间和目标表,命中就抛异常。核心逻辑大概八十行。
他开始写。
写到一半,他停下来,加了一个配置项——禁入时间窗要能配,不能硬编码。又停下来,加了一个白名单——万一以后真有紧急变更要在凌晨做,得有口子。又停下来,想到白名单会被滥用,于是给白名单加了一个审批标记字段,谁加的、什么时候加的、什么时候过期。
八十行变成了两百四十行。
九点十分,他跑通了单元测试。十七个用例,全绿。
九点四十,他提交。
commit message 他打了很久:
feat(gateway): 日终任务窗口写入禁入拦截
在数据访问网关增加时间窗拦截:命中禁入窗口(默认
02:00-04:00)且目标表在保护清单内的写请求直接拒绝,
返回明确错误码与建议重试时间。
配置项:
settle.guard.windows 禁入时间窗,支持多段
settle.guard.protected_tables 保护表清单
settle.guard.whitelist 白名单,需带审批号与
过期时间,过期自动失效
近三年凌晨写入争抢类事故 7 次,本拦截可覆盖其中 6 次
(第 7 次根因为从库延迟,不在本次范围)。
单测 17 例覆盖:窗口边界、跨零点窗口、白名单过期、
多段窗口重叠、保护表大小写、时区偏移。
他看了一遍这段话。
写得很清楚。每一句都是事实。
他把它推上去,提了一个 MR,指派给老梁 review。
然后他想起来,老梁已经不是他的组长了。
他把 reviewer 删掉,改成纪衡。
看了两秒,又删掉。
最后他填了组里另一个资深工程师的名字,那个人昨天主持双周会的。
MR 的描述框是空的。系统提示"建议填写变更说明"。
他把 commit message 复制了一遍,粘贴进去。
然后他在最上面加了一行:
这个改动能让每年 2 次以上的凌晨事故变成 0 次。
打完之后,他看着这句话。
这句话是真的。也是他第一次这样写字。
他把它删了。
改成:
覆盖近三年 7 次同类事故中的 6 次。
然后提交。
十点零五,他关电脑。
出办公楼的时候,外面在下雨。不大,是那种要撑不要撑都可以的雨。他没带伞,站在门口看了一会儿。
保安在门口的桌子后面看手机。
"没伞啊?"保安说。
"没。"
"前台有共享的。"
"不用,就两百米。"
他走进雨里。
走了大概五十米,他停下来,从兜里掏出手机,打开备忘录。
那条昨天写的还在:
三千字没人看。改进项那四条要单独发。
他在下面加了一行:
改成三百字。三千字放附件。
雨落在屏幕上,字有点看不清。他用袖子擦了一下,屏幕更花了。
他把手机放回兜里,继续往前走。
到小区门口的时候,衣服湿了肩膀那一片。
进电梯,按了 11 楼。电梯里有一面镜子,他看见自己头发贴在额头上。
他抬手把头发往后拨了一下。
十一点整他到家。何晚已经睡了,客厅留了一盏灯。桌上有一个碗,碗上盖着一个盘子。他掀开看,是炒面,已经凉了。
他没有热,站在灶台边吃了一半。
然后他把剩下的倒进垃圾桶,把碗洗了。
洗碗的时候他想起来一件事,他今天一整天没有看监控大盘。
他擦干手,走到客厅,打开笔记本。
登进去,第三行第二格。
绿线,平的。
他看了大概十秒,把笔记本合上。
卧室的门是关着的。他没有立刻进去。他在客厅站了一会儿,然后走到阳台上,把窗推开了一点。
雨还在下。
对面楼那户人家的窗还亮着。他站在这里看了十一个月,那扇窗一直亮着。他不知道那家人是干什么的,不知道是有人在加班,还是只是忘了关灯。
他忽然想到,也许那家人也在看他这边。
也许在那个人眼里,这扇窗也一直亮着。