作为一名程序员,总有一些时候,会对自己所做的重复性的工作感到厌倦,也会羡慕明星项目做得热火朝天 Star 数蹭蹭上涨。而读代码,则是缓解焦虑的良方。
每当读懂软件的精彩设计,赞叹优美整洁的代码,甚至发现藏在注释中的彩蛋时,都好像在不同的时空与作者产生了交叉,畅快地聊了会儿天。
读代码很有趣,但要读通读懂也很费功夫。本文是我在日常读代码中积累的一点心得,分享出来,希望能与大家产生共鸣。
1. 寻找一位好老师优秀的项目就像一位好老师,我们可以从它身上全方位地学到各种领域知识。
不过在开始读代码之前, 最大的问题就是:怎么样才能找到合适的代码项目?
Star 数高的项目更优秀吗?从某些角度讲的确是的,但是在 gitstar-ranking 上, 4k 个 Star 的 Repo 只能排到第 5000 名,而至少有 50k 个 Star 才有可能排进前一百。光看 Star 数,这项目太多了根本选不出来啊。
在我看来,抓住如下几个方向,一般就能筛选到合适的项目了:
兴趣使然
首先就是一定要选自己感兴趣领域的项目。
不少代码片段都是比较枯燥而难以阅读的(比如“飞一般”的位操作,为提升性能而莫名其妙的语句,或是包含了大量隐含知识等等),只有自己感兴趣,才会有读下去的意愿和动力,才能在其中发现乐趣。
有时候我们开始读代码的契机就单纯只是在工作当中用到了,想要进一步了解其原理和设计,这是一个不错的起点。想必很多同学第一次看源码都是因为一层层追到了 Spring 的 Class 里面去了吧。
有的时候可能就是觉得某项技术很神奇,像魔法一样,越是猜不透,就越想了解它是怎么“施法”的。
总之一旦有了兴趣,就会很想进一步去了解它。不过,如果读到一半又失去了兴趣,也请大胆放弃它。失去了这一片草丛,还有整个树林等着我们去探索。
经典且被大量使用
经典的、拥有大量用户的项目,经历了时间的考验,不断地迭代,通常在设计上都有很多出众之处。
经典项目的维护者一般都是非常资深的工程师,并且也都会有大公司赞助,确保了代码的高质量。这类项目在阅读的过程中能学到很多知识,包括架构抽象、性能优化、工程化等等。
比较常见的典型的项目有如:Go、Kubernetes、MySQL 等等。
合适的规模
代码量太过庞大的项目,有时虽然很出名,但难免令人生畏。实际上可以找到很多行数不多,但依然精彩的代码库。
首先就是各种语言的标准库,比如 Java 的 Stream、Lock 的实现等。另外也有不少开源的小而美项目,比如 redis、leveldb 等。甚至,许多经典大学课程里面的 Lab 也隐藏着优秀的代码,比如 xv6。
总之,这一类代码可能几天或几周就能大致看完主干,特别适合学习设计思想。
2. 先看文档选定了项目,我们就差不多能对它有一些浅尝辄止的了解了。
这时候,先不要直接 Clone 代码。代码完整地包含了所有知识,但也将细节毫无保留地暴露出来,直接进到代码里面很容易迷失方向。
对于事物的理解,从全局到部分,从抽象到细节才是一个比较容易让人接受的过程。
成熟的项目通常会有比较详尽的文档,文档一般分为两类:给用户看的使用文档,和给贡献者看的开发文档。
了解概览
通过阅读使用文档我们能快速地了解到项目创立的目的、解决了哪些问题,以及从用户的视角看该软件是什么样子的。除了看 overview,我也会大致关注配置,通过必填配置可以进一步了解软件的依赖和外部特性。
以 TiDB 为例,它的使用文档截图如下:
从左侧边栏能了解到使用文档的结构包括了简介、部署、配置、参考等部分。这些部分都是使用者最关心的内容。
架构和模块
优秀的开发文档一定会包括整个软件的架构模型,和关键模块的设计。
通过阅读架构图和高层设计,软件的原理以及解决问题的思路一目了然。对于有一定经验的读者甚至可能看到架构设计后就已经大概知道软件的工作流程了。
上图是 TiDB 开发文档截图,我们发现它不仅包含了架构设计,还事无巨细的告诉读者如何启动代码、怎样贡献、详细的设计流程等等。
除了架构设计,比较完善的开发文档也会包含关键模块的信息。关键模块可能会涉及核心逻辑的设计和数据结构,以及边界处的契约和交互方式等。
对于 Go 语言这种持续演进的开源编程语言,甚至专门建立了一个 Proposal 仓库来追踪各种提案的设计、讨论、代码以及发布的情况,比如等了 10 年的泛型提案:
搞明白了架构模型和关键模块,真正打开源码时就能将包、文件名、接口等包含的知识与整体结构相互映射,在脑中形成一张完整的图。
其他的前置知识
有时候文档的作者还会加上不少前置知识,比如基于什么样的算法,受到了哪些知识的启发甚至是实现了哪篇论文的思想等等。
这些前置知识,对我们的理解会大有帮助。我们可以通过学习这些知识来进一步了解软件的细节设计。