如何深入理解开源项目从小代码集看起聚焦请先看文档关注资源的生命周期找一个好工具建立调试环境看代码很累,要坚持

感谢这个时代,我们有了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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏iOS122-移动混合开发研究院

记一个同时支持模糊匹配和静态推导的Atom语法补全插件的开发过程: 序

简介 过去的一周,都睡的很晚,终于做出了Atom上的APICloud语法提示与补全插件:apicloud_autocomplete.个中滋味,感觉还是有必要记录...

19860
来自专栏Golang语言社区

【Go 语言社区】在 Go 语言中,如何正确的使用并发

Glyph Lefkowitz最近写了一篇启蒙文章,其中他详细的说明了一些关于开发高并发软件的挑战,如果你开发软件但是没有阅读这篇问题,那么我建议你阅读一篇。这...

36690
来自专栏牛客网

腾讯一面应用开发

最遗憾的,叫写冒泡排序都能写数组溢出,非科班面对算法题真的紧张。凉凉。 面试官是做php的,我用java。 问了http和https的区别。 答: 后者是前者的...

30260
来自专栏更流畅、简洁的软件开发方式

您把哪些东东看成了对象?

     我们初学面向对象的时候,书里面往往会用小猫、小狗、鸭子、汽车等举例子,说是可以把这些看成是一个对象,然后再弄出来一些属性、方法、事件等进行说明。   ...

202100
来自专栏Golang语言社区

在 Go 语言中,如何正确的使用并发

Glyph Lefkowitz最近写了一篇启蒙文章,其中他详细的说明了一些关于开发高并发软件的挑战,如果你开发软件但是没有阅读这篇问题,那么我建议你阅读一篇。这...

20700
来自专栏架构专栏

互联网公司想月薪15K挖走大牛程序员网友:欠你的吗

@路比咯:这程序员很实在,都说到点上根本不浪费彼此时间,个人感觉是这个HR气量太小反应过激才说了这些鬼

27940
来自专栏北京马哥教育

高性能服务器架构里的隐藏秘密

作者:Coder李海波 来源:http://blog.csdn.net/marising/article/details/5186643 在提到服务器架构时,...

35740
来自专栏EAWorld

生成全局唯一ID的3个思路,来自一个资深架构师的总结

标识(ID / Identifier)是无处不在的,生成标识的主体是人,那么它就是一个命名过程,如果是计算机,那么它就是一个生成过程。如何保证分布式系统下,并行...

70260
来自专栏小巫技术博客

那些Android中的性能优化tips

10720
来自专栏Java技术栈

TBSchedule应用实战之“性能怪兽(集群篇)“

本节的重点将采用原生java,tbs和xxl-job三个模型来测试处理50万业务数据,总结他们的差异,向读者朋友们展示为什么作者称tbs为性能怪兽。 本节以实际...

39270

扫码关注云+社区

领取腾讯云代金券