https://zhuanlan.zhihu.com/p/114868001
由于工作的原因,最近几周看了很多代码,总结了一些经验,就此记录下来,欢迎讨论。
看代码的过程中,一定要遵守一个基本原则,就是明确自己的目的。
你这次看代码的目的是什么?是要了解整个项目的大概流程?还是要弄明白具体细节,以方便自己修改?明确目的之所以重要,就是因为不同的目的需要采取不同的阅读策略。
如果这次阅读是想了解项目大概流程,就应该采取只看主干的策略,先浏览目录树,找到入口,然后只关注主干,配合上阅读相关文档,迅速了解系统的整体流程;如果是想研究某个项目中的某个组件的实现细节,那就只去看相关文件,把对应的细致逻辑捋清楚。
整个过程就像渔夫捕鱼,如果想捕大鱼,那么就用去用大网眼的渔网,一些小鱼就放过,不要投入太多精力;如果想捕小鱼,那就把网眼缩小,保证小鱼不会放过,但对于更小的虾米,也没必要投入精力。
明确目的之后,我们就要开始阅读了,这部分我推荐的步骤是:自顶向下,反复阅读。
具体来说,就是在明确了需要阅读的范围后,多次反复阅读相关代码,阅读的粒度则逐渐细致。开始时先粗略的了解数据的大致流向,把函数调用都当做黑箱,大致猜一下它们的作用;后续的阅读中再逐步摸清每个函数具体的逻辑实现。
整体遵循的原则就是“自顶向下”。自顶向下这个原则我之前在讨论架构设计的文档 架构设计开发的两大原则:自顶向下与MVP 中曾经谈到过。实际上代码作为架构设计的产物,在阅读它的过程中,也应该遵循类似的原则。
为什么?就是为了避免提前陷入细节,导致大脑被多层调用栈的上下文和细节填满,失去了对宏观的感知。这时,一旦阅读遇到困难,就很容易就会导致负面情绪,从而降低阅读的效率。
但实际上有时你所纠结和困惑的一些逻辑,其实在看了后续的代码之后,就会很轻易地弄明白。所以与其在细节上钻入牛角尖,不如先扩大自己的视野,前后都看看更为高效。
而按照自顶向下的原则去阅读的话,通常情况下,前一两遍的阅读应该能让你对当前所读代码的目的、设计、数据的流动、与其他模块的关系有了粗略的认知。带着这个认知再去研究细节的话,我相信肯定能事半功倍。
整个阅读过程中,需要克服一个心理惯性,就是总想只通过一次阅读就完成目的。许多人都有这个倾向,但其实这是不现实的,因为它不符合人的认知规律。
受限于大脑很小的工作记忆的容量,人类对复杂系统的认知本身就要通过分层抽象的方式来进行。我们需要先把细节压缩成概念,放入长期记忆中,然后再在工作记忆中处理多个从长期记忆中提取的概念,将其处理压缩成一个新的高层概念,最后存储到长期记忆中。整个流程循环往复,就是人类认知世界的基本规律。
想要一次阅读就完全理解一个复杂模块,只会导致在工作记忆中,后面读入的细节不断覆盖前面读入的细节,即狗熊掰棒子,捡一个丢一个的后果。
而按照自顶向下的原则去读的话,前几次的阅读就相当于现在工作记忆中建立几个概念的黑箱,然后存入长期记忆,后几次的阅读则会不断回想并填充这些概念。而回想和填充的操作,则会不断加深对这些概念的记忆和理解,最终形成对整个待阅读内容的一个深刻的认知(实际上,我觉着看代码的乐趣之一,就是我猜这部分应该这么设计,结果最后发现代码就是这么写的)。
最后推荐一些我觉着看代码的时候非常好用的工具。
首当其冲的就是纸和笔,无可替代的工具,灵活、方便、易于修改。(关于纸和笔的优势,其实我在 如何更好的思考:以手助脑 详细分析过,感兴趣的可以看下)
再然后推荐一些vim上的插件(因为我主要用vim开发)
- nerdtree:展示整个仓库的文件树,方便对整个项目有整体认知
- Mark—Karkat:支持用不同色彩高亮多个关键字,追溯变量更改时很有用
- LeaderF:神器,可以很方便的跳转到文件或指定函数。配合ripgrep用来搜索代码也是非常快速便捷。
(PS. 有心的同学应该能发现,这篇文章所讲的原则和步骤不仅仅适合看代码,还适合看一些非虚构类书籍:) )