这应该是很多读者想知道的问题,先讨论几种老生常谈的阅读源码的方式。 第一种方式就是所谓的精读和粗读。很多读者应该听说过这种所谓的阅读源代码的方式,有些人认为有些源码只需要搞清楚其主要结构和流程就可以了,而另外一些源码需要逐行认真去研读其某个或者某几个模块的源码。或者,只阅读自己感兴趣或者需要的模块。 第二种方式,说的是先熟悉代码的整体结构,再去依次搞清楚各个模块的代码细节。 第三种方式是所谓的调试法,通过开源项目的一个或几个典型的流程,去调试跟踪信息流,然后逐步搞清楚整个项目的结构。
例如学习 Nginx 的源码,调试就是一个非常好的方式:
以上三种方式都是不错的阅读源码的方式,读者可以根据自己的水平、目的和阶段去使用。但是,我这里想说的并不是这些东西。
我建议,一个技术人员如果想通过源码去提高自己,应该以一种"闲登小阁看新晴"的心境去阅读源码,这也许是在某个节假日的清晨,某个下过雨的午后,某个夜黑人静的深夜。看源码尤其是看高质量源码本来就是一种享受,像品茗。闲暇时间去细细品味一些开源软件的源码,和锻炼身体一样,都是人生中重要不紧急的事情,这类事情做的越多,坚持的越久,越能提高你的人生厚度。虽然阅读源码的最终目的是功利性的,但是阅读源码的心态不建议是功利性的,喜欢做一件事本身的过程,比把这件事做好的目标更快乐。
我从学生时代开始,就喜欢看一些开源软件的源码,当然,从现在的标准来看,看的很多源码都不是"高质量"的,择其善者而从之其不善者而改之,不是吗?有些源码可以学习其架构、结构设计,有些源码则可以学习其细节设计(如变量命名、编码风格等)。
看过的这些源码对我的技术视野影响很大。我上大学的时候,迷恋 Flash 编程,当时非常崇拜 Flash 界的两位前辈——鼠标炸弹和寂寞火山(现在已成币圈有名的大佬),另外还有淘沙网的沙子。多年后再看他们的代码可能质量没有那么高,但是我从他们开源出来的代码中学到了很多东西。举个例子,我喜欢在一些成对结束的花括号后面加上明显的成对结束的注释就是从沙子的代码那里学来的。虽然,现在的 IDE 会清楚的标示出来各个花括号的范围,但是这种注释风格在某些时候大大方便了代码阅读和 review。
//实例
class A
{
public:
void someFunc()
{
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
//some codes...
}// end inner-for-loop
}// end outer-for-loop
}// end method someFunc
}; // end class A
三、给大家阅读源码的一些建议
很多人阅读源码存在以下不当的习惯或者认知方式:
很多人阅读源码其实是随波逐流的,今天有人推荐阅读 A 项目的源码,他就去阅读 A 项目的源码,明天有人推荐阅读 B 项目的源码,他就去阅读 B 项目的源码。天下源码何其多呀,找到自己感兴趣的或者对自己有用的,不要随波逐流,适合别人的不一定适合你。
代码的质量高低是相对的,不要因为一些项目的源码质量低或者不符合你的 style 就放弃。大多数完整的项目代码总有其可取之处,要学会吸取其有用之处。举个例子,很多做 Windows C++ 客户端开发的同学,应该会在网络的各个地方看到很多人抨击 MFC 的,然后一堆建议不要学习 MFC 的。从我个人的经历和感受来看,MFC 的源码还是很值得做 Windows C++ 客户端的同学学习的,尤其是其设计思想。当然,MFC 之所以被很多人抨击,是因为其臃肿笨拙,这有很多历史原因,MFC 不仅封装 Windows 界面逻辑那一套,同时实现了一套常用软件文档、视图模型的程序框架结构,同时自己实现了一套 STL 相关功能,以及其他一些常用功能(如对象的序列化和反序列化)。这些设计思想都被后来的各种软件框架借鉴和继承,例如 QT 和 Java 中的序列化和反序列化。一个开发者如果想成为架构师,其心中一定要对某个场景有一套可行的技术方案,如果你经验不足或者水平不够,拿不出来这样的方案,那就去借鉴和学习这些开源的软件。而不是只会抨击这些软件源码的缺点,而自己又无更好的解决方案。旧的方案虽然不好,但是我们需要去学习、熟悉,只有熟悉了之后,我们才能基于其去改造和优化。