如何深入理解开源项目

感谢这个时代,我们有了github,有了近乎无穷的开源项目可以看,可以学。

记住,看的目的是学,但是看不等于学

从小代码集看起

对于一个新手,是绝对不适合一上来就追求spring,web容器,数据库这种级别的代码。万事开头总是要从简单的来。如果没有太多阅读开源代码经验的话,请从一个代码量在千行级别或更小的repository开始吧。在阅读代码中,也慢慢留意一些约定,如

  • 代码的文档一般写哪里了(README.md ? 或者 docs目录?)
  • 代码的起名字和目录组织大概遵循什么规范
  • 代码如何配置
  • 代码如何build

这些将帮你构建一个初步的可以深入代码的路径,并为进一步深入理解代码打基础。

这一点不得不夸一下javascript的npm。npm有相当多的很小的好代码。老牌web框架express的代码数才4000多行。一些小工具比如随机字符串产生器、分布式ID产生器只有数十行。非常适合入门学习。

聚焦

有多少人是抱着一颗不切实际的预期去看代码的?有人说,我Java想提升一下去看看Spring吧;有人说我Web没有太理解,去看看Tomcat吧。结果可想而知。正像问问题时不应该问过于宽泛的问题,看任何代码都不应该抱有看一遍全都看懂的期望——因为就连代码作者自己都做不到。

写代码时往往都会做一些抽象,把某个特定问题拆解。比如分层、比如抽象为一个class代表一个实际的概念等等。每个抽象都可能解决一个具体的问题。看代码也是如此,一定要先聚焦,把看代码的scope限制住,不要贪多。

比如当看Java Collections代码,可能是希望学习其数据结构的实现方式——到底链表、树、跳表等是怎么实现的,内存中一个个object是如何关联起来的,如何被快速访问的;又或者是特定算法的实现(比如Collections.sort用的是什么排序算法)。此时,其他的部分就不要太过于在意,直接忽略那些抽象隐藏起来的地方,以及不相关的细节。

对于更复杂的服务就更要聚焦。比如Jetty解决了相当多问题,比如:如何启动、如何找到Java Runtim、如何加载配置文件、如何load核心class、如何打log如何处理IO、如何解析HTTP协议的数据、如何将数据转换为Servlet标准的处理、如何管理集群…… 并且,这些代码里还会夹杂着一些设计模式的层,比如XXXXFactory,XXXXAdaptor…… 如此复杂的代码,即使是很有经验的人也不可能兼顾着在短时间内全看懂。所以,每次看代码之前,务必先确定一个要学习的目的。如果代码量很庞大,就可以安排一个学习计划,每次聚焦于一个目的。

对于像Java这样的面向对象语言,优秀的设计往往都是基于一组代表概念的类生成的对象的相互交互。学习代码时,优先去看类名,组织起高层的全局感非常重要。比如,如果希望学习一个“驾驶模拟”系统的代码中有关“如何驾驶”的部分,一定会找到代表操作人、油门和方向盘概念的类。然后去观察他们是如何互动的。此时绝对不该扯上变速箱、发动机和传动轴。

作为像C这样的语言,其源码大致是面向过程的,即分多个步骤做一件事,每个步骤再细分为更多子步骤。例如,nginx分配一段内存来存储一个http请求头就大概包括

  1. 利用一个工具函数分配指定大小的内存
  2. 从socket中将数据读出来,并填充到分配的内存上

而第一步可以进一步细化为:从一个内存池把一段内存借出来,如果没有可用内存了就得找操作系统要,要到了内存可能还需要填充为零……等等子步骤。这时预先画画流程图对理解代码会非常有帮助。

总之,如果你被庞大的源码打败,大概率不是因为你笨,而是因为你过于贪心急躁了。

请先看文档

任何代码,总得有个出现的动机和大致的工作原理。好的代码一般会在文档里(一般是README.md)里讲得比较明白。比如Redis的源代码的README.md就给出了非常概要性的信息,见https://github.com/antirez/redis。如果还需要对某个特定的主题的解释,Redis官网也提供了大量的文字来说明,比如

这些文档能非常好的指导阅读相关的源代码。

更复杂的开源系统往往都有对应的书籍来解释其内部工作原理。比如,《MySQL技术内幕:InnoDB存储引擎》是很好的指引如何理解InnoDB源代码的书,大名几乎每个做业务的同学都会接触到;当年侯捷先生的《深入浅出MFC》非常细致的剖析了MFC内部的C++是怎么把本来C++运行时做不到的事情通过一些歪招给搞定的;《C专家编程》(又称鱼书),用很多小例子来解释比如一个复杂的函数指针的是怎么被parse的,变量是如何被保存和传递的。等等等等。

