如何学习开源项目?

勇哥微信公众号约 2517 字大约 8 分钟

二哥,开源项目该怎么学习啊,我从Github直接下载源码部署使用,总感觉没有自己写的记忆来得深,但自己从头写项目又感觉有心无力,不懂该从何写起#球友提问✍🏻️#

这是球友小柏在星球上提的一个问题,我们今天就来聊一聊,我觉得还是蛮有意义的,这个帖子我也会顺带同步到《Java 面试指南》专栏里的《技术提升篇》,访问方式:https://t.zsxq.com/6iuzn6Iopen in new window

我经常给大家强调,尤其是工作了几年的球友,有一定的项目经验,对编程也有了自己的理解,想要再继续提升自己,就需要去主动学习开源项目了。

那到底该怎么学习开源项目呢?有什么方法吗?开车🚗

一、学会使用

首先,我们需要学习如何使用开源项目

Github 是全球最大的在线软件源代码托管服务平台,很多开源项目都托管在他上面。码云上也有非常多优质的开源项目,比如说那些 GVP 项目,我之前给球友们推荐过一次:https://t.zsxq.com/07X49ztINopen in new window

在 GitHub 下载源码后,需要重点关注类似 Quick Start,Getting started ,Example 之类的文档,这些文档会告诉我们该如何使用项目。

假如项目需要部署,可以参考项目文档,在独立的环境中尝试从零开始动手部署该项目。

某些项目也会提供完善的 example 工程,里面有现成的例子,可以尝试按照文档介绍运行入门例子。

如果入门例子运行顺利 ,对于我们来讲是一个很好的开始。若运行中出现异常,也不必慌张,寻找项目中 FAQ 文档(可以跑去 issue 区看看,很多问题可能之前就有人提出并得到了官方的解答),或者搜索出现问题的关键字(比如异常信息),查询相关的解决方案。

成功运行了项目中第一个基础例子之后,可以尝试运行更复杂的功能例子。

二哥建议单独创建一个工程,一个一个功能例子完善整个项目。当这个项目越来越充盈,也就证明你掌握得越多。在学习过程中,最好将学习的心得记录在笔记中,便于后续回溯。

二、阅读源码

阅读源码是深入理解开源项目最重要的一步

阅读源码之前,尝试从源码构建该项目。通常开源项目都会提供一份构建指南,指导你如何搭建一个用于开发、调试和构建的环境。构建成功后,尝试运行该项目。

查看该项目的架构设计文档,梳理出整个项目的骨架,可以画流程图或者 UML 图(思维导图也可以),加深对项目的理解。

当我们了解到整个项目的骨架后,可以挑选感兴趣的模块来阅读,比如你对网络通讯感兴趣,就阅读网络层的代码,深入到实现细节,如它用了什么库,采用了什么设计模式,为什么这样做等。如果可以, debug 细节代码。

阅读源码的时候,重视单元测试,尝试去运行单元测试,基本上一个好的单元测试会将该代码的功能和边界描述得很清楚。

二哥体系化的阅读源码是在2011年,当时刚入职没多久,平常只能打打杂,后来机缘巧合下了解到公司将来的技术栈重心,就去研究了 flex 组件库的源码,给后来我晋升 team leader 埋下了伏笔。再后来,就是 2017 年左右,因为对消息队列非常感兴趣,同时也迫切想了解网络编程框架 Netty 到底是如何使用的。

于是,先从 RocketMQ 网络通讯模块 remoting 开始学习,因为源码中有完善的测试用例,先运行单元测试,学习网络编码模型。

在学习网络编程的过程中,二哥有两点思维突破:

▍一、客户端的编程模型

RocketMQ 客户端网络通讯有如下三种方式:

  • oneway : 单向发送
  • sync :同步调用
  • callback :异步回调

很多技术的思想是相通的,下图是蚂蚁开源的通讯组件 sofa-bolt 支持的调用类型。

蚂蚁通讯框架Bolt调用类型
蚂蚁通讯框架Bolt调用类型

▍二、服务端处理器模式

RocketMQ 服务端通讯使用经典的 Reactor 模式,服务端注册不同的业务处理器,而各个业务处理器可以绑定不同的线程池。

void registerProcessor(

      final int requestCode, 

      final NettyRequestProcessor processor,

      final ExecutorService executor);

