这行代码有种近乎无耻的熟悉感。
深夜一点,屏幕蓝光刺眼,我不是在审查别人的PR,我只是像强迫症患者一样,浏览着GitHub上那些与我相关的开源项目的动态,就在一个边缘工具库的提交列表里,我看到了那个用户名:“Rivert”,头像是一张逆光的侧脸剪影,模糊不清,但我认得,林河的代号,从未变过。
他提交的是一个优化算法,将一段冗余的数据清洗逻辑,替换成更优雅的MapReduce模式,注释写得简洁清晰,像他这个人……曾经给人的印象,我的鼠标悬停在那个提交哈希值上,指尖冰凉,鬼使神差地,我点开了“对比视图”,绿色的增补行,红色的删除行,像一道突然撕裂旧伤疤的手术灯光。
七年前,我们共用同一台笔记本电脑,在潮湿闷热的大学宿舍里,他写核心逻辑,我负责调试和边界处理,屏幕上流淌的也是这些绿色和红色,那时候,我们认为代码是世界上最纯洁的东西,非黑即白,有错就改,运行通过就是一切,我们的关系也像一段精心耦合的代码,他是我最默契的“协作者”,我是他代码最忠实的“审查者”,直到毕业前那个燥热的夏夜,一次关于未来路径的激烈“冲突”后,他直接“推送”了所有本地修改,然后清空分支,注销了在我们所有“共享项目”里的权限,没有解释,一次干净利落的“强制推送”(force push),我被留在原地,面对着一片突然“丢失同步”(out of sync)的狼藉。
这些年,我成了别人眼中冷静到有些冷漠的资深架构师,用一层层设计模式和严谨的接口,把自己封装得很好,我写过很多优雅的代码,解决过很多棘手的问题,但没人知道,我心底始终有一个无法“编译通过”的私有函数,函数名是他的名字,而他,从这个行业里几乎消失了,听说他回了南方小城,没想到,会在这里,以这种方式,“拉取请求”(pull request)般突然出现。
提交时间是一周前,他为什么回来?为什么是这个无关紧要的项目?我点开他的GitHub主页,寥寥几个仓库,像废弃的驿站,最新动态就是这一条,没有其他线索,只有这段代码,像一封用特定密钥加密的信,静静地躺在互联网的某个角落,等待或许根本不存在的收件人。
那几天,我像个拙劣的侦探,又像个可悲的跟踪狂,我试图从代码风格里寻找更多痕迹,他习惯在if语句后加空格,喜欢用lambda表达式简化循环,甚至那个独特的、将复杂条件判断拆分成布尔函数的手法……全都还在,代码不会撒谎,它比记忆更精确,比语言更直白,这段代码在说:看,我回来了,我还是我,但除此之外,一片静默。
我失眠了,黑暗中,天花板变成巨大的显示屏,反复播放着那段代码差异,绿色的行生长蔓延,红色的行褪色消失,我开始怀疑一切,真的是他吗?还只是一个巧合,一个品味相似的程序员?或者,是我过度解读的幻觉?我需要一个“签名”,一个只有我们懂的“约定”。
我想起毕业设计,我们写过一个图像处理库,里面有个不起眼的工具函数,用来计算图片的“指纹”以快速去重,算法是我们瞎琢磨的,混合了颜色直方图和边缘检测的特征值,效率不高,但独一无二,我们戏称它为“我们的哈希算法”,那个库早就无人维护,躺在我的硬盘深处。
一个疯狂的念头攫住了我,我翻身起来,打开电脑,从旧硬盘里挖出那个落满灰尘的项目,找到那个函数,我翻出我们最后那段时间的所有聊天记录——我没删,它们像归档的日志文件一样堆在云盘角落,在一段关于晚饭吃什么的琐碎对话里,他随手贴过一张小猫的照片,说是校园里拍的,照片早就过期无法显示了,但我记得文件名。
我写了一段脚本,用“我们的哈希算法”去计算那张不存在的照片可能产生的特征值,然后将这个特征值,转换成一段看似随机的十六进制字符串,这串字符,毫无意义,除非你知道密钥。
第二天,我在那个边缘工具库的“议题”(Issues)区,新建了一个问题,标题是“关于数据清洗函数重构的一点疑问”,内容里,我一本正经地讨论了那个MapReduce实现的潜在边界情况,然后在最后一段,用看似随意的语气补充:“想到一个旧方法,不知道适不适用,附上一个参考哈希值供讨论:a7e3f8d209c1。”
点击“提交议题”,像一个将漂流瓶投入漆黑大海的傻瓜,我知道这有多荒谬,他可能根本看不到,看到了也可能不明白,明白了也可能不屑一顾,概率渺茫得像在银河系里寻找一粒特定尘埃。
三天,毫无动静,我嘲笑自己的愚蠢,试图将注意力拉回现实的工作,第四天深夜,邮箱提示音响起,是GitHub的“提及”(mention)通知,我的心跳骤停了一拍。
在那个议题下面,有了一个新的评论,来自“Rivert”。
他回复了我提出的技术问题,语气平和专业,就像任何一个开源贡献者,但在回复的末尾,另起一行,他写道:“关于那个哈希值,让我想到另一种思路,或许可以试试用这个种子数做随机初始化:195。”
195。
不是代码,不是哈希,是一个数字。
我的呼吸凝固了,那是我们唯一一次共同参加的马拉松里程数(公里),跑到三十公里处,我差点弃赛,他在我耳边喘着粗气说:“代码……代码跑一半能挂,人不能。” 我们互相拖拽着,以难看的姿势冲过了终点,那个数字,是我们之间字典里,最生僻也最私密的一个词条。
他记得,他不仅记得,他还用这种方式回应了,一种极客式的、加密的、心照不宣的回应。
我看着屏幕上那行小小的数字,良久,窗外的城市灯火流淌,像无尽延伸的数据流,我没有再回复,我不知道能回复什么,是质问当年的不告而别?是叙说这些年的各自轨迹?还是假装这只是一次寻常的技术交流?
我什么也没做,只是移动鼠标,找到了他提交的那个优化算法的文件,在最新的提交上,点击了“合并拉取请求”(Merge pull request),绿色的提示闪过:“分支已合并。”
系统自动生成了合并提交的信息:“Merge pull request #xx from Rivert/optimize-data-clean”。
他的代码,就这样无声无息地,汇入了我的项目主线。
这大概就是我们的结局了,没有戏剧性的重逢,没有长篇的释怀或控诉,只是在浩瀚如星海的数字世界里,两个匿名的ID,一次围绕代码的、静默的握手,像两段曾经紧密耦合后又被硬拆开的程序,在各自运行了无数个周期后,偶然交换了一个彼此还能识别的、特定的信号,继续在各自的分支上,异步地运行下去。
我知道明天太阳升起,我依然要面对排期、会议、无穷无尽的需求,他也将继续他的生活,或许在南方小城的某个角落,继续写着他的代码,我们不会再交谈,那行“42.195”和那个合并请求,就是全部了。
但有些东西,确实不一样了,那个在我心底沉寂多年、一直返回“错误”(error)的函数,今晚,它默默输出了一个值:“已接收”(acknowledged),不是原谅,不是和解,甚至不是理解,只是一种确认——确认那段共同写下的“程序”,真实存在过;确认那个突如其来的“异常抛出”(exception),终于被某个遥远的处理器“捕获”(catch)并安静地处理了。
我关掉电脑,黑暗重新降临,这一次,天花板上的幻影消失了,只剩下一行淡淡的、绿色的痕迹,像夜光代码,缓缓隐入意识的深空,那是合并请求成功后,系统留下的、最短的日志:
Fast-forward (快进)。
我们的时间,无法倒流回共同的“分支”,但至少,在某一刻,它朝着某个方向,轻轻地、快速地,前进了一点点,这就够了,对于两段早已分道扬镳的代码,对于两个在生活这个庞大而残酷的系统中独立运行了很久的进程,这或许已经是,所能想象的最温柔的重逢。