一、为何阅读开源软件
这是一个对于程序员来说,非常重要的动机问题,如果没有足够的动机,那么阅读开源软件的过程中会变得没有目的,效率低下。
那么阅读 开源软件有什么意义呢?需要说明的是,软件的构建是一个复杂的过程,是一个逐步细化的过程。因此,我们可以从不同的粒度来审视一个优秀的开源项目,比如说,较大的粒度有设计角度、风格、模式,而较小的粒度上有编码、注释、命名等。
根据不同粒度上的意义,总结了有如下几点。
1.理解编程理论
我们所学过的课本上的知识,有时候对于我们而言过于抽象。很多东西我们只有在做的过程中才能深刻体会。
下面列举一些我们常见的一些抽象概念:
- 高内聚,低耦合
- 接口隔离
里氏替换原则
…
这些概念对于我们来说都是非常抽象的一些东西,如果我们不去在代码中体会这些东西,是很难体会到的。
我们要做的很重要的一件事情,是将这些抽象概念与具体代码之间形成一定的映射关系,这样子才能深刻体会 这些抽象的概念,所以我们需要去深入到代码中去体会这些抽象的东西。也只有这样我们也才会更家容易具备从抽象到代码实践的能力。
建议在代码阅读时,多问自己下面的一些问题:【代码现象】为什么会有这么多接口?这些接口有什么作用?
- 【编程原则】它的包的分类为何以这种形式展开?这是否和模块化有关系?是否体现了高内聚,低耦合?是否符合单一职责的原则?…
- 【数据结构】链表,树等数据结构,在代码中是如何体现的?应用在了什么样的场景中?
- 【算法】对于这个问题,作者为何会采用这种算法?作者使用该算法的目的是什么?如果是我,我会怎么实现来解决这个问题?
(问题还有很多,带着问题去查看代码的时候,你会发现能达到很好的效果)
2.了解软件发展规律,吸取前人经验教训
研究历史,总能给人以启迪。
现在的开源代码一般都是以仓库的形式进行管理的,这也就为我们追溯某段开源代码的历史提供了方便。
【成功与失败】追溯历史的作用在于,历史中是存在一定的模式的,一些经常犯错的地方,我们自己如果重新走这条路的话,我们会有很大的概率遇到这些错误。历史的作用在于告知我们哪些是成功的经验 ,哪些是失败的经验,以及如何避免失败等等。
【构建软件的过程】学习一个软件的版本发展历史,提交历史,你可以发现一个软件是如何发展壮大起来的。这能够给我们的启示是,假如说你想做一个软件,但是不知道以一种什么样的方式来开展,看看开源软件的提交历史也许会有一些启发意义,你将明白最初的时候应该构建哪些模块,然后如何去逐步扩展你的软件。图1是GitHub上一个soot项目的提交记录,我们能从中看到它的细节方面的发展历史。
可以借鉴的查看版本历史的方法:
如何以“正确的姿势”阅读开源软件代码?
图1:
3.学习良好的模块化设计,以及代码组织规范
较大的粒度的一种学习。
在进一步讨论之前,先提出一些问题:
- 什么叫做模块化?模块化有哪些体现?如何体现在代码中?
- 你在平时的编程过程中是如何进行模块划分的?你是如何发现模块化所能带来的优点的?
人们总有一种这样的倾向,分类的倾向,因为有这样一种本质的属性,所以人们对于所见到的事物总会归类到某种类别下面。比如说,当你看到一个事物,如果你知道这是什么,那么你会想到这个事物的名字(名字是一个代号,一个集合的代号),如果你不确定,那么你可能会把它归结为动物,植物,或者其他的什么东西。
之所以提到上面的这些内容,是因为说明在人类进行编程的过程中,也同样存在着这样的行为。而这种分类行为体现在了人们进行模块划分,体现在了代码组织上面。
【举例】想象一下,当你开始一个项目的时候,一般人是不会立刻开始写代码的,首先要做的事情是进行模块的分解,模块分解结束后,在后续会体现在代码结构上,可能是不同包的组织方式,不同类的组织方式,不同的方法上面。并且模块划分之后,我们通常习惯用这个模块的功能来命名这个模块。
【水杯设计】我想设计一个水杯,那么我需要先对水杯进行整体上的认识。弄清它的组成部(块),由盖子和瓶体组成(两个模块),那么我会将这两个模块分别放入相应的包中,lid(盖子)包,bottle(瓶体)包中。然后在盖子模块(包)中进行进一步的细化,比如说,颜色,形状等等。
这里想说明的是,模块与包之间的对应关系。
类与包,本质上都是模块化的结果,都是分类的结果。你需要具备这样子的一种能力,细化到什么程度用包的方式组织,细化到什么粒度用类的方式组织。
4.细节,核心的学习
包括语言技巧,数据结构,算法等细节。这些都是非常细节的一些东西,但往往也是一些你需要非常关注的地方,程序的逻辑就体现在了这些地方,可以说,这是一个程序的灵魂性的东西。
逻辑是一个程序的本质,组织方式,原则是方便人进行开发的形式。(所以一般进行代码阅读,主要的精力是应该放在这上面的)
语言技巧
假如说你是java程序员,你平时面对的主要编程语言是java.但是你在编程过程中,不会去知道java语言的哪些特点是好用的,哪些是应该避免使用的,学习别人的优秀码,能开阔你这方面的视野。
比如说,你知道for(;;)使用办法,但是没有接触过foreach,通过阅读别人的代码你可能会发现这一点。
数据结构
关于数据结构存在的意义,见文章(数据结构存在的意义)。
从某种程度上而言,数据结构也决定着你程序的结构。如果你想优雅的进行编码,就得进行采取恰当的数据结构。
举个简单的例子:
我列举出了两种组织方式
组织方式1:
int data1;
int data2;
int data3;
...
组织方式2:
int data[50];
不同的组织方式导致不同的程序结构:
- 组织方式2能够充分利用java提供的循环结构,进而简化代码。
对于组织方式1的遍历(很多行代码):
System.out.println(data1);
System.out.println(data2);
System.out.println(data3);
...
对于组织方式2的遍历:
for(int i =0; i< 50;i++){
System.out.println(data[i]);
}
参考:
为何阅读开源优秀代码?
二、如何阅读开源项目
结合自己的经验,以及网上大牛的经验,做出如下总结。
待续···