关于阅读代码

一些关于最近阅读代码的想法

原因.这些感想都是来源于最近搭建博客这件事情.大概是两个星期以前,刚读完 EOPL 没多久后想到除了做题以外还得搭建博客. 其实我之前有一个用 Jekyll 做的博客,但是我一直想学习写一个 builtin Emacs 静态站点生成器,于是第一个博客我写了两篇 文章后我久没管了.于是我就到 GitHub 上找一些关于利用 Emacs 来 blog 的 libraries.最后我找了 org-page 这个项目 来读,于是长达 5 天的代码阅读之旅就开始了.

阅读的过程,一个错误示范.计划这是美好的,现实中整个过程十分漫长和痛苦.对 Emacs Lisp 的操作符号不熟悉,不太懂利用 Emacs 的功能;不懂如何获得 function call stack;被代码的设计方式绕晕.从入口函数一句一句地读起来,手动笔记 function call stack,这样实在是痛苦.后面还边读边跟着敲,这怕是我做过最蠢得事情之一了.

反思.代码我还没完全读完,因为我已经读了我想要的,所以就放弃剩下的了.这个糟糕的过程也不是一点收获也没有,我还是 对 Emacs Lisp 的自带操作符有了更深刻的了解,熟悉了 Emacs Lisp 的代码编写规范.这比起直接通过 Reference 来学习 Emacs Lisp 要快的多.这也让我产生了掌握代码阅读技能的欲望.

参考.我在 GitHub 上找到一个有趣的项目 how-to-read-code,这上面用 JavaScript 来做为讲解例子,虽然不是我熟悉的语言 ,不过思路是可以参考一下, 大部份的文章都基本是提议,"不求细节抓结构,结合项目文档 + 利用 debugger 获得 function call stack + uml 记录"这种方式来了解项目的全貌,这个项目也有提到这些,不同点就在于她提出一个给代码分类的做法,下面大概罗列一下.

Another way to think of kinds of source code.具体就是把代码分类,给出了六种,不同人会有不同的分类:

  1. Glue – 把不同的东西捆起来的部分,比如 middleware
  2. Interface-defining – 接口定义部分
  3. Implementation – 接口的实现部分
  4. Algorithmic – 算法部分,业务逻辑.
  5. Configuring – 配置部分
  6. Tasking – 处理任务的部分

每一个类都有不同的读法,也就是读的时候该如何思考:

自己的阅读策略 这个分类实际上间接地介绍了代码的作者编码时候的总体思路.结合自己的经历,我的阅读代码的策略如下:

  1. 明白自己的阅读目的.更快上手刚学习的语言,选择小项目;了解具体方面的实现,比如某某解析器,那么请确保自己有解析器相关知识再 来读;等等
  2. 准备好阅读的项目,准备好代码的运行环境,利用 git 新建一条用于阅读和修改的分支.比如我读 org-page 的时候就是 clone 并且新建切换分支,最后手动 (add-to-list 'load-path "path/to/repo/org-page")
  3. 准备好它的文档,先使用一遍,大概了解它的工作流程
  4. 选择一个好的起点.一般是入口函数,比如我只想要了解 org-page 发布文章的流程,那么我就给它的发布函数设置断点 (debug-on-entry op/do-publish),单步运行,记录它的 function call stack,可以现在你喜欢的方式进行记录. 再根据 function call stack 来了解 function 的大概意图,只有等你想了解具体实现的时候才去读它的实现; 又比如我想读完整个项目,还是先从文件结构来开始,这时候可以结合上面的代码分类来了解每个文件的作用,选一个感兴趣的点 开始读.
  5. 读的时候可以多使用 debugger,还可以根据自己的猜想来修改代码再运行,结合代码分类的阅读思路来阅读.
  6. 遇到实在不懂的地方一定要去问作者,所以会英语是很重要的.
  7. 不要企图总是一次读完或者一次读懂.项目太大是不可能一次读完或理解的的.放慢脚步慢慢阅读,有必要的划还要重复读. 中途暂停时记得做好笔记方便下一次继续读.除非你要学习编程方法,否则标准函数不要读.

关于该不该读代码 这个问题,结合我个人的经历来说,先不说应不应该,是值得,即便它花了我一段时间也没有实现一个静态站点生成器, 但其实这是我的问题,我内心其实就不是真正的想写一个静态站点生成器,不过我还是以偏离了一点的目标实现了一个.这都是归功于这段糟 糕的阅读经历,否则我是不可能在别人的博客教程的基础上进行拓展的,因为这段经历让我能更加熟练写 Emacs Lisp,你要知道我用 Emacs 有一段时间了,真正有所长进也是这一次.没有什么学习方式比模仿和实践更有效率,这其实就跟学英语一样的,语法是重要,词汇量也很重要, 但最重要的还是多读多听说,其中多读就是广读法,当你读的量上去了,你也很自然地能够写出相应的句子或者文章.对于编程,实际上写代码 的时间不长,一天真正有用的代码可能也就几十行,除去构思代码的实践基本都是在读文档和代码了,所以编程的主要工作不就是阅读吗?再回 到问题上,答案是应该的,每天读一点代码也是工作之一.

一些阅读代码小Tips – 持续更新

  1. 如何去阅读并学习一些优秀的开源框架的源码? - 知乎用户的回答 - 知乎
  2. 使用 UML 进行梳理,不过个人觉得不适合用来记录 function call stack

Author: saltb0rn (asche34@outlook.com)

Date: 2018-05-30

Emacs 28.2 (Org mode 9.5.5)

Validate