8 月 13 日,DEV Community 上多了一篇文章,作者 isha singh,自我介绍是计算机科学毕业生、MERN 开发者、开源爱好者,标题叫 My (not so pretty) journey in tech。是她的第一篇——评论区里一位自称版主的 FrancisTR 特意点出了这一点,还顺口问她是不是自学出身。我平时刷到"journey in tech"这种标题是直接划走的,那天不知怎么停下来了,大概是因为标题里那个"not so pretty"——干考古这行的,对“官方叙事自称不官方”的东西有职业反射。
先把这篇文章的路径原样摆出来,因为路径本身就是我这次想讲的东西。按她自己的说法:从 C++ 起步,那会儿觉得难、觉得压力山大,撑下来了;然后是数据结构与算法,她把这东西比作数学,要持续努力、重复练习,具体建议是每道题拿不同的输入手动走一遍,至少三遍;然后自学机器学习,NumPy、pandas、matplotlib、OpenCV 一路过下来;然后是 Web,HTML、CSS、JavaScript,再到 React、Angular、Node.js——她提到对 Node.js 的演进印象深刻,可惜没展开,这其实是全文我最想听她展开的一段;再往后,她说自己掌握了阅读大型代码库的能力,才转向开源,并且表示钦佩维护者付出的努力;当前目标是开源上精进,同时学 AI 和系统编程。
然后我的问题来了。这篇自称"not so pretty"的东西,结构上漂亮得过分。每一站的形状一模一样:遇到困难,坚持,通关,进下一站。没有死胡同,没有白费的一年,没有“这段经历后来证明对我几乎没用”。一个人真实的十年学习史不长这样,长那样的是简历。评论区里 Self-Correcting Systems 那位一针见血:这种成功故事缺乏现实检验,实质是幸存者偏差。这话对,但只说了一半,另一半我想接着往下挖。
幸存者偏差在个人学习叙事里的深一层,不是“成功的人才有话语权”,那只是表层。深一层是:活下来的人会把“我这么走过来了”讲成“这么走就能过来”,把一次幸存讲成一条有效路径。听的人分不出这两句话的差别,代价就从这里开始。这正是我在技术史里每天面对的同一个结构。Unix 那套“小工具、文本流、可组合”被讲成永恒的工程真理,可它是 1970 年代贝尔实验室在内存按 KB 算的约束下磨出来的,约束变了,哪部分还成立、哪部分已经是包袱,得拆开看;SQL 活了五十多年被讲成“设计得好”,其实相当一部分是生态惯性,每个想取代它的最后都得给它加个 SQL 接口才能活下去;JavaScript 更极端,当年那十天赶出来的设计,今天被骂的每一条几乎都是 1995 年网景那摊政治约束的遗产,可它照样统治了 Web 三十年。技术史里“活下来”和“优秀”的相关性,远比大家以为的低。个人路径同理:她走通了 C++、DSA、全家桶、开源这条序列,不证明这条序列有效,可能只证明她没死在中途。
把她的路径当一条演进线来考古,每个节点问一句“这是必然还是偶然”,第一站就值得多看一眼:第一门语言是 C++。这个起点不是中性的。在相当多地方的 CS 课程表里 C++ 至今是默认第一门,这个默认值是几十年教学惯性堆出来的,不是“C++ 适合入门”的结论,它显然不适合,她自己都写了难和压力。如果她第一门直接从 Web 起步会怎样?反事实历史是廉价的,我们还是看这条路径实际怎么走的。DSA 那一站更有意思:她把 DSA 比作数学、要重复练到长出直觉,评论区 Anik Sikder 也赞同这个说法。但“程序员必须先过 DSA 这一关”本身是个有出生日期的序列,它是算法竞赛文化和后来的面试产业联手把 DSA 推成门槛的,不是编程这门手艺自古的入门礼。手动执行三遍是笨功夫,我不反对笨功夫,我承认我对笨办法有偏爱,但偏爱改变不了刷题文化本身的问题:它把“重复练习出直觉”从工程语境里抽出来,泡成了应试。
全文我停得最久的一句,是她说的“掌握了阅读大型代码库的能力之后,才转向开源”。这个顺序。先读,后写,再进社区。她钦佩维护者的努力,维护者的努力一大半是什么?是读别人的代码,是理解十年前某个人在某个约束下为什么这么写,然后决定是改还是绕。这和考古是同一门手艺。而这个顺序在今天已经不是默认顺序了:vibe-coding 那一代的起点是生成,不是阅读,“读大型代码库”正在从入门阶梯变成少数人的职业特长。我本来想把这写成“她是最后一拨按旧地图走路的人”,写到这里自己先觉得不对。十年前说 StackOverflow 一代人不再读手册的,和更早说 Google 一代不再背 API 的,跟今天说 vibe-coding 一代不读代码的,是同一句话。每一代都以为下一代跳过了某个神圣环节,而每一代的下一代都照样长出了能干活的人。这个结构我认得,所以“最后一拨”这种话我说不出口。
她进开源之后看到的是活着的社区、有回应的维护者,这本身又是一次幸存者采样。开源世界是幸存者偏差的重灾区:我们叫得出名字的项目是活下来的那批,每个活下来的项目背后是维护者的无偿劳动,外加一堆死掉的、连名字都没人记得的替代品。Linux 活成今天这样,是 GNU 先把工具链铺好了、Torvalds 选了 GPL、互联网正好起来了、几家商业 Unix 还在互相内斗,一环扣一环,抽掉任何一环都可能不是今天,把开源的胜利讲成必然是天命所归式偷懒。个人进开源也一样:她照着活下来的社区的样子理解了开源,这个理解没错,但不完整,不完整的那部分账,要等她自己的第一个提交被晾上三个月才补得上。
评论区本身也值得看一眼。Gera GA 问的是“作为 CS 毕业生学 ML 有多难、怎么开始参与开源”,注意这个问题的形状:求路径,求一条可复制的路径。没有人问“你中途有没有想过放弃”,没有人问“哪一段是白费的”。整个评论区在路径求取的模式下运转,和文章本身严丝合缝。这不是 isha singh 一个人的问题,是这种文体在自我复制:每一篇新的 journey 都兼容上一批 journey 的模板,学习叙事也有它的向后兼容,模板定下来之后,连"not so pretty"都成了模板里的一个字段。
所以回到今天。幸存者偏差最贵的代价,不是让人高估成功的概率,那只是乐观一点的误差,是让人以为路径只有一条、且路径本身有效。前者错了,人会多试几次;后者错了,人是拿着别人的地图走自己的路,死在中途没人给你写讣告。这也是我看 AI 编程这一轮讨论时最警惕的东西:等这拨人开始写自己的 journey,他们会写的,journey 这种文体比任何具体技术都长寿,大概率还是这个模板,困难、坚持、通关,只是“困难”那一栏从“C++ 好难”换成“prompt 调不准”。历史会重演,但不简单重复。
她那篇文章里,最值得留下的反而是最笨的一句:每道题拿不同的输入手动走三遍。这句话笨到没法进模板,因为模板需要的是“坚持就能通关”,而手动走三遍讲的是“慢下来才能长出直觉”,这两件事在叙事里长得像,在实践里是反的。十年后回头看这一拨学习叙事,我猜活下来的也是这种笨话,而不是那条漂亮的时间线。