学完网络框架 Remoting 之后,然后结合 Broker 模块,学习 RocketMQ 存储模型,通过这种方式就可以对 RocketMQ 有了一个相对清晰的认识。

三、知行合一

前些年,读李开复老师的书,书中有一句话,我印象深刻:“I Hear and I Forget, I See and I Remember, I Do and I Understand ” 。

中国古代哲学家荀子也说过:"不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之;学至于行之而止矣"。

学习源码的过程中,将知识点夯实的关键要诀是动手实践,并保证实践之后有输出产物,也就是知行合一

二哥总结了两点经验,供大家参考。

▍一、源码中的知识点应用到项目中

开源项目中有非常多的优秀实践 ,可以将代码中的编码技巧,设计思想,优秀源码引进到业务项目里。

2016 年,我们公司的优惠券计算服务遇到性能瓶颈,二哥负责重构这个系统。在阅读 RocketMQ 源码后,学习到了线程池使用精髓:线程池隔离,各司其职

于是,二哥先梳理出业务场景,根据任务类型,绑定不同的线程池,为了便于扩展同时对外暴露并发度的配置参数。在重构这个系统的过程中,还引入 RocketMQ 创建线程工具类代码 。

重构之后,不仅系统的性能提升了5倍,而且二哥的自信心也大大提升,对技术的理解也更加深刻。

▍ 二、造轮子

当我们学习完了一个开源项目,可以参考开源源码仿写一个。仿写的过程就是查漏补缺的过程,也能完善自己的知识体系。

2016年,sharding-jdbc 开源了,下图是当时 sharding-jdbc 的架构设计图:

二哥当时对分库分表着迷,同时脑海里有很多疑问,比如如何封装 jdbc 的接口,如何实现 SQL 解析 ,如何将多个分片的结果聚合等。

于是,二哥参考 sharding-jdbc 的源码,仿写了一个分库分表组件。

经过这次仿写,二哥深入实践了 client 模式分库分表的原理,并积累了自己的技术储备。

四、参与开源

“开源理念之一就是非常鼓励不同的人一起合作”。——Linux 之父 Linus Torvalds 2016 年 2 月 TED 演讲《The mind behind Linux (opens new window)》

在《教授鼓励学生参与开源项目的 5 个理由》这篇文章里,提到了如下五点理由:

  1. 无边界的学习
  2. 专业的交流
  3. 外在的机会
  4. 更深入的理解计算机科学

那么程序员如何参与开源呢 ?参与开源有很多种方式,最常见的有如下几种:

  1. 直接参与开源项目的开发
  2. 参考开源项目的社区比赛
  3. 修复开源项目中的 Bug
  4. 开源项目文档编写
  5. 参与开源项目的测试和 Demo 编写工作
  6. 参与开源项目推广

参与一个开源项目,并与许许多多同样聪明的工程师协作,把脑海中的奇思妙想一一实现,是多么美好的事情。

五、写到最后

亲爱的球友们,当你不知道选择哪一个开源项目开始学习时,希望你**立足当下,**当前技术团队使用的开源组件,正是你学习的方向。

行动起来,相信你会成为更好的自己,加油。

就像二哥之前说的,先从一个简单的项目开始,比如说你要入门 Spring Boot,直接上手编程喵或者若依就足够了,这样简单的项目就能让你掌握整个 Spring Boot 项目的开发流程和涉及到的技术栈,比如说 SpringSecurity、JWT、OSS 等等。

再比如说,你们公司自研的组件库,或者正在开发的项目,也是非常值得花时间去学习的,如果原有的技术栈比较旧,最后在本地能再跑一个新的技术栈,然后把业务实现一遍,完成改造。

如果你所在的公司体量比较大,项目比较复杂,那就最好从 1.0 版开始研究,这样能节省掉大量的学习成本,毕竟 1.0 版肯定是基于先跑通业务的基础上做出来的,技术不会搞得太难。

就像如果你要学习 JDK 源码,最好从 Java1.6 或者 Java8 开始学起,不要直接去搞最新的版本。

以上,希望能给大家一些帮助和启发。

参考链接:https://mp.weixin.qq.com/s/nWdzvy76YV4sKqmu6znfQgopen in new window