利用开源代码和读相关论文来提高写代码能力


本文来自作者 李峰  GitChat 上分享 「利用开源代码和读相关论文来提高写代码能力」,阅读原文查看交流实录。

文末高能

编辑 | 哈比

越来越多的软件开源以及搜索引擎带来的便利,大大提高了工程开发效率。但是相对于程序员来说,这种效率的提高却给自身成长带来了很多困惑:

  • 对于大部分普通工程师来说,每天的工作内容只不过是在原有代码基础之上修修改改,用着框架做着重复单调的 CURD 工作,写着不痛不痒的业务代码,反过头来看自己所掌握的技能,觉的什么都会一点,可是都不精通,开始变的焦虑不自信;

  • 目前需独立开发一个全新系统,却毫无头绪,不知道怎么做架构设计;

  • 有些同学想通过学习开源代码来提高自己,可是一看到代码量这么庞大,却无从下手或者望而却步。

那么在平常的工作中如何提高自己的代码和架构能力呢?本文以相关代码为例子,具体说明如何读源代码和论文,并且掌握其中的思想来为我所用,最终可以做到写代码有理可寻,有据可依。

文章的大致结构:第一部分,开源代码,具体从熟悉、阅读、应用实践源代码三个阶段叙述;第二部分,论文,具体从论文阅读和论文应用实践两个方面论述;最后一部分总结。

一、开源代码

源代码被看做是学习的宝藏,从中可以学到很多先进思想和技术。很多同学都曾想通过读源码提高自己,可是面对这庞然大物,有的同学选择一头扎进去开始从头开始学,最后收获甚微,只能放弃,而有些同学则心生畏惧,望而却步,最终一无所获。

其实学习任何一新技能和知识,都需要经过一个过程,从熟悉,到深入,最后到实践为我所用,然后再继续熟悉,以此循环往复,整个过程需要付出很大的耐心和精力。

同样,阅读开源代码亦是如此,在开始这项工作前,一定要克服心理魔障,从战略上藐视对方,“哼,读源代码并没什么了不起的 “,战术上一定要重视。

做好充分的心理准备后,开始关于源代码的战术分析。

1. 熟悉

学习任何新东西都有一个熟悉的过程,切忌一开始直接下载源代码从头开始啃,这种方法只会事倍功半,而且很容易产生挫败感直至放弃。学习需要有一个循序渐进的过程。

在开始正式阅读源代码之前,首先要经历熟悉的三个阶段。

1.1 阅读文档,熟悉基本概念

在遇到一个新的软件,一定要先阅读文档了解其解决什么问题,涉及到的核心概念,每个模块的具体职责。如果不看文档直接打开源码,会发生什么事呢?

打开源码的瞬间,各种类的定义迎面而来,spout,tuple,stream,nimbus,一看是不是想死的心都有了。所以,事情说三遍,基本概念一定要弄清楚,概念越清楚,系统了解的越透彻。

常用文档 Read List:

  • 官方文档:常用的开源代码都有其公开的网站。

  • wiki:对应 github 仓库的 wiki 文档。

  • 系统对应的发表论文:比如 Bigtable、Zookeeper、Kafka 等都有论文发表。

这里以 storm 为例子:

文档中,storm 提出了一些新的概念,spouts,bolts,详细阅读这些名词背后所表述的含义以及在系统中担任的职责。

文档内容需要反复的读,每次读都会有不同的新的认识。

1.2 实践使用

具体实践活动:

  • 按官方文档部署相关软件,准备运行环境。

  • 写一个 hello world 的 demo 运行起来:开发包中一般存在文件夹名包含 starter 和 example 字眼的文件夹,该文件夹下会有许多官方使用例子。

  • 修改 demo 实现自己的业务逻辑。

这个阶段主要是模仿官方的例子实现自己的业务逻辑以及熟悉常用的 API。

在实践的过程中,会遇到各种问题,同时也会看一些相关技术文章,难点一点点攻破,系统的了解也会更深入。

1.3 构建数据流图

看到自己的代码可以正确的运行,成就感油然而生。但是,请收起你的放纵,这还远远不够,请继续下一阶段:构建数据流运行图。

程序的运行其实就是数据的流动运转,即数据是在模块之间流动交互的,数据从输入到输出,经历了哪些模块,以及模块之间如何协作。

刚开始构建数据流图不需要很详细,只要把文档中涉及到的核心概念联系起来即可,随着对系统的深入,回头反过来继续充实更多的细节内容。

例如,在学习使用 storm 时,会试着构建这么一个数据流图:

为什么要花时间构建这样一个图呢?

  • 理解概念,了解系统的运行机制;

  • 逼迫自己去思考,比如模块之间如何交互,数据流怎么流动。脑海里有越多的问题,看源码的动力就越足;

  • 随着对系统的逐渐了解,可以一步步完善,添加一些具体的实现细节,比如 task 如何知道输出结果应该发往那个 task 呢,其地址是多少呢?

  • 遇到问题时,可以依照该图猜测问题可能出在哪个模块,迅速找到切入点。

Tips:在分析系统时,可以从数据流动的角度来思考这个问题。

2. 阅读

通过熟悉阶段,脑海里积累了很多疑惑,已经迫不及待的开始要阅读代码解惑了。切记,阅读代码一定要化整为零,从小模块开始。具体过程则是提出问题,大胆猜想,小心验证。

阅读代码不是简单的读,而是一个思维碰撞的过程:大胆猜想非常重要。

当遇到一个技术问题时,首先一定要先独立思考,想一下:如果换作自己该如何解决以及实现这个功能,当有了自己的解决思路后,然后再对照源代码验证。当发现自己的思路跟作者是一样的,那种快感,哈哈,慢慢体会。

