赞
踩
本文以开源代码阅读为例,谈谈如何阅读源码,尤其是大型系统,包括如何快速入手,如何高效处理。可展开为代码阅读方法;软件调试方法与技术技巧;软件优化方法与技术技巧。相关内容后续补充。
首先,达成三点认知:
1 人脑可处理的信息量是有限的,而程序包含的信息很容易超出人脑的处理限度。迪杰斯特拉名言,关于10的9次方说法。
2 人需要对事物从抽象、层次、结构不同角度认知,这是大脑的特点。
3 人的时间和精力都是有限的,现代大型系统很容易就触及百万行级别,所以需要掌握方式方法,而不是采用蛮力。
一,开源软件的学习
这部分以开源软件学习为例,介绍高效处理大型系统的方式方法。
<1> 了解软件开发背景
了解要关注软件产生的背景。这样才会有一个总体性的目标。
<2> 关注软件的官方网站
许多开源软件都有官方网站,发布有关该开源软件的官方权威信息、接口说明、注意事项、历史修改等。通过官方网站,可以更加全面的了解软件的产生背景、设计架构、当前功能及后续改进计划等。这对我们“看懂”代码,非常重要。
<3> 目前的最新版本和其他信息
介绍软件目前的版本以及以前所有保留的老版本。之所以介绍老版本,是因为最初的版本一般都是最简单的,所以从早期的实现了基本功能的版本入手也是快速学习的一种手段:因为这些版本的代码看起来是要更简单一些。顺着选定的一个早期的版本往下走,再根据版本演变的历史资料,我们不仅可以更容易理解一些扩展功能或者高级功能,也更容易看懂接近当前版本的代码。如果一开始就从最新的版本下手,功能是包括的最全了,另外,可能也是最稳定的,Bug最少的,代码最整洁的,但是,面对大量的扩展功能或者高级功能的时候,特别是逻辑上,针对特定功能的代码不是设计出来而是随着功能演进插入实现的情况时,容易产生云里雾里的感觉,并且可能还会因为觉得太复杂影响继续学习的积极性和兴趣。所以,需要了解各个版本的演进过程,其目的即在于此。
<4> 软件的用途
这部分简单直观的描述软件到底是干什么用的,以及如何用,效果的一些演示等。
<5> 基础知识
介绍这款软件所涉及到的相关领域的基础知识,为后面的研究学习做准备。
<6> 软件的架构
介绍软件整体的框架,可能包括官方的和个人理解的,但是会注明到底是来自哪里。
<7> 核心数据结构
介绍用到的关键的几个数据结构,既然是核心,不会涉及太多。
<8> 流程
根据函数调用过程介绍软件到底是如何工作的。
<9> 值得借鉴的编程技巧和理念
介绍软件中用到的一些编程技巧和设计理念,加深认识,提高自身技能。
二,额外的话,关于架构
上面几点的顺序基本按照人的正常认识过程来排列,并且假设读者基本上没有相关基础知识。总体上整个过程可以分为三部分:背景、软件、扩展。首先是背景相关,包括背景知识,软件目的以及基础知识。先介绍背景知识,使读者了解到这款软件的开发背景;其次是软件的用途,明确该软件到底是干什么用的,以及基本的使用过程,使读者在脑海中形成一个宏观的概念或者框架,以便后续阅读目的性更强;再者,基础知识,介绍了解该主题和软件所需的基础知识,包括基本概念,一些简写的含义等等。对于相关这些知识都非常了解的读者来讲,前面这几部分完全可以跳过,或者只是扫一眼。第二部分包括架构、数据结构以及流程。从软件的架构开始,就涉及到软件的核心了。先是软件架构,使读者了解针对前面的所介绍的基础知识和要实现的目标,该软件是如何来进行架构以达到该目的(桥梁作用,完成解空间的转换,从现实世界到软件世界)。之后是核心的数据结构,可以说数据结构是理解和掌握该开源软件的核心,那么核心的数据结构就是核心中的核心了。数据结构中的各个项实际上都是关联与基础知识中介绍的各个元素或者是元素的一部分的,虽然说数据结构是一种比较松散的结构,但是相对而言,在一个数据结构中的各个元素还是在某种程度上具有一定关联性的,所以,掌握这些数据结构既是对基础知识中基本概念的加深认识,同时对这些基本概念之间的关联性也就有了一定的了解。下一步是流程,我们讲程序是算法加数据结构,在这里流程在一定意义上讲是具有算法的特点的。再结合架构,我们不仅会看到软件是如何将这些数据结构联系起来的,更重要的是达到了最终的目标:即软件到底是如何工作的。有了上述两部分,可以说目的基本上就都达到了。但是一款开源软件,不仅存在,并且被大部分发行版包括Ubuntu、Fedora 等接收作为默认的软件在安装系统时被选择作为相关功能的软件,并且还能不断发展,有新版本不断推出,肯定有自己的特色,而设计技巧和设计采用的理念就属于特色之一,所以在了解完软件之后还是有必要将这两部分拿出来作为扩展单独讨论一下,这就是第三部分扩展的内容。对于这部分的内容,还是有必要去细细品味的,这也是快速提高自身设计能力的一种方法。
三,以Linphone为例谈如何阅读源代码
个人鄙见,欢迎拍砖。
本部分以Linphone为例来说明如何阅读优秀开源软件的源代码。这里记录的只是个人在阅读Linphone源代码过程中感受,并不适合所有人。每个人都有自己习惯的接收新事物的方式,这里的习惯也包含了更快的意义。所以以下所有的内容仅作为大家在阅读源代码过程中的参考,如果能对大家有所帮助,则目标就达到了。
1 认识软件功能。
在学习一个软件前,了解其功能我觉得是一个基础步骤。如果对软件功能都不了解,那还谈什么研究和学习。当然,这里只针对软件学习而言,不包括其他行业。这里所说的认识软件的功能是说应该知道这个软件是干嘛的。
2 运行软件,感受软件。
3 到官方网站,查看软件相关信息。
4 找到或者画出基本正确的软件架构图。
如果官方网站已经有了软件的架构图,那么就太幸运了,通过了解软件整体架构可以快速入门。
5 根据模块或者功能,对软件进行分块。
即便现在信息技术如此发达,人们认识事物的过程还是由简单到复杂,这个基本逻辑从未变过。如果开始一下子就要研究软件的整个功能,我想即使是天才也是做不到的。所以我们需要将软件划分成小块,一块一块来学习,这叫化整为零。
6 在上一步的过程中,可能的话加入对软件的调试。
最简单的方法,可以加一些打印信息到代码中,然后将软件跑起来,看看打印从而了解软件的流程。通过这一步你将对整个软件的流程有更加具体的感受。
7 整合串接。
当对重要的基础的模块有个了解后,再将它们合起来感受。这时应当对整个软件的流程有个清晰的了解和认识了。这叫化零为整。
8 以具体任务为切入点,深入理解。
当对整个软件流程有了比较近距离的了解后,可以考虑修改一些功能或者添加一些功能,以改进软件,并进一步加深对软件的认识。
9 学以致用。
学习一个软件,不仅是要了解软件的功能,学习软件的流程,还要学以致用,将其中优秀的编码思想和方法运用到自己的开发中,这样才能提高。
10 做好充分心理准备,不断前进。
学习一个开源软件,最后还要踏踏实实,一步一个脚印,慢慢来,切忌急躁。一般而言,除非是实现一个算法结构题,否则一款具有实际功能的软件包,都不可能是我们在学校里那样一个源文件加一个头文件就能搞定的,有个几十个几百个文件那很正常,但是我们也不能被这么多的文件吓倒,要把它当做纸老虎,不用怕它。这并不是说我们就需要一个文件一个函数挨个去看,而是要在把握整体架构的基础上一个模块一个模块来理。从另一方面来说,许多开源软件的写法风格之类都是比较约定俗称的,有一定相似性,如果看过比较多的开源软件代码,对这一点就会有比较深刻的感受。所以对于有一定基础的人来讲,一般通过命名,布局等信息,就会对功能有个初步的心理感知。对于新手来讲,这可能有点难度,但是没关系,这是你要学习开源软件必经的过程,也是消化吸收的过程。方法可以使你少走弯路,有一个比较正确的或者直线的方向,但是掌握的过程是需要时间积累的。
11模块化验证。
如果可能,可以将能跑的模块单独拿出来跑Test。即使不是单独的模块,如果这部分的封装比较规整,独立性强,耦合性小,逻辑复杂,则都可以拿出来单独编译,添加Debug信息看结果。这样也可以比较快速的看出接口的功能,同时也可以比较方便的跟进去看具体的实现。比如笔者在做媒体网关产品项目时,涉及到防火墙模块,有一个判断输入IP地址范围的接口,内部实现比较复杂,有迭代操作,于是就将其单独拿出来进行编译跑,发现具体功能是对输入的IP地址范围输出该范围内的所有合法的IP地址。所以针对这一步,我们在看源代码时可以随时跑一个测试工程,用于将复杂的,计算逻辑的接口添加进去单独跑测试。这样做貌似花费了不少时间,实际上是节省了大量时间,直接看代码貌似是最快的方式,但是存在一时半会看不懂,理不清,搓信心,多重复等问题,实际上是浪费了大量时间。
12 测试驱动阅读。
每个模块应该提供测试Demo,这也是开源软件的一大弊病,就是没有测试程序。这与开源软件的生成是相关的,因为开源软件一般都是由一个人或者几个人完成的,重点在于实现功能。当然,参与开发人员少,断断续续,时间少等外在因素是部分原因,另外,开源与免费挂接,没有后续支持才是主要原因。对于商业软件,一般都是由多人合作开发,模块划分会比较清晰,模块完成时同时也就提供了Demo,包括模块自身的测试也需要这样的Demo。另外,作为收费的商业软件,需要保证稳定性,可维护性,需要提供后续支持,甚至部分接口可能要提供给合作伙伴,加快开发进度,减少开发难度,这些因素也都促成商业软件的模块化测试比较完整。针对不断的修改提交,还需要回归测试,以便能够有效减轻测试压力,加快验证过程。总的来看,许多软件工程的理论方法在开源软件中体现的并不充分、明确,这一点在阅读和测试开源软件时需要额外关注。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。