读代码这事,先要分是精读还是泛读。
从学习的目的来看,一定要精读一定量的经典代码。而精读是指每行都读懂,不看代码脑子里就能勾画出程序的基本结构。
这里有个很形象的状态,精读代码时会满脑子都是代码,放不下,甚至睡觉前脑子里也是代码。
但这一篇里主要不是关注如何精读代码的,而是关于如何在工作中掌握既有代码的,等价于泛读。
现存的很多系统往往很大,几十万行的可能也只算普通。
这时候一旦加入了这样一个项目,那么如何去读代码?
下面说点个人体会。
读这类代码前,先得把规格大致弄清楚,而不能上来就读,比如:对于应用型程序,你要先大致整清楚它的使用方法。
如果其中有涉及到领域知识,比如:流程、财会等,那也最好预先有些认识。这类东西从代码里反推回来是不太可能的。
我个人感觉这对读程序是个很大的障碍,你不知道编码规则,却去读编码的程序,总是会云里雾里,这时候反倒不是因为程序难,
而是因为不知道程序中所包含的专业知识。
在这一步里,最好能抽取出来几个典型的应用场景,这在后面有用。
一旦开始接触代码,那要先弄清楚代码的基本静态结构。如:包构成、类构成等。
这里涉及一个层次问题。一下子把层次探的太深,就容易盯在细节上出不来。
有设计文档的项目,大致上可以通过包来界定这个层次。
没设计文档的就可怕了,只能靠自己划分,最好不要超过10个,超过了真记不住。
在静态结构这步,要弄清楚每个部分的核心职责,可以简单,最好能记住。
接下来就要用到上面的典型场景了。
要在典型场景下考察上面的静态结构是如何发挥作用的。
典型场景下用到的接口往往就是关键的接口,要整清楚,他们的定义和作用。
也要整清楚,典型场景下数据流的变迁。
这步骤算是弄清楚代码的时序。很像UML里的Sequence图。
但牵涉到数据的时候,一般需要对数据的规格有所了解。
接下来要关注进程、线程的结构。比如:都是什么时候开始、什么时候结束的,在上述典型场景下都负责干什么。
上述四步(规格、静态结构、典型场景、进程线程)完成后,对程序的第一次泛读完成。
检验标准很简单,这时应该能够单靠纸笔描述出程序典型场景的Sequence图。
干这事儿的时候,要抑制自己的求知欲,因为总是很想在调试器里通过call stack把一个功能的实现细节整清楚,
但至少在第一个层次里,可以先不要这样。
第一次泛读后,就要进入深掘的过程,针对的对象应该是自己会负责的部分。这部分功能往往会隐藏在某个接口之下。
这时候一般来讲可以放过功能型的模块,比如:XML解析的模块等。其他部分可以认为是需要把之前所说的四个步骤再重复一下。
但这时候要关注细节和调用堆栈了。
不管是在那个读代码的层次,有两个基本技巧总是需要的,一个是要掌握具体程序里内嵌的Log机制,要能看Log,必要时可能还得加Log;一个是基本调试方法。
调试很难展开,《软件调试》一书写了1000多页。
但只停留在设个断点等他停下来这个层次上还是会有点欠缺的。条件断点、多线程调试、多进程时的调试还是要知道一点的。
程序类型太多,因此估计读程序的方法也很多。上面只是个人的一点经验,欢迎补充。