上个月,我把一个开源项目的源码,从头到尾讲给一个朋友听——GitHub 上六万三千多个星, Stack Overflow 的年度开发者调查里常年有它的名字。讲了四十分钟,他没睡着。
这事搁半年前,我自己都不信。其实吧,半年前的我连运行环境都是照着教程抄的。
真的。
仓库叫 Express , Node.js 圈里的老前辈。第一次 clone 它是两年前——点开 lib 文件夹,扫了一眼 application.js 里两千多行的代码,鼠标自己就溜了,典型的当场劝退。
关掉。
第二次是 Vue 的源码,第三次直接挑战 Linux 内核。三次,全摔在同一个地方:我以为读源码得像读课文,得从第一行啃到底,读懂才算数。
现在想想挺离谱的——代码又不是课文。凭什么非得顺着读?谁规定的?没人。
这个想法,坑了我两年。
为什么前三次都失败了
先交代背景: Tidelift 这家做开源治理的公司, 2021 年调查过约两千名开发者。
结果挺扎心:大家真正写新代码的时间只占 32%,花在维护现有代码上的有 19%——注意,维护的多半是别人写的代码。
也就是说,读陌生代码不是什么业余爱好,是本职工作,躲不掉的。
可没人教怎么读。
2011 年 V2EX 上有个老帖,楼主问:你们都是怎么读陌生代码的?底下有人回了句大实话——总不至于有人一边喝咖啡,一边像读小说那样躺着读代码吧。
十几年过去,答案没变。说白了,没有舒服的姿势,只有省力的路线。
可笑的是,我偏偏挑了最费力的走法:试图占领每一个山头,连土坡都不放过。侦察兵不该这么打仗——上来就跟整个军团对线,纯属扯淡。
第一步:先让它跑起来,一行都别读
这次学乖了。我从博客园一篇方法文里偷了个思路,原文说得直白:挑一个主要功能调试它,找到触发函数,再往深处走。
我的版本更糙——先把官网的 hello world 跑起来再说。教程?先不读。
五分钟的事。 npm install 一敲, node app.js 一跑,浏览器一刷新,屏幕上蹦出 Hello World 。
就这么个小玩意儿,价值比我后来读的所有教程加起来都高。它给了我一份活的地图:请求进来了,响应出去了,中间那条看不见的路,就是地形本身。
选仓库也有门道。别上来就挑战几千万行的巨兽,从 Lodash 、 Express 这种小而美的项目起步——工具库逻辑短, Web 框架脉络清楚(这也是那篇文章给的建议)。这不叫胆小,叫侦察兵不跟军团硬碰。
第二步:盯住一条完整的路,其余全是迷雾
有了活地图,第二步是在 app.listen() 那一行打断点,然后在浏览器里按一下回车——让 VS Code 把整条调用栈摊开给你看。
说实话,第一眼我是懵的。一层套一层,函数名长得跟天书似的。
懵完有个问题冒出来:这样盯着一条路看,真的够吗?
够。因为问题变小了。以前我想看懂每一行,现在只想回答一件事:一个请求进来,经过谁的手,怎么变成响应出去的?至于兼容层、边界处理、第三方适配——统统先当作不存在。想一遍吞下几万行代码?那不叫学习,叫自欺欺人。
带着一个问题往下钻,迷雾自己就散了一半。
阿里云开发者社区有位写 Java 的作者三友, 2023 年总结过 18 条读源码的心法,其中一条我记得死牢:顺着 demo 读。他拿 RocketMQ 打比方——想知道消息怎么发出去,先写个发消息的 demo ,再钻进 example 模块顺藤摸瓜。
类名也是线索。以 Registry 结尾的大概率存着单例, Event 和 Listener 结尾的多半是观察者模式。这些命名习惯像地图上的等高线,看不懂的时候眯一眼,能猜出七八分地形。
嗯,猜错了也无所谓,回头修就是——地图本来就是边走边改的。
第三步:亲手把它改坏
改坏它?对,故意的。
我在 Express 的路由层插了一行 console.log ,把每个进来的请求路径打出来。 Chrome 里一刷新,日志一行行滚过去——那一刻有点奇妙,黑盒子突然开口说话了。
这一步有个陷阱得提前说:别把「看懂」当目标。目标只有一个——敢动它。
再狠一点的玩法:故意改坏一处,看报错从哪儿冒出来。
比如把两个中间件的注册顺序对调一下,跑一遍,观察哪里先炸。 Express 的中间件按注册顺序执行,这是官方文档写得明明白白的行为——所以报错冒出来的位置,会直接告诉你这条链路上谁依赖谁,比任何架构图都诚实。
这一手像佯攻:打一下,看敌人在哪儿冒头。
那篇《如何阅读开源项目代码:六步法》里有句话,我抄下来贴在显示器边框:「千万不要一上来就死扣细节,那样你会被折磨的很惨。」
改坏代码,就是最好的防折磨疫苗。理解全部是个伪目标,你真正要做的,是把认知负荷拆小——一次只啃一个模块。
后来我看账本的方式变了
两周下来, Express 的核心链路我能白板画出来了。不算精通,但从「打开就困」到「能给人讲明白」,这一步我跨了两年。
真正让我心里一沉的是另一笔账。
Sonar 在 2018 年调查了近 300 名开发者:平均每人每周花 12 个小时做代码维护; Stripe 更悲观,他们估算是 17.3 小时,其中 13.5 小时耗在技术债上。
按一周工作 40 小时算,将近三分之一的时间,泡在别人的代码里。
其实吧,最贵的还不是时间,是你明明在读、大脑却在空转的那种糊弄感。
这么贵的投入,配得上正经打法,光囤教程属于零元购式的自我感动——收藏一百篇《源码解析》,然后看着它们在收藏夹里吃灰。
Linus 当年在邮件列表里撂下一句: Talk is cheap. Show me the code. 我现在觉得这话还有下半句——想读懂别人的 code ,光盯着看没用,你得把手弄脏。
如果重来,我会这么排顺序:
第一周,只干两件事——跑起来,打断点。别贪,贪了必糊弄。
第二周,改三处代码,画一张调用图,丑没关系。
第三周以后?随便你。反正地图在你手里了。
一个月后回头看第一遍让你发怵的地方,大概率会笑出声——当初怎么就被几千行代码吓成这样?想想都可笑。
怕它干嘛。它又不咬人。
夜雨聆风