2.1 准备阶段

在开始具体的代码阅读时,还要做些技术储备。首先我会先看下该软件所依赖的外部库,从了解这些外部库开始。为什么要从这儿开始看呢?

其实软件开发就像搭积木一样,由一个个小的模块拼装而成,只有了解了每个小模块的正确使用方式,才能更流畅的剖析如何搭积木的。

这里以 JAVA 项目为例子,打开 pom 或者 gradle 文件查看,该项目依赖了哪些外部库。

这里是 storm 依赖的外部库,里面用到了 curator(zookeeper 使用)、kryo(序列化)、disruptor(生产者消费者模式库)、netty(网络)。这里需要额外花些时间研究下该库的解决的问题、使用方法和常用 API。

同时,这也是知识储备的过程,以后遇到类似的问题,可以联想到对应的库,为解决问题提供更多的思路。

2.2 切入阶段

有了一定的知识储备,就可以寻找切入点开始在代码的汪洋中尽情遨游。关于切入点的选择,自己有几点体会:

(1)从熟悉的基础依赖库入手,查看它在代码中是如何使用的。比如基础库中对 netty 使用比较熟悉,就直接找代码里对应的 handler 具体实现,pipline 的构成以及 netty 的设置管理等。

从自己熟悉的东西入手,一方面可以克服恐惧,同时通过阅读代码可以知道更多的 api 和 api 使用方法,看完之后经常会有“原来还可以这样使用”的感叹。

(2)从使用过程中遇到的 bug 入手,依赖错误日志的上下文来查看代码。

(3)从概念模型中提到的概念模块入手,比如 storm 中提到了 tuple,spout,nimbus,worker 等,直接找到对应的实现类(一般类名和概念名是一样的,可以直接按名字来搜索),依照其在系统中的职责查看具体实现。

(4)从问题出发,查看相应的技术文章,进一步缩小范围,查看相关代码。问题可以是开发中遇到的异常,构建数据流图的困惑,或者一些很普遍的疑问,比如数据的存储格式,通信协议,数据处理异常的解决方案等,问题越详细越好。

(5)从 demo 代码开始一步步 debug。

2.3 深入阶段

在深入代码的阅读过程中,没有必要一行一行的阅读,有些方法可以当作黑盒子,有些 if-else 分支可以直接略过(忽略一些异常条件情形)。最后模仿代码自己动手写一些简单实现。

2.4 整理阶段

通过一定时间的学习,看了一部分代码,即使做总结,一方面可以反过来丰富前文提到过的数据流图,完善一些细节,同时也可以写一些技术文章条理一下思路。

3. 应用实践

俗话说,读书千万卷,不会吟诗也会驺。同样的,源代码看多了,东拼西凑也可以实现所需的功能,其实会抄并且抄的好也是一种能力。

源代码会在开发中的哪些方面会有帮助呢?

这里我总结了几点可操作的具体实践:

3.1 概念模型和命名

在开发初期,需要根据业务需求抽象出概念模型以及系统设计文档。这一阶段也是最难的部分,刚开始根本无从下手。

那现在有没有想起熟悉阶段我们阅读过的文档和平时积累的素材呢?其实每个优秀的开源软件都有很好的概念模型和清晰的系统架构,比如在数据处理中任务执行的系统中经常会听到这些词,比如 topology,task, job,manager,service dispatcher,DAGscheduler,context 等。

现在要开发设计一个任务提交管理系统,那这个任务和 storm 的拓扑提交以及 hadoop 的任务提交及其生命周期管理是不是同一个领域问题呢?

很多概念是不是就用上了(job,task,JobManager,JobScheduler,worker,executor,cordinator 等)只要看代码命名,是不是瞬间觉得高大上了。

关于系统架构图,有没有想到前面思考过的系统数据流图,只要稍微调整一下即可,是不是很容易。

3.2 开源基础库的使用

在准备阶段会了解到很多新的开源应用基础库。

比如在看 presto: https://github.com/prestodb/presto 分布式 SQL 执行引擎的时候,了解到其中一个组件 presto-parser,可以解析 SQL 语句。

正好,现需要开发一个 SQL 语法解析的功能,引用该基础库,几行代码直接搞定。如果需要重新造轮子,可以参考其实现。

SqlParser SQL_PARSER = new SqlParser(); Query query = (Query)SQL_PARSER.createStatement(“select * from tableName”); QueryBody queryBody = (QuerySpecification) query.getQueryBody();

3.3 部分代码的 copy

看代码的过程中,经常发现这一段代码实现很巧妙,可以记录下来,当实现类似的需求,可以直接 copy 过来,稍微改一下。比如看到 flink 的限流代码:https://goo.gl/yHyq4o,构造 netty 通信协议代码:https://goo.gl/jhBQ7K。

在自己设计 SPE 底层通信协议:https://goo.gl/DSVrVK 的时候,直接 copy 过来做些调整,开发就是这么 easy。

二、论文

平时的工作中,很少会接触论文,阅读论文的时间少之又少。但是论文真是个好东西,内容包含了作者的一些思考和问题阐述,从技术的起源说到目前的状况等,而这些内容正好帮助构建和丰富自己的知识体系。

1. 阅读
1.1 论文的选择

(1)在阅读开源代码的时候,有些代码注释会标注其涉及到的论文:

想要理解具体算法和实现,就需要下载下来仔细阅读。

(2)比较出名的开源系统(kafka,zookeeper,disruptor 等)都会有相对应的论文。对于想学习分布式系统的同学,有网友已经总结了一些好的论文 readlist:https://goo.gl/rjDrQU,有兴趣的可以看下。

扫描下方二维码,阅读完整原文。


  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值