算法无错
% l/ p: M9 n. s3 \) M x0 `我认识老范,是在一家把“用代码温暖世界”刷在墙上的公司。这地方到处都是彩色的豆袋沙发和免费的燕麦拿铁,年轻人也老是穿着印有古怪口号的T恤走来走去,空气里弥漫着一种廉价的乐观主义气息。老范在这里,就像一滴油掉进了清水里,格格不入,但又顽固地保持着自己的形状。 " q! f1 K% c, T$ B
他叫范理,但我们都叫他老范。他大概五十岁,头发是我们这个行业里罕见的、没有过早投降的类型,只是在鬓角处一丝不苟地白了。他不像我们,他从不穿那些T恤,永远是一件领口洗得发硬的Polo衫,颜色限于蓝、白、灰三种。他有一种独特的本事,能把任何一张符合人体工学的办公椅,坐出一种在冷板凳上反思人生的感觉。
/ y) J3 Q) a9 G5 J* \% B5 s老范的世界是纯粹的,由“if...then...”和“0与1”构成,清晰、有序、不容置疑。但他家,就是他那个纯粹世界的第一个、也是最顽固的bug。
; c7 v+ b3 A5 t8 C$ J我去他家做过客,就一次,但印象深刻。他家在个老小区,楼道里堆着邻居家的杂物和小孩的破自行车,空气里永远有股饭菜、油烟和庸常生活混合在一起的、无法被算法优化的味道。这些东西,在老范眼里,都是亟待重构的“遗留系统”。
, K7 ^6 B* @ u& y4 N他老婆文娟,就是这个“系统”的首席维护官。文娟是个实在的女人,她的逻辑很简单:灯不亮就换,马桶堵了就通,儿子不高兴了就哄。她的人生,是一连串具体的、必须立刻响应的“高优先级中断请求”。 4 d# ^# b9 j" f
那天,我正坐在他家客厅,听老范阐述“纯函数”在生活中的美学意义,卫生间里传来滴滴答答的声音。文娟从厨房里探出头,围裙上还沾着面粉。“老范,”她喊,“水龙头像得了前列腺炎一样滴个没完,你那个德国进口的工具箱呢?拿出来给它做做手术啊。”
]0 s3 u( y. O8 Q6 T0 ~1 i# A老范皱起了眉头,仿佛一个精密的计算过程被强行终止了。“我在阐述一个重要的概念,这是高优先级任务。”他朝卫生间的方向摆了摆手,“那个水龙头,它的故障模式不符合逻辑,你先用个盆接一下,等我找到它的根源,设计一个一劳永逸的解决方案。” / w* O* k) j5 i+ O6 d- |
他所谓的“一劳永逸”,通常就是等文娟自己找楼下的王师傅花五十块钱搞定。然后他会走出来,看着修好的水龙头,用一种惋惜的语气说:“暴力修复,治标不治本,没有一点工程学的美感。”
+ z$ I# Q/ e3 c A% c1 Q他儿子小远,就在这种“美感”和“实用”的夹缝里长大。那天,小远正上小学,在饭桌上写作业。老范凑过去看了一眼,立刻进入了“代码审查”模式。 “你这个解题步骤太冗余了,”他指着小远的数学练习册,“你看,这里可以抽象出一个公因子,封装成一个函数,减少三次重复计算。效率,小远,逻辑的本质是追求效率!你这样写,既浪费纸,又浪费时间。”
* b9 R4 d0 ` V; K小远当时手里捏着支铅笔,抬起头看着他爸,眼神里充满了我们后来都熟悉的那种,面对一个无法沟通的系统时的茫然和绝望。老范试图把儿子也变成一个“程序”,一个可以被优化、被重构的“子进程”。他没意识到,他儿子不是进程,是个人。人这东西,最不讲效率,也最恨被人当成效率问题来处理。 老范在我们公司是“活化石”,一个古典主义的遗老。在我们这群信奉“快速迭代、敏捷开发”的游击队员眼里,他是个堂吉诃德,挥舞着他那本厚得能砸死人的老版本的《算法导论》,独自对抗着我们制造的“屎山”风车。他不说“代码”,他说“程序”;不说“功能”,他说“实现”。他认为程序本质上应该是一首十四行诗,是巴赫的赋格曲,是逻辑的终极之美。而我们写的玩意儿,在他看来,不过是一群猴子在键盘上乱敲一气,偶尔碰巧能运行而已。
, V0 E4 v" [. V* s他身上有种宗教般的虔诚。每当他要剖析一段他认为有问题的代码时,他会先用一块专门的绒布,极其缓慢地擦拭他的眼镜片,那神情,仿佛不是要看代码,而是要通过水晶球洞悉宇宙的奥秘。然后他会戴上眼镜,凑近屏幕,发出一种介于叹息和呻吟之间的声音。那声音里充满了痛苦,不是对写代码的人,而是对这个被玷污了的、本应纯洁的逻辑世界的痛苦。 # H9 n5 m5 h( c6 G; h
第一幕:神圣的“邻里宝”与渎神的张大妈
$ |' Y3 K8 x g0 P公司为了提升企业形象,接了个公益项目,给附近一个老社区开发互助App,名字起得又红又专,叫“邻里宝”。逻辑简单得像一句废话:张大妈家的灯泡坏了,发个单;王大爷闲着没事儿,就去帮忙拧上。在我们的产品经理看来,这活儿最多值两个实习生一个星期的工时。
; o: ]- ^7 C. o- ^9 B6 f但老范把它变成了他的奥斯特里茨战役。
. O+ A* H% L G2 s他把这个小小的App,当成了一个构建“理想社区”的社会学实验。他拒绝了我们提出的所有“简单粗暴”的方案,坚持要从底层构建一个“可以自我调节、具备道德仲裁能力的完美架构”。他花了整整两个月,把自己关在会议室里,白板上画满了我们谁也看不懂的流程图和状态机。那东西与其说是架构图,不如说是一幅神秘主义的星盘。
6 J+ d" X } w* ^& { f这套架构的核心,是一个被他命名为“德行引擎”的算法。它的工作原理,是给每个用户建立一个隐藏的“贡献值”。你帮别人越多,分值越高;你求助别人越多,分值越低。这个算法复杂到变态的程度,它甚至会根据求助内容的“技术含量”和“紧急程度”来加权计算。比如“换灯泡”的求助,扣分就比“求人陪着去医院”要少。 1 M6 B L2 D# z6 y7 b/ C
在项目评审会上,老范站在投影仪前,像个布道者一样,阐述着他的“数字乌托邦”。“我们不能让善良被滥用,也不能让懒惰占便宜。”他挥舞着手臂,唾沫星子在光柱里飞舞,“‘德行引擎’会像一只看不见的手,引导社区的道德风尚走向一个最优解!” ! J- k! N$ E. w( f
我们面面相觑,没人敢说话。产品经理张了张嘴,想提一句“字体放大”,但看着老范那张被神光笼罩的脸,又把话咽了回去。
/ T4 o& T1 J) k* bApp如期上线。第一周,相安无事。第二周,那只“看不见的手”终于伸出来,给了所有人一记响亮的耳光。
5 B8 ^: h5 k: y8 r* C. u( l1 K社区里有个张大妈,快九十了,独居,一条腿前年摔断过,走路离不开拐杖。她成了“邻里宝”最忠实的用户。一周之内,她求人帮忙带了三次菜,通了一次堵住的马桶,还问有没有人能帮她把窗台上的花盆搬下来。然后,灾难发生了。 - W1 d% b' C, E9 p; Q' |+ l; A
老范的“德行引擎”精准地识别出这个“只索取,不贡献”的“劣质节点”。系统自动将她的信用分降到了最低。当她再次颤颤巍巍地举起手机,试图发布一条“燃气灶好像没气了,谁能帮我看看”的求助时,屏幕上弹出一个对话框,字体是系统默认的、小得像蚂蚁一样的尺寸:“尊敬的用户,您的社区贡献值过低,暂时无法发布新需求。建议您先通过完成‘帮助他人’任务来恢复信用等级。”
4 r& o) H# ^) E7 v![]() 这件事的后续,就像一场失控的洪水。张大妈不识字,她求助邻居,邻居是个热心肠的大嗓门,半小时内这事儿就传遍了整个社区。一个本应“温暖世界”的App,把一个最需要温暖的老人,像垃圾一样给分类处理了。愤怒的电话打爆了公司的前台,当地的晚报用半个版面报道了这起“算法羞辱独居老人”的事件。
, F+ I. e# k% e2 H4 i% q, c6 p在紧急召开的复盘会上,老板的脸黑得像锅底。所有人都低着头,准备接受审判。只有老范,他像一尊顽固的雕像,在所有人的沉默中站了起来。他走到白板前,拿起笔,指着那幅复杂的星盘,脸涨得通红,声音因为激动而微微发颤: “我的算法没有错!是这个样本有问题!是她,破坏了整个模型的平衡和美感!一个完美的系统,不应该为了一个异常值而否定自身存在的价值!”
n3 C: i& }: N, |2 e; C![]() 那一刻,会议室里死寂一片。我看着他,忽然觉得他不是在为自己辩护,他是在捍卫他的神。他的神殿塌了,他能做的,就是指着废墟中央那个不肯挪窝的张大妈,控诉她才是那个唯一的、不可饶恕的异教徒。
& d* n8 `1 h; c, m1 G& ~4 g第二幕:父子关系的重构与一份冰冷的性能报告0 S2 O; f" a2 i4 U% E7 x# b2 R" m1 F
“邻里宝”事件后,老范被彻底打入了冷宫。他被调离了所有核心项目,工作内容变成了给旧代码写注释和文档——这对于一个视代码为生命的程序员来说,无异于让他去给尸体化妆。一个战败的将军,被剥夺了兵权,只能在故纸堆里,给前人的战役图做批注。他的战场,悄无声-息地从公司转移到了家里。他的新对手,是他那个正值青春期的儿子,小远。 $ S( U5 X( p* H+ S% `! b/ n
小远的问题,在老范看来,是一个典型的“逻辑谬误”。他迷上了一个叫“星野玲奈”的虚拟偶像,一个由顶尖CG技术和声优技巧合成的、不存在的女孩。小远管她叫“老婆”,为她花了大量的零花钱,房间里贴满了她的海报。在老范眼里,儿子正在对一堆精心渲染的多边形和预设好的音频文件,投入一种完全非理性的、不产生任何实际回报的情感。这简直是人性的“重大bug”。 3 F" ]* E" r# w- Z+ ? F+ C
他决定修复这个bug。
/ F5 d5 |4 Y0 j& V' U但他不知道,或者说,他那套非黑即白的逻辑系统无法处理一个事实:小远不是在单向地“崇拜”一堆数据,他是在一个新世界里,用他自己的方式,成为了一个“程序员”。 + x- A) P: Q3 Y
这件事,是我很久以后才零零星星拼凑出来的。小远从小就被他爸用《算法导论》当睡前故事念,被逼着用“流程图”来规划暑假作业。结果就是,他对那种刻板的、学院派的、追求“数学之美”的编程产生了生理性的厌恶。但他骨子里,流着老范的血。他对逻辑和构建,有一种与生俱来的敏感。他只是需要找到一个不属于他父亲的、全新的战场。 9 B, h4 y% X' w! }
那个叫“星野玲奈”的粉丝社区,就是他的战场。那是个混乱、热情、充满了“野路子”智慧的地方。在那里,没人关心你的代码是否“优雅”,只关心它是否“管用”。小远,这个在家里被他爸当成“待修复bug”的少年,在那个世界里,是个“大神”。他自学了Python,写脚本帮大家抢演唱会的门票;他用爬虫抓取数据,分析偶像每次直播的弹幕词云,预测下一次活动的主题,准确率高得吓人。他为那个社区写的小工具,被人夸“牛逼”,被人真心实意地感谢。 他用他父亲最看重的“技术”,在一个他父亲最鄙视的“非理性”领域,找到了自己的尊严和乐趣。他构建的不是冰冷的教堂,而是一个热闹的、充满了人间烟火气的草台班子。这是一种复仇,也是一种自我救赎。 * r) T. b) v7 c6 x' T# U; L% ]0 B
老范对此一无所知。他就像一个正规军的将军,带着地图和沙盘,去剿灭一片沼泽里的游击队。他不知道,那里的每一个人,都熟悉每一寸泥潭,懂得如何用最简陋的武器,在最不可能的地方,给予致命一击。 / r n, g+ o0 y, h: J: q+ q
他花了一个星期,几乎没怎么睡觉,炮制出了那份长达三十页的PDF报告——《关于虚拟偶像“星野玲奈”的非理性崇拜现象及其潜在风险的量化分析报告》。
5 k' ~, P" ]* ?) T: ^周六晚上,他把小远叫进书房,打开投影仪,像在公司做项目答辩一样,冷静地、一条条地,用数据和图表,剖析着儿子的“愚蠢”。他以为这是一场降维打击,是一场文明对野蛮的审判。 a/ y% [8 b) I8 n: P, ^
但他错了。小远从头到尾都异常平静,他看着墙上的图表,就像在看一份与自己无关的天气预报。那不是因为他不在乎,而是因为他看懂了。他看懂了父亲的逻辑,看懂了父亲的武器,也看懂了这件武器的脆弱。 % R+ e! c' i5 S9 ?
长达一个小时的“逻辑陈述”结束后,小远点了点头,说:“爸,我明白了。你的分析很有道理。” 1 L; Y+ n* n5 K+ p
老范松了一口气。他以为他赢了。他用无懈可击的逻辑,兵不血刃地“疏通”了儿子情感世界的“洪水”。 9 p8 ?; Y0 u* D4 u# u! a
一个星期后的同一个时间,小远把他叫进了书房。这一次,是小远打开了投影仪。幕布上出现了一个PPT,标题是:《关于“父亲”这一角色在家庭系统中的行为模式分析与性能评估报告》。 * S" ]3 Y% P; y" \
小远站在幕布前,用和他父亲一模一样的、不带任何感情的语调,开始了他的“答辩”。他用的所有术语,所有图表,都完美地复刻了老范的风格,甚至做得更精致,更无懈可击。 ( M3 c! W' u' t8 {7 C& h. o
“根据过去十五年的行为数据采样,”他按动着翻页笔,一张张图表在墙上切换,“‘父亲’这个角色,在‘情感沟通’模块的调用成功率低于5%。在‘共情’函数的响应时间上,平均延迟超过72小时,且经常返回空值或错误代码。”
: N9 p' Y0 ]8 p“在‘陪伴’功能的实现上,存在严重的资源分配不均。工作日平均调用时长为7.3分钟,周末则被‘个人项目’高优先级抢占,导致长时间的进程阻塞。” # r3 E. a4 h* E- B, G/ W
“综合评估,”小远看向他的父亲,目光平静得像一潭死水,“该角色的‘人性化交互’性能评级为:不合格。存在大量冗余的‘说教’进程和缺失的‘倾听’接口。”
$ F V$ D+ ]& m: R0 Q6 I+ S他做出了最后的总结:“爸,你的逻辑是对的。一个有缺陷的、不断产生负面反馈的模型,最理性的选择就是放弃。从今天起,我将停止向你这个‘情感服务器’发送任何新的请求,以避免造成双方系统的进一步资源浪费。” % L0 s6 v$ \) u V: s5 B$ u& {+ S+ l
![]() 说完,他关掉PPT,走出了书房,轻轻带上了门。
8 |* B: I8 l$ h老范一个人坐在黑暗里,面对着那面白色的墙壁。他那由0和1构筑的、坚不可摧的信仰大厦,在这一刻,无声地崩塌了。他赢了世界上所有的道理,却输掉了他唯一的儿子。他亲手把儿子训练成了一个最优秀的战士,但这战士的第一个战利品,就是他自己的头颅。 4 E* i1 X0 S8 l1 f) i& W; B
第三幕:二进制的陵墓与来自“用户”的问候
$ p& ~9 w8 ?( |5 ~从那天起,老范就从我们的世界里“死”了。他办了离职,把自己锁进了房间。我们听说他和他老婆也分居了,他儿子上了大学后,就再也没回过家。他像一个自我放逐的僧侣,切断了和这个混乱、非理性的世界的一切联系。
. X8 U, p* K" N6 Q0 X+ r( _- V0 v![]() 我以为他会就此沉沦,变成一个终日与酒为伴的、油腻的中年男人。直到有一次,我为了查找一个技术问题的解决方案,鬼使神差地逛到了一个全球最大的开源代码托管平台。在那里,我看到了一个ID:“FanLi-Praxis”。Praxis,在古希腊哲学里,是“实践”的意思。一个充满了讽刺意味的名字。 / t& O( V9 }4 t4 P1 n
我点了进去,然后被我看到的东西震住了。
8 F; m) ~5 C2 h1 w9 V8 E) ?他正在做一个项目,一个宏大到荒谬的项目:FOS(Fan's Operating System)。他在用最原始、最繁琐的C语言,从零开始,一个字节一个字节地,构建一个完全属于他自己的操作系统。
/ |0 A1 h+ L' i$ l! F那不是一个给任何人用的东西。它没有漂亮的图形界面,没有网络协议栈,甚至不支持多用户。它只有一个黑色的屏幕和孤独闪烁的白色光标,像宇宙诞生之初的虚空和奇点。这是一个绝对纯净、绝对有序、没有用户、没有需求、没有那些乱七八糟的人性“bug”的数字王国。 7 W; J Q- H* P; O' y2 [0 O
我忽然明白了,他不是在写代码,他是在用二进制,为自己修建一座陵墓。一座完美的、永恒的、但也是毫无生机的陵墓。
$ k! R* X( |# Y" y& p, A1 c8 i4 Z我像个偷窥者,一个数字时代的考古学家,开始默默地关注这个项目。他的代码提交记录像心电图一样规律,每天凌晨四点,准时更新。那代码写得像艺术品,注释清晰,逻辑严谨,每一个函数都像精雕细琢的钻石。我能想象出他独自坐在黑暗里,屏幕的幽光照亮他那张不再有任何表情的脸,只有手指在键盘上飞舞,构建着他那个完美的、永恒的、却也毫无生机的世界。 6 b1 i/ ?5 M* I+ R9 W
他就这样,在自己的陵墓里,安安静静地“死”了一年。
2 s& r5 {3 ]$ \& x6 X" G直到有一天,我照例打开那个项目页面,却看到了一个意想不到的变化。在项目的“Issue”(问题反馈)板块,出现了一个新的,也是这项目诞生以来的第一个Issue。 2 N( r8 f# s. `6 {& I' j9 a l) @
提交者的ID是:“Yuan”。远。 8 X4 q+ G+ q/ _( L1 ^1 |
Issue的标题写着:“在内存管理模块,当一个子进程向父进程请求的内存块大小恰好为某个巨大的素数时,有极低概率(理论上约为1/2^32)导致父进程的堆栈指针发生单一位的寻址错误。”
3 R2 M6 i6 y5 d) [& S- I' D9 S& |![]() 下面是长达数页的复现步骤、核心转储文件分析和代码片段,分析得冷静、深刻、无懈可击。我后来把这个问题拿去问了真正的大神,大神告诉我,要发现这个bug,你不能只把它当成一个程序来测试。你必须像它的创造者一样去思考,去理解他每一个设计的选择,甚至他每一个隐藏的偏执。你需要付出巨大的、枯燥的、近乎于信仰的努力,去寻找一个几乎不可能存在的瑕疵。
/ R9 y- z; H* W! ^2 P' [1 z这不是一次挑衅,更不是炫耀。这是一个“用户”,在向“开发者”,提交一份全世界只有他们两个人能看懂的bug报告。
( T$ e: _5 O. q我盯着那个Issue,看了很久很久,忽然间,我好像明白了什么。小远没有去砸开父亲那座陵墓的门,他找到了唯一能进入那座陵墓的钥匙。他用他父亲教给他的、信仰的、也是最终摧毁了他的语言,跨越了那个由逻辑和自尊筑成的鸿沟,进行了一次无声的对话。 7 t6 _: U. ~2 l* n2 ]
这份bug报告,是这个笨拙的儿子,能想到的、最温柔的问候。他仿佛在说:
+ ?. k$ O" m' T“爸,你的世界,我看懂了。但是,这里有个bug。” 三天后,老范更新了代码。在更新日志里,他修复了那个几乎不可能被触发的bug。版本号从v0.9.1,变成了v0.9.2。 在更新说明里,只有两个字,言简意赅,像他所有的代码一样: “收到。” 7 g/ H7 c2 r+ b$ v6 C! w
我看着那两个字,忽然觉得,老范那句始终没有问出口的、在他心里盘旋了无数个日夜的“算法无错,为何输出为谬”,终于在这一刻,得到了回答。
+ ^0 c2 k7 B3 V; R8 J. i& P7 o算法没有错。错的是,它妄图去计算世界上唯一无法被计算的东西。而当它彻底失败,把自己封进一座冰冷的坟墓时,能将它唤醒的,恰恰是另一个来自人间的、同样不合逻辑的、充满了爱意的“bug”。
8 O" {9 [" s* Y2 ]这真他妈的……既荒谬,又温柔得让人想哭。
5 E8 D, Z$ n; [( i( d5 F) W2 Q |