目录
零、开源项目是什么?
开源项目不仅仅是开放源代码,起码要满足四点:
1、开发项目中所有源代码以及配套工具
2、完善的文档,如新手入门文档、项目整体架构设计文档、模块的详细设计文档、配置说明文档以及注意事项。
3、活跃的社区
4、持续的更新和完善
一、初步了解
1、走读官网文档(至少一遍)
有多少人愿意花时间好好看官网文档的?估计很少,大家一上来就是开始撸代码,强撸!!!
常见的几种错误:
1) 一头扎进代码细节,直到怀疑自我
我国的教育体系主张研究透底层机制后,才开始动手实践,其实并不然,俗语:“知其然,然后知其所以然”,学技术也是如此,先知道大概是什么样,然后才能逐渐的研究其原理。
人的认知过程是从观察、模仿、亲身实践、总结经验或教训,然后逐渐学会一项技能,此技能练习千百次,才慢慢窥探到其底层原理。
一个人想直接透过问题表象看到问题本质,是很难的。
2) 未阅读完操作文档,就着急动手实战,得不偿失
为赶项目进度没好好看文档就匆匆忙忙的撸代码,代码运行后有很多稀奇古怪的问题,再回过头来排查这些问题,发现是自己的使用方式有问题,而这些在文档中已明明白白的写的很清楚。
3) 多参与开源社区,闭门造车要不得
虽然网上的技术博客,专栏,公众号平台或视频课程都会针对某个技术做讲解,但是我依旧推荐
推荐你看官网的一手资料
为什么这么说呢?
时代在发展,开源软件也在不断的进化,,从时效性和内容准确性上都要比中文技术博客的内容要好的多。
重点关注下Get Started和Example之类的文档,能够帮助更快的入门。
重点看文档中什么内容:
1、开源项目背景
采用了什么技术?
提供了什么功能或特性?
解决了什么问题?
2、适用场景
优点是什么?
缺点是什么?
适用于什么场景?
不适用什么场景?
明确了适用场景,才能在架构选型时有的放矢。
3、哪些公司在生产环境中使用
有多少公司在生产环境中部署并维护过此开源项目?
一方面经历过生产环境的项目质量相对较好,即使有bug其他公司或多或少也遇到过,自己解决起来不至于孤立无援。
可以从侧面证明项目很有潜力和竞争力。
2、了解代码目录结构
在下载源代码之后,先看下代码目录的组织结构,可先从示例代码或测试代码入手。
如
base代表基础库
net代表网络库
demo/example代表示例代码
tests:测试代码
docs:文档目录(类图,流程图,活动图,业务知识相关资料等)
入手之初,建议从例子代码或测试代码开始看(demo,example,test)
3、在安装部署前补充新概念、新技术
在已有的知识体系之上去学习新的开源项目,需要对新概念或新技术有个大致的了解,才能更好的理解项目的整体实现思路,做起事情来事半功倍。
千万不要一上来就看代码,核心概念不清楚,核心原理不懂,核心算法没吃透,看代码很难看懂。
二、安装部署,运行(很重要!)
2、1 成功运行并简化环境
好的开源项目,其文档都比较完备,安装部署文档一般会在README中或者doc目录中,甚至提供rpm安装包和docker镜像
如果官网提供qq群或微信群,也可以加下,毕竟里面有不少技术资料可供参考。
将程序运行起来!!!
将程序运行起来!!!
将程序运行起来!!!
重要的事说三遍,程序运行起来有,我们就有了直观感受。
就我的经验而言,一个项目代码,是否能顺利的搭建调试环境,效率大不一样。
跑起来之后,要尽量的精简自己的环境,减少调试过程中的干扰信息。
比如,Nginx使用多进程的方式处理请求,为了调试跟踪Nginx的行为,我经常把worker数量设置为1个,这样调试的时候就知道待跟踪的是哪个进程了。
比如有些环境是分布式的,那么我们部署个单机版本的用来学习和做实验,也算是化繁为简。
2、2 成功运行意义何在
首先,便于从视觉感官上体会项目的功能,对开源项目的功能从宏观上能了解一些。
其次,下断点-> 调试-> 修改代码 -> 观察现象 ->再调试,查看是否符合修改的预期,一点点理解程序的逻辑
最后,方便截图,截牛逼的图去吹牛逼,哈哈,2333~
玩起来,嗨起来,搭建成功后必须装逼起来,哈哈
三、运行并研究Example例子
example目录:例子目录,先通过例子上手学会如何使用此开源项目
安装部署好项目,成功运行并直观体验到项目功能后,从总体转到局部,来好好看下example例子中的代码。
3、1 最简单的入门例子
简单的入门例子,代码行数一般在50行左右,摒弃了复杂的处理细节和框架的高级特性,便于读者尽快熟悉项目的主干和核心模块。
简单例子也可能遇到问题,此时可通过邮件列表、社区、Issue来解决遇到的问题。
熟悉简单例子的过程中,对于有疑问的地方先记录下问题,后面带着问题去阅读源代码解决心中疑问
3、2 逐步研究更复杂的例子
熟悉简单例子后,也可阅读些更复杂的例子,熟悉例子代码的过程,就是熟悉开源项目api接口的过程。
中间会对照代码来查看api文档,了解接口的参数、返回值以及注意事项。
进阶:手动修改代码来验证自己心里的想法,看看例子是否能正常运行?如果运行失败报错,则查找其原因,排查问题。
3、3 手写个人demo
如果公司使用的开源项目实在没有example例子,可考虑自己根据公司需求编写一个demo例子,编写demo的过程,是检验自己是否对api接口熟悉的过程。
四、针对部分组件,阅读其测试用例
如果测试用例写的很仔细,那么很值得好好去研究一下。
原因在于:测试用例往往是针对某个单一的场景,独自构造出一些数据来对程序的流程进行验证。
test目录:测试目录,学习下单元测试是如何写的
通过看单元测试用例,可了解到某个类或某个组件是如何使用的。
先学会如何使用,然后再去从源代码角度理解实现原理,使用过程中遇到了问题或者疑惑,带着问题去阅读源代码,这个效率杠杠滴。
五、阅读源代码之前必读
5、1 看代码之前认真看文档
一个好的开源项目是有完善的文档的,比如百度开源的RPC框架brpc
docs目录:
库的开发入门指南,代码的风格文档,程序的命令操作手册,程序中采用的第三方库
类图,流程图,活动图,架构图,设计文档
业务相关基础知识介绍文档
项目技术细节详细介绍
阅读这些文档可以了解该项目的大体设计和结构,读源码的时候不会无从下手。
务必要耐心好好的看,多看多实践多思考,少BB
六、阅读源代码
6、1 明确阅读代码的目的
在开始阅读代码之前,首先要明确自己的阅读目的:
是需要了解其中一个模块的实现?比如基础模块还是业务模块?基础模块中有内存池、线程池、网络数据收发epoll模型等
还是需要了解这个框架的大体结构,
还是需要具体熟悉其中的一个算法的实现,等等。
心里很清楚自己想要什么,才能更有动力去朝着目标努力奋斗。
6、2 区分主线和支线剧情
阅读源代码时,分清主线和支线
先看主线:
想了解一个业务逻辑的实现流程,中间调用了第三方库函数、utils函数、定制的数据结构和算法等,其实不需要了解其内部实现;
只需要了解其对外接口,了解这些接口的入口、出口参数以及作用,把这部分当成一个“黑盒”即可。
再看支线:
在对主线有充分了解前提下,可以考虑打开“黑盒”研究下其内部实现,比如看看内存池的实现代码,调度器的代码,dpdk中对于海量数据包是如何处理的等。
具体做法:
从main函数进入,使用gdb单步跟踪理清一次完整流程(如程序初始化)的代码调用路径,这可以通过debug来观察运行时的变量和行为。
6、3 挑选感兴趣的“分支”来阅读
这里的分支指的是功能或版本:
从功能上说:
比如你对网络通讯感兴趣,就阅读网络层的代码,深入到实现细节:
如它用了什么库,
采用了什么设计模式,
为什么这样做等。
如果可以,debug细节代码。
从源代码版本上说:
不一定选择最新版本的开源代码进行阅读,如果感觉有点吃力,可选用同一个开源项目的老版本(如1.0版本),
此时的项目代码,不管是代码量还是复杂度上都要小很多,看起来要容易的多。
6、4 理清核心数据结构
程序设计 = 数据结构 + 算法
因为结构定义了一个程序的架构,结构定下来了才有具体的实现。好比盖房子,数据结构就是房子的框架结构,如果一间房子很大,而你并不清楚这个房子的结构,会在这里面迷路。
而对于算法,如果属于暂时不需要深究的细节部分,可以参考前面“区分主线和支线剧情”部分,先了解其入口、出口参数以及作用即可。
Linus说: “烂程序员关心的是代码。好程序员关心的是数据结构和它们之间的关系。”
因此,在阅读一份代码时,厘清核心的数据结构之间的关系尤其重要。
6、5 添加日志 and 单步调试(情景分析)
看文档或看代码的过程中,对一些技术点,是需要验证的。
所谓的“情景分析”,就是自己构造一些情景,然后通过加断点、调试语句等分析在这些场景下的行为。
我惯用的做法,是在某个重要的入口函数上面加上断点,然后构造触发场景的调试代码,当代码在断点处停下,通过查看堆栈、变量值等等来观察代码的行为。
情景分析的好处在于:不会在一个项目中大海捞针似的查找,而是能够把问题缩小到一个范围内展开来理解。
从而把个人的时间和精力聚焦到一个小的范围内不断的研究,一直研究到自己满意为止。
修改源码加入日志和打印可以帮助你更好的理解源码。
gdb单步调试,一步步跟踪,是了解源代码最好的途径,没有之一。
6、6 画图梳理逻辑
适当画图来帮助你理解源码,在理清主干后,可以将整个流程画成一张流程图或者标准的UML图,帮助记忆和下一步的阅读。
画图虽然很浪费时间,但是对帮助理解架构和流程很有帮助。
6、7 解决遇到的问题
相信经过前面三个阶段,你已经是各种玩,各种瞎折腾,心里还是有很多疑问吧?
这个功能真牛逼,是如何实现的呢?
我的配置文件为什么没有生效呢?
程序为什么被我搞挂了呢?
我添加的打印为什么没有被执行?
打印的值为什么不符合我的预期?
好!很好!带着这些你心里的问题,去源代码中找答案吧
1.先总体后局部,把握好主体逻辑代码,然后再逐层深入下去
一上来就陷入太多的实现细节是大忌!!!
熟悉主体逻辑后,你大概能知道你感兴趣的代码处于整个项目中的什么模块,什么文件,什么类中
是个什么样的处理流程,定位到具体代码,一行行的分析它,这个过程会持续一段时间。
2.带着问题去看代码
一个系统实现了什么功能,为什么要实现这些功能,是基于什么业务场景?
3.思考自己如何实现类似系统(功能)
如果要我来实现一套类似的系统,我会如何来考虑问题,如何来实现这套系统?
然后再看看别人是如何实现的,找到两者之间的差距,并不断缩小之间的差距。
七、写笔记记录想法,促进思考和总结
1.记录解开问题谜团的过程
2.记录下开源代码中好的设计思想,好的代码技巧,以及任何你觉得好的东西
3.画整个程序的流程图,有利于理解程序的整个流程,而不被代码的细节所干扰。
4.坚持记录源代码学习笔记,记笔记能够有助于更深入的思考,以前很多问题只是浅层思考,不够深入
八、抄写项目源代码
以groupcache来举例,它包括lru,singleflight,protobuf,一致性hash这四个技术
步骤一:抄写前,可以大致了解下这些技术,比如lru是什么?lru解决什么问题?简单了解下lru的实现原理(后续深入具体实现)
步骤二:抄写过程中,会发现和之前了解的实现原理有不同的地方,比如有优化,或者有疑惑点,记录下来,继续抄写。
步骤三:抄写后,针对有疑惑的点,找资料,找人交流,必须搞清楚前面记录的不动的地方。
九、仿写项目
如果感觉自己对于项目理解的还不到位,我推荐一个笨方法,抄项目代码,抄着抄着你就懂了。
如果想进一步深刻的学习到源代码的精髓,可以仿写一个相近的程序进行操练。
理解了这个程序并不表明掌握了这个程序,只有在操练一个相近的程序时,才知道你到底理解了多少,掌握了多少
最近一直在仿写,或者说叫抄写开源项目,所以有点心得,整理一下:
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
自己写的东西,必须要合理的制作文档
仿写开源项目,按照如下思路来:
首先,熟悉开源项目,并熟练使用
其次,阅读开源项目源代码,梳理其流程和核心数据结构
再次,取主干,抛细节
以开源项目用一棵大树比喻,核心思想是剥离出开源项目的主干,去除掉繁杂的枝叶,以求能否更好的理解其设计理念和编码技巧。
最后,开始仿写开源项目代码。
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
十、教给他人(输出知识)
检验是否掌握一门技术,就是将知识输出,看他人能否听懂
当自己对项目的方方面面都很熟悉后,可以在B站上开直播,将自己所学的知识传授给他人。
输出形式:
1、csdn博客、知乎、头条、微信公众号等平台发文章
2、组内技术讨论或者微信群讨论
3、公司内技术分享会(正式)
3、在B站上直播
//以下是2021年更新的
更新日志:
2020-12-25 添加ch兄的学习方法论截图
2021-01-27 添加杨波老师的开源项目学习经验
阅读开源代码,一上来就陷入技术细节是大忌!!!
上图是ch总结的学习方法论,
核心概念:
总体架构
核心概念和术语
逻辑关系如何
从使用者的角度来看:
1、提供什么功能?
2、解决什么问题?
3、使用场景和限制是什么
4、如何来使用
横向对比:
功能上相似之处和差异
技术实现原理上相似之处和差异
从设计者角度:
1、为什么这么设计?
2、背后的思想和理论
3、如果我来设计,会从哪些方面来考虑?