网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
个人经验:驱动我“专门读代码”的最大动机是好奇心,和小孩拆小物件为了看内部构造差不多。 学习OO设计模式,我建议阅读《Head First 设计模式》 ,这本书超有趣,比四人帮那本删减了一些不常用的模式,但是你能轻松读下去。
阅读了解项目代码是参与(开源)项目的第一步,希望这篇文章能帮助你参与到心仪的项目中去。 这也可以帮助你在工作中了解同组同事的工作,而“了解同组同事的工作对工作有诸多潜在益处” 。 来吧,花点时间挑一个看上眼的项目(或者就读你手头的项目别人写的部分), 找到你最感兴趣的功能,读一读它是怎么实现的。
转载于:https://boholder.github.io/blogs/learn-from-source-code/#contents:应该读什么样的源码
我看到回答里也有人提到了我的书《通用源码阅读指导书》。这本书才刚上架还没几天,就有人提及了,十分荣幸。
本回答将按照下面的章节体系进行:
1 我为什么阅读源码
2 阅读源码的好处
3 阅读源码的困难
4 阅读源码的步骤
5 阅读源码的方法
1 我为什么阅读源码
我开始阅读源码是在进行互联网开发的第八九个年头。在此之前,我做过校园网站,接过网站开发的私活,进行过理论算法相关的研究,也设计开发了许多系统。我对我做过的系统都比较有信心,它们也都运行的不错,但是一个疑问却在我的心头逐渐浮现:我的架构和世界最优良架构之间的差距到底有多大?
阅读开源项目的源码能给我答案。
许多优秀的开源项目历经数千开发者的数万次提交,被数亿用户使用。这些项目从可扩展性、可靠性、可用性等各个角度考量,都是十分优良的。通过阅读这些项目的源码能让我找到自己在软件设计和开发上的不足。
于是我开始了我的源码阅读计划。
2 阅读源码的好处
阅读源码的好处很多,而且已经成为共识。光靠铺天盖地的源码阅读活动就能感知一二,虽然我觉着那些活动都太过浮躁,主要是个噱头,学不到啥。
但是不可否认,阅读源码的好处极多,包括但不限于:
- 透彻地理解项目的实现原理
- 接触到成熟和先进的架构方案
- 学习到可靠与巧妙的实施技巧
- 发现自身知识盲点,提升自身知识储备
所以,我有些后悔,我觉着我应该更早地开始源码阅读。我推荐进行源码阅读的时机是:学会编程语言的基本知识,并做过少量项目之后。
我们知道,学编程的过程中在不断接收新的知识,进步很快。刚开始做项目时,进入实践领域,进步很快。然后就到了平台期,可能几年下来都是重复的增删改查,毫无进步。这段平台期实际是进行源码阅读的良好时机,能让你的技术持续进步。
3 阅读源码的困难
当我们阅读一份源码时,需要面对的困难通常有:
- 难以归纳的凌乱文件
- 稀奇古怪的类型组织
- 混乱不堪的逻辑跳转
- 不明其意的方法变量
- ……
所以很多人即使知道阅读源码的好处,也坚持不下来。就因为以上困难难以克服。
而阅读源码的难,是正常的。
3.1 时间维度带来的困难
从时间维度上看,每一个优秀的工程项目都经历了从雏形到成熟的曲折演化过程。而整个过程都会被映射到一个时间点上,肯定很难。
于是有人提出了“阅读源码时,从第一次提交开始阅读”的主意。我要说一下,这是错误的!
这是一种纸上谈兵式的错误,提出这种方法的人肯定没怎么读过源码。事实上,我也有过这种想法,然后在实践中很快被抛弃了。
如果一个项目只经过了几次提交,这种方法获取可行。而一个优秀的通常有几千上万次提交,将这几千上万次提交都读完,工作量要比把当前最新版本的代码读完难的多得多!因为其时间维度的复杂度比空间维度复杂度大得多了。
我用下面的图片展示了项目发展的过程,一个项目从版本1到版本n,逐渐完善。版本1一般是最简单最基础的,但是,要想从版本1读起,一直读到版本n,可能要阅读几千个版本。难度极大,远不如直接去读版本n。
还有,许多项目的第一次提交并不是只有几行代码的init项目,往往第一次提交就是几百个类。而且,初期的代码组织还比较混乱。毕竟,作者也不知道该项目能火,往往比较随意。
更别说,历史提交中还夹杂很多的Bug、回退、依赖包升级等等。想要把每次Bug、回退、依赖包升级所产生的历史背景都搞清楚,这几乎是不可能的任务。
3.2 空间维度的困难
每一个优秀的工程项目都凝聚了众多开发者的缜密思维逻辑,而这些逻辑都被投射到了平面的代码上。这使得阅读源码的过程成了逆推开发者思维逻辑的过程,显然,逆推是很难的。
不过,这方面的困难真有解决方案:详细了解开源项目的功能,然后自己琢磨该如何实现。
这样,就将**“逆推”的过程转化为了“正向推导+验证”的过程**,这样就相对简单了。
但无论如何,阅读源码总不会太简单。于是有人说读懂源码比编写源码更为困难,想必也是有一定道理的。
4 阅读源码的步骤
阅读源码推荐按照下面的步骤进行:
- 了解项目的背景。这相当于了解了项目的需求。
- 充分了解项目的功能,并熟练使用。我们说过,将“逆推”的过程转化为“正向推导+验证”的过程是阅读源码的一个重要方法。而了解项目的功能是这个方法的基础。
- 调试代码。通过断点调试,掌握整个代码的流程走向、主次关系、依赖关系。
- 划分源码。根据每个包、模块的功能不同,将源码划分为几个部分。
- 由底层到上层,逐个击破。先阅读不依赖其他模块的,或者依赖其他模块比较少的基础模块。然后逐步上移,完成整个项目源码的阅读。
- 横向总结。在由底层到上层阅读完成后,横向以功能点为维度串联源码的实现逻辑。
一般情况下,一个项目的源码要在3~4个月左右读完。否则,可能读到后面的,已经忘记前面的功能了。
当然越快越好,但考虑到我猿们还要加班,时间太短了不太现实。
5 阅读源码的方法
有人说读懂源码比编写源码更为困难,不无道理。而源码阅读和软件开发一样,是一个非常综合的能力,没有一个万全之法。但有很多不错的方法。
例如一些常用的方法:
- 调试追踪:多数情况下,当我们对某些变量的含义产生疑惑时,借助开发工具的调试功能直接查看变量值的变化是一个非常好的方法。而且该方法还能指引代码逻辑的跳转过程,对于理解源码极为有用。
- 归类总结:优秀的源码都遵循一定的设计规则,这些规则可能是项目间通用的,也可能是项目内独有的。在源码阅读的过程中将这些设计规则总结出来,将会使得源码阅读的过程越来越顺畅。
- 上下文整合:有些对象、属性、方法等仅仅通过自身很难判断其作用和实现。此时可以结合其调用的上下文,查看对象何时被引用、属性怎样被赋值、方法为何被调用,这对于了解它们的作用和实现很有帮助。
- 类比阅读:如果存在实现某功能的两条或者多条路径,可以类别阅读,找出他们处理逻辑的不同。
- ……
还有很多方法,不再一一介绍。因为没有实在的源码案例,光介绍显得很浮。
如果大家真的决定阅读源码,开始提升自己架构能力和编程能力的新阶段,可以阅读《通用源码阅读指导书——MyBatis源码详解》。
是一本以MyBatis源码为材料,详细介绍源码阅读相关方法和技巧的源码阅读指导书籍。
该书以实际开源项目MyBatis为例,详细介绍了源码阅读的经验和方法。在源码阅读中,透彻分析了相关的背景知识、组织方式、逻辑结构、实现细节。在本书的讲解中,不漏过每一个类,不跳过每一个难点,做到深浅一致。并对这些源码阅读方法进行了进一步的总结整理。
阅读源码会使你有很大的提升,但是这个过程也确实需要你沉下心来慢慢进行。
但我保证,只要你读完一个项目的源码,就会收获巨大。
最后,用书籍前言中的一句话结尾。
我是高级软件架构师易哥,欢迎大家关注我。
我会偶尔分享软件架构和编程相关的知识技巧。
转载于:https://www.zhihu.com/question/19625320
阅读源码是每个优秀开发工程师的必经之路,那么这篇文章就来讲解下为什么要阅读源码以及如何阅读源码。
首先来说下为什么要读源码,有学习源码的必要吗?
为什么要阅读源码?
关于为什么阅读和学习源码,我个人认为可能有以下几点:
(一)吊打面试官,应对面试
为了找到更好的工作,应对面试,因为在面试中肯定会问到源码级别的问题,比如:为什么 HashMap
是线程不安全的?
如果你没有阅读过源码,面试官可能会对回答的结果不满意,进而导致面试结果不太理想,但如果你对源码有所研究,并能够很好地问答面试官的问题,这可能就是你的加分点,可以形成自己独特的竞争力,吊打面试官,升职加薪不是梦。
(二)解决问题(bug)
在开发过程中,我们或多或少会遇到 bug
,比如:在 foreach
循环里进行元素的 remove/add
操作,为啥有可能会报 ConcurrentModificationException
异常?
我们可以先在 Google、Stack Overflow
以及对应项目的 Issues
里看有没有类似问题以及解决办法,如果没有的话,我们只能通过阅读源码的方式去解决了。如果我们对相关源码有所涉猎,就可以快速定位到问题所在。
(三)提升编程能力
读一本好书,就是和许多高尚的人谈话。 -歌德
和阅读一本好书一样,阅读源码就是和编程大牛面对面交流的机会,在许多优秀的开源项目中,它们的编码规范和架构设计都是很棒的,另外在设计上也使用了大量的设计模式,通过阅读和学习源码,能够快速提升我们的编码水平,以及对设计模式有更深的理解。
同时,在我们阅读完一个源码后,可以触类旁通,能够快速地对其他框架的源码进行阅读和学习,减少时间成本。
除了上述提到的原因之外,可能还有许多,在这里就不一一赘述了,那么在确定了要阅读源码之后,就让我们看下如何阅读源码吧!
如何阅读源码?
如何阅读源码取决于你为什么要读源码,比如:
- 如果为了应对面试,那就可以围绕常考的基础类、集合类、队列、线程、锁等内容进行阅读和学习;
- 如果是为了解决
bug
,那么就可以只围绕出现问题的相关类进行阅读分析,随着解决bug
的增多,我相信阅读的源码也会越多,从而更容易去阅读和学习源码;
下面大概说下阅读源码的几点建议:
在阅读之前,可以先从开源项目的官网上看它的架构设计和功能文档,了解这个项目的整体架构、模块组成以及各个模块之间的联系。
如果没有对应的项目文档,可以根据代码的模块进行梳理,以形成对项目的初步了解,或者查看已有的源码解析文章或者书籍,在阅读源码之前,了解项目的架构和思路会使阅读源码事半功倍。
在了解一个类的时候,可以使用 ctrl+F12
来查看类中的成员变量和方法。
可以通过 IDEA 的 Diagrams
功能去了解一个类的继承关系。
多打断点调试,断点追踪源码是很好的阅读源码的方式,可以先通过 debug
了解下调用逻辑,都和哪些类有关联,有大致了解后再通过 debug
了解整体代码的功能实现,各个类都起到了什么作用,有没有涉及到设计模式等。
另外,优秀的开源项目中肯定会有许多地方应用到了设计模式,建议在阅读源码之前,需要对常用的设计模式有大致的了解,不然阅读源码的效率会大大降低。
如果遇到读不懂某部分源码的时候,可以先跳过,之后再回来看,如果属于搞不懂这部分就茶不思饭不想的人,可以在网上找是否有该部分源码的解析或者文档,也可以自己通过源码注释和测试用例去阅读学习。
一般优秀的开源项目都会有单元测试,可以通过对应类的单元测试去了解方法的含义和用法,加深对源码逻辑的理解。
在阅读源码的时候,可以在代码上加上注释和总结,同时还可以画出时序图和类图,这样对阅读源码有很大的帮助,可以很清楚地知道类之间的调用关系和依赖关系,也方便以后回顾,重新阅读。
在这里推荐大家一个 IDEA 插件 SequenceDiagram
,可以根据源码生成调用时序图,便于阅读源码。
刚开始阅读源码,不建议直接看框架源码,可以先从 jdk 源码看起:
jdk 源码也是非常庞大的,可以分模块来阅读,下面是建议的阅读顺序:
java.lang
包下的基本包装类(Integer、Long、Double、Float
等),还有字符串相关类(String、StringBuffer、StringBuilder
等)、常用类(Object、Exception、Thread、ThreadLocal
等)。java.lang.ref
包下的引用类(WeakReference、SoftReference
等)java.lang.annotation
包下的注解的相关类java.lang.reflect
包下的反射的相关类java.util
包下为一些工具类,主要由各种容器和集合类(Map、Set、List
等)java.util.concurrent
为并发包,主要是原子类、锁以及并发工具类java.io
和java.nio
可以结合着看java.time
主要包含时间相关的类,可以学习下 Java 8 新增的几个java.net
包下为网络通信相关的类,可以阅读下Socket
和HTTPClient
相关代码
其他包下的代码也可以做下了解,JDK源码阅读笔记:https://github.com/wupeixuan/…
再有了一定的源码阅读经验后,可以再去学习 Spring、Spring Boot、Dubbo、Spring Cloud
等框架的源码。
总结
本文主要介绍了为什么读源码以及如何读源码,供大家参考,每个人都有适合自己的阅读源码的方式,希望可以在学习中去摸索出一套属于自己的方式。
阅读源码不是一蹴而就的,这是持久战,只要你能够坚持下来,肯定受益匪浅。阅读源码的过程比较枯燥,可以在社群里一起讨论学习,这样可能效率更高些。
写得不好的或者大家有什么更好的建议,也欢迎留言讨论。
最好的关系就是互相成就,大家的在看、转发、留言三连就是我创作的最大动力。
参考
《Java并发编程之美》
《程序员修炼之道:程序设计入门30讲》
面试官系统精讲Java源码及大厂真题
解锁大厂思维:剖析《阿里巴巴Java开发手册》
阅读源代码的能力算是程序员的一种底层基础能力之一,这个能力之所以重要,原因在于:
- 不可避免的需要阅读或者接手他人的项目。比如调研一个开源项目,比如接手一个其他人的项目。
- 阅读优秀的项目源码是学习他人优秀经验的重要途径之一,这一点我自己深有体会。
读代码与写代码是两个不太一样的技能,原因在于“写代码是在表达自己,读代码是在理解别人”。因为面对的项目多,项目的作者有各自的风格,理解起来需要花费不少的精力。
我从业这些年泛读、精读过的项目源码不算少了,陆陆续续的也写了一些代码分析的文章,本文中就简单总结一下我的方法。
先跑起来
开始阅读一份项目源码的第一步,是先让这个项目能够通过你自己编译通过并且顺利跑起来。这一点尤其重要。
有的项目比较复杂,依赖的组件多,搭建起一个调试环境并不容易,所以并不见得是所有项目都能顺利的跑起来。如果能自己编译跑起来,那么后面讲到的情景分析、加上调试代码、调试等等才有展开的基础。
就我的经验而言,一个项目代码,是否能顺利的搭建调试环境,效率大不一样。
跑起来之后,又要尽量的精简自己的环境,减少调试过程中的干扰信息。比如,Nginx使用多进程的方式处理请求,为了调试跟踪Nginx的行为,我经常把worker数量设置为1个,这样调试的时候就知道待跟踪的是哪个进程了。
再比如,很多项目默认是会带上编译优化选项或者去掉调试信息的,这样在调试的时候可能会有困扰,这时候我会修改makefile编译成-O0 -g
,即编译生成带上调试信息且不进行优化的版本。
总而言之,跑起来之后的调试效率能提升很多,而在跑起来的前提之下又要尽量精简环境排除干扰的因素。
明确自己的目的
尽管阅读项目源码很重要,但是并不见得所有项目都需要从头到尾看的清清楚楚。在开始展开阅读之前,需要明确自己的目的:是需要了解其中一个模块的实现,还是需要了解这个框架的大体结构,还是需要具体熟悉其中的一个算法的实现,等等。
比如,很多人看Nginx的代码,而这个项目有很多模块,包括基础的核心模块(epoll、网络收发、内存池等)和扩展具体某个功能的模块,并不是所有这些模块都需要了解的非常清楚,我在阅读Nginx代码的过程中,主要涉及了以下方面:
- 了解Nginx核心的基础流程以及数据结构。
- 了解Nginx如何实现一个模块。
有了这些对这个项目大体的了解,剩下的就是遇到具体的问题查看具体的代码实现了。
总而言之,并不建议毫无目的的就开始展开一个项目的代码阅读,无头苍蝇式的乱看只会消耗自己的时间和热情。
区分主线和支线剧情
有了前面明确的阅读目的,就能在阅读过程中区分开主线和支线剧情了。比如:
- 想了解一个业务逻辑的实现流程,在某个函数中使用一个字典来保存数据,在这里,“字典这个数据结构是如何实现的”就属于支线剧情,并不需要深究其实现。
在这一原则的指导下,对于支线剧情的代码,比如一个不需要了解其实现的类,读者只需要了解其对外接口,了解这些接口的入口、出口参数以及作用,把这部分当成一个“黑盒”即可。
顺便一提的是,早年间看到一种C++的写法,头文件中只有一个类的对外接口声明,将实现通过内部的impl类转移到C++文件中,比如:
头文件:
// test.h
class Test {
public:
void fun();
private:
class Impl;
Impl *impl_;
};
C++文件:
void Test::fun() {
impl_->fun()
}
class Test::Impl {
public:
void fun() {
// 具体的实现
}
}
这样的写法,让头文件清爽了很多:头文件中没有与实现相关的私有成员、私有函数,只有对外暴露的接口,使用者一目了然就能知道这个类对外提供的功能。
“主线”和“支线”剧情在整个代码阅读的过程中经常切换,需要阅读者有一定的经验,清楚自己在这段代码的阅读中哪部分属于主线剧情。
纵向和横向
代码阅读过程中,分为两个不同的方向:
- 纵向:顺着代码的顺序阅读,在需要具体了解一个流程、算法的时候,经常需要纵向阅读。
- 横向:区分不同的模块进行阅读,在需要首先弄清楚整体框架时,经常需要横向阅读。
两个方向的阅读,应该交替进行,这需要代码阅读者有一定的经验,能够把握当前代码阅读的方向。我的建议是:过程中还是以整体为首,在不理解整体的前提之前,不要太过深入某个细节。把某个函数、数据结构当成一个黑盒,知道它们的输入、输出就好,只要不影响整体的理解就暂且放下接着往前看。
情景分析
假如有了前面的基础,已经能够让项目顺利在自己的调试环境跑起来了,也明确了自己想了解的功能,那么就可以对项目代码进行情景分析了。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
进行,这需要代码阅读者有一定的经验,能够把握当前代码阅读的方向。我的建议是:过程中还是以整体为首,在不理解整体的前提之前,不要太过深入某个细节。把某个函数、数据结构当成一个黑盒,知道它们的输入、输出就好,只要不影响整体的理解就暂且放下接着往前看。
情景分析
假如有了前面的基础,已经能够让项目顺利在自己的调试环境跑起来了,也明确了自己想了解的功能,那么就可以对项目代码进行情景分析了。
[外链图片转存中…(img-JTdbRnmq-1715387429916)]
[外链图片转存中…(img-O26rkGh8-1715387429916)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!