如果你阅读的是著名系统的源代码,请尽量先从文档/书籍入手找到切入点,往往能事半功倍。对于可读性,给人写的东西总是好过给机器写的东西啊。

关注资源的生命周期

有生产意义的系统一般总是会有一些核心的资源需要管理,而这些资源的生命周期的维护往往是这类系统代码的核心。

比如

  • 对于spring-core来讲,其核心资源是“Bean”。一个Bean被创建、初始化、被使用、被解构,是整套代码的核心;
  • 对于spring-webmvc,其核心资源是“HTTP 请求”。一个http请求从被收到开始、其数据被注入到请求handler,其返回的数据结构被设定,是整套代码的核心;
  • 对于一个池 (比如commons-pool,thread-pool),其核心资源是池中的Object。Object从创建,被借出,被使用,被归还,到最后被销毁,是整套代码的核心

数据库系统、队列系统、web系统、一些业务系统(比如做活动、发红包)、安全系统等等,都有这样的资源的存在。把握住核心资源的生命周期就能掐到代码的命门。

找一个好工具

很多年前我们做C开发时都喜欢用一款叫做"Source Insight"的软件来学习代码。他可以开很多窗口,在不同的函数间跳来跳去,还可以做书签方便定位。

如今,基本上是个IDE都会有这些功能,就连没有类型的js也能很方便的在VS Code中做各种符号跳转和多串口切换。

代码嘛,了解其执行顺序,而非其写作顺序更有利于学习。

建立调试环境

如果对于某些系统需要特别细致的理解,就需要把代码跑起来。通过打断点,输出log验证等方式印证自己的想法。

对于js,python这类会相当简单,因为npm/pip等工具解决了很多依赖问题,而且无需编译,直接启动-修改-重启-修改-……即可不断的尝试。jvm类的系统只要能满足mvn install或者gradle build这样的通用编译约定,或者通过IDE直接加载,也能相对容易的把系统跑起来。

对于C/C++的系统就要麻烦许多,需要自己建立一个虚拟机,然后自行安装必要的包。对于它们,远程GDB之类的技术是非常必要的。

对于前端代码,使用jsfiddle配合chrome开发工具这样的工具可让你快速的构建一段js+html+css代码的片段,并且实时的看到效果。

值得提一句的是,有些系统可能涉及到比较复杂的多进程/线程并发执行,对调试学习非常不利。此时需要优先寻找将系统退化到单线程/进程的运行方式(毕竟代码作者自己也得靠这个模式调试不是:)。一个典型的例子是nginx通常会有1个master进程+多个worker进程并发运行,但在开发时只要配置中设定:

daemon off;
worker_processer 1;

即可使其退化为单进程运行时模式。

看代码很累,要坚持

就像跑步能跑多远,跑多久,都是要靠自己。阅读代码的确能极大地提高个人能力。但是能走多远要靠毅力坚持。而坚持的大敌就是过大的挫折感。上面提到的种种方法——从简单的入手、聚焦、有计划、找好工具,说白了就是尽量减少挫败感,最大限度的提高“正反馈”。但是即便如此,不可否认的是,对于大多数人,看代码是一项非常枯燥的过程。这时你的恒心,你的毅力,你的“熬”的劲头决定了你能走多远。毕竟,想成为高级程序员并不是轻轻松松的事情。

横下一条心来,挑战自我吧。


最后附上部分我曾经看过的高质量开源代码:

  • nginx
  • MFC
  • Redis
  • Lucene
  • Jetty
  • Kafka
  • Thrift
  • Java Executors
  • Java Collections
  • Java Concurrecy
  • express
  • koa
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,799评论 25 707
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,213评论 11 349
  • 看到朋友们都在讨论思维导图,自己也试了试。今天终于弄好了,相比较昨天自己手绘的图自己向前迈进了一小步。现在还不能...
    孙小宁阅读 214评论 0 0
  • 最近几个关系很好的朋友出来聚了一番,一个朋友(男)心情很不好,因为女友拒绝和自己上床,关系闹得很僵,最后导致分手。...
    驻马店大表哥阅读 2,628评论 0 0
  • 医院,现在的人民,一讲医院就魂飞魄散又不得不直面对去的地方很是无奈,人们字字语语所表达出来了的并不全是对死亡的恐惧...
    寒冰英子阅读 111评论 0 0