最近一年里,我阅读了不少开源项目的源代码,之前也和朋友讨论过阅读源代码时遇到的一些问题。我觉得有必要写一篇博文分享一下自己的经验。
序章:准备工作
通常情况下,我们不会无缘无故拿到一份源代码,我是说,当想要阅读源代码时,一定是抱着某种目的进行下去的,这个目的会贯穿整个研究过程,比如:
- 想研究某个东西的实现
- 想学习作者的代码风格和项目组织
- 想参考实现并用其他语言移植项目
等等。所以在最初的时候,明确自己阅读源代码的目的非常关键。
在明确了目的之后,就可以正式开始深挖代码了。不过在此之前,还是要提醒一下:工欲善其事,必先利其器。
可以用来写代码的工具有很多,如包括Vim、Emacs、SublimeText、Atom等在内的Text Editor,还有包括Visual Studio和JetBrains全家桶在内的IDE。Text Editor在编写代码时有无与伦比的优势,方便的快捷键、一流的反省速度、高度可配置的编辑环境等等,无疑能极大程度上提高程序员的手速,然而这些亮点都不是在阅读代码时候所必须的;阅读代码时,很多时候需要搞清楚函数之间的调用关系,这时候就需要有强大的代码静态分析工具和一个便捷的断点调试工具,这也正是IDE的优势。
因此我郑重推荐在阅读代码时使用IDE,当然如果是较小的项目加之已经调教成IDE的Vim/Emacs,也是没什么问题的。
接下来,就真的可以开始深挖代码了。
第一步:自顶向下理清代码组织关系
代码组织结构
很多时候这一点根本就不是问题,因为项目的构建无非是通过构建工具、框架或最佳实践来做的,实在不行还可以查阅开发文档。
Code Breakdown Structure
这是我认为最重要的一个步骤,然而我也吃惊地发现,并不是每个人都能重视这个步骤并处理得很好。
所谓Code Breakdown Structure的说法,本身源自软件工程中Work Breakdown Structure。WBS把软件需求按照业务的角度逐级下分,而这份产物能够直接影响到项目代码里的数据模型。
当然,项目代码里的结构,不仅仅受到了实际需求的影响,也受到了构建工具和设计模式的影响,比如能够应用在全局的MVC模式,或者应用在局部场景的单例模式、状态模式等等,更会受到程序语言相关层面的直接影响;但不论是怎样的软件模式、怎样的编程范式,阅读源代码时仍旧需要搞清楚不同的代码组织在整个项目里的角色是什么,需要分别知道数据层、工具函数、顶层抽象、抽象实现和具体的功能性代码分别是什么、在哪里。在整理这部分内容的时候,通常会在脑海中形成清晰的思路,但如果可以的话,请把这些东西用纸笔画出来。
如果想要研究的是具体的功能实现,就需要在上面的基础上更进一步,着眼于功能性的代码,对每个功能实现画出活动图和时序图。
总之这一步里包含了不小的工作量,但搞清楚这些东西,是继续进行下去的基础。
第二步:有针对性地深挖代码
这是阅读代码的核心步骤,是最复杂的一个步骤,也是我无法在此篇文章中展开的步骤。因为每个人阅读代码的目的不尽相同,每个人研究问题的习惯也有很大差异。
研究问题的时候,通常会有大量自己改代码、打断点、做编译的机会,请尽情享受解决自己目标问题的思维过程,并且不要忘记以下重要的辅助资源:
- 开发文档
- 开发日志(Issues, Mails)
- 主要开发成员的博客(如果有的话)
- 相关领域的资料,包括书籍和论文
- 与同类开源项目产品的实现相比较
- 与原作者、开发组进行沟通:IRC、Maillist、Gitter等
第三步:自底向上理解局部代码在全局中的重要性
不论是把眼光聚焦在对问题的解决方案上,还是在代码组织、设计模式上,能针对结果做进一步抽象,才是最好的。
这里面蕴含的机会是:
- 一旦理解了作者的解决方法,对自己理解这种解决方案本身和背后的业务模型都有提升。
- 一旦发现了更好的解决方案,自己就有机会提PR。
尽管要做好这一步,需要较强的领域技术背景,但如果能坚持尝试这么做的话,会受益匪浅。
接下来的事情
阅读完一份源代码,找到了自己需要的东西,让自己的能力得到提升。接下来的事情当然是:
- 多运动,让自己大脑放松一下
- 多陪陪父母妻儿(没有妹子的话就去找)
- 阅读下一份开源代码