从开源软件和论文中提升自己

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

  • 对于大部分普通工程师来说,每天的工作内容只不过是在原有代码基础之上修修改改,用着框架做着重复单调的CURD工作,写着不痛不痒的业务代码,反过头来看自己所掌握的技能,觉的什么都会一点,可是都不精通,开始变的焦虑不自信;
  • 目前需独立开发一个全新系统,却毫无头绪,不知道怎么做架构设计;
  • 有些同学想通过学习开源代码来提高自己,可是一看到代码量这么庞大,却无从下手或者望而却步。

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

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

开源代码

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

其实学习任何一新技能和知识,都需要经过一个过程,从熟悉,到深入,最后到实践为我所用,然后再继续熟悉,以此循环往复,整个过程需要付出很大的耐心和精力。同样,阅读开源代码亦是如此,在开始这项工作前,一定要克服心理魔障,从战略上藐视对方,“哼,读源代码并没什么了不起的“,战术上一定要重视。

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

熟悉

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

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

阅读文档,熟悉基本概念

在遇到一个新的软件,一定要先阅读文档了解其解决什么问题,涉及到的核心概念,每个模块的具体职责。如果不看文档直接打开源码,会发生什么事呢?打开源码的瞬间,各种类的定义迎面而来,spout,tuple,stream,nimbus,一看是不是想死的心都有了。所以,事情说三遍,

基本概念一定要弄清楚,概念越清楚,系统了解的越透彻

常用文档 Read List:

  • 官方文档:常用的开源代码都有其公开的网站。
  • wiki:对应github仓库的wiki文档。
  • 系统对应的发表论文:比如Bigtable、Zookeeper、Kafka等都有论文发表。

这里以 storm 为例子:

从开源软件和论文中提升自己

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

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

实践使用

具体实践活动:

  • 按官方文档部署相关软件,准备运行环境。
  • 写一个hello world的demo运行起来:开发包中一般存在文件夹名包含starter 和example字眼的文件夹,该文件夹下会有许多官方使用例子。
  • 修改demo实现自己的业务逻辑。

这个阶段主要是模仿官方的例子实现自己的业务逻辑以及熟悉常用的API。在实践的过程中,会遇到各种问题,同时也会看一些相关技术文章,难点一点点攻破,系统的了解也会更深入。

构建数据流图

看到自己的代码可以正确的运行,成就感油然而生。但是,请收起你的放纵,这还远远不够,请继续下一阶段:构建数据流运行图。程序的运行其实就是数据的流动运转,即数据是在模块之间流动交互的,数据从输入到输出,经历了哪些模块,以及模块之间如何协作。

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

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

从开源软件和论文中提升自己

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

  • 理解概念,了解系统的运行机制。
  • 逼迫自己去思考,比如模块之间如何交互,数据流怎么流动。脑海里有越多的问题,看源码的动力就越足。
  • 随着对系统的逐渐了解,可以一步步完善,添加一些具体的实现细节,比如task如何知道输出结果应该发往那个task呢,其地址是多少呢?
  • 遇到问题时,可以依照该图猜测问题可能出在哪个模块,迅速找到切入点。

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

阅读

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

,小心验证。

阅读代码不是简单的读,而是一个思维碰撞的过程:大胆猜想非常重要,当遇到一个技术问题时,首先一定要先独立思考,想一下:如果换作自己该如何解决以及实现这个功能,当有了自己的解决思路后,然后再对照源代码验证。当发现自己的思路跟作者是一样的,那种快感,哈哈,慢慢体会。

准备阶段

在开始具体的代码阅读时,还要做些技术储备。首先我会先看下该软件所依赖的外部库,从了解这些外部库开始。为什么要从这儿开始看呢?其实软件开发就像搭积木一样,由一个个小的模块拼装而成,只有了解了每个小模块的正确使用方式,才能更流畅的剖析如何搭积木的。

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

从开源软件和论文中提升自己

这里是storm依赖的外部库,里面用到了curator(zookeeper使用)、kryo(序列化)、disruptor(生产者消费者模式库)、netty(网络)。这里需要额外花些时间研究下该库的解决的问题、使用方法和常用API。同时,这也是知识储备的过程,以后遇到类似的问题,可以联想到对应的库,为解决问题提供更多的思路。

切入阶段

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

(1)从熟悉的基础依赖库入手,查看它在代码中是如何使用的。比如基础库中对netty使用比较熟悉,就直接找代码里对应的handler具体实现,pipline的构成以及netty的设置管理等。从自己熟悉的东西入手,一方面可以克服恐惧,同时通过阅读代码可以知道更多的api和api使用方法,看完之后经常会有'原来还可以这样使用'的感叹。

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

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

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

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

深入阶段

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

整理阶段

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

应用实践

俗话说,读书千万卷,不会吟诗也会驺。同样的,源代码看多了,东拼西凑也可以实现所需的功能(

会抄并且抄的好也是一种能力)。

那么源代码会在开发中的哪些方面会有帮助呢?这里我总结了几点可操作的具体实践:

概念模型和命名

在开发初期,需要根据业务需求抽象出概念模型以及系统设计文档。这一阶段也是最难的部分,刚开始根本无从下手。那现在有没有想起熟悉阶段我们阅读过的文档和平时积累的素材呢?其实每个优秀的开源软件都有很好的概念模型和清晰的系统架构,比如在数据处理中任务执行的系统中经常会听到这些词,比如topology,task, job,manager,service dispatcher,DAGscheduler,context等。现在要开发设计一个任务提交管理系统,那这个任务和storm的拓扑提交以及hadoop的任务提交及其生命周期管理是不是同一个领域问题呢?很多概念是不是就用上了(job,task,JobManager,JobScheduler,worker,executor,cordinator 等)只要看代码命名,是不是瞬间觉得高大上了。

从开源软件和论文中提升自己

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

开源基础库的使用

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

比如在看 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();

部分代码的copy

看代码的过程中,经常发现这一段代码实现很巧妙,可以记录下来,当实现类似的需求,可以直接copy过来,稍微改一下。比如看到flink的限流代码,构造netty通信协议代码。在自己设计SPE底层通信协议的时候,直接copy过来做些调整,开发就是这么easy。

论文

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

阅读

论文的选择

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

从开源软件和论文中提升自己

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

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

阅读方法

这里简单说下自己阅读论文的心得,我会着重花时间在论文的introduction部分,并试着翻译成中文记录下来:

从开源软件和论文中提升自己

好的论文有个特点,在introduction部分会详细说明一些背景知识,包括:提出问题,目前已有解决方案及其缺点,所讨论技术方案的优点

等,这些内容会叙述的相当透彻。阅读这些内容可能对代码能力的提升及其有限,但是会提高程序员的软素质。比如在准备tech talk和写文章时,需要叙述一些相关技术背景,论文就是很好的素材。

应用实践

阅读论文是为了更好的解决实际遇到的问题。有些论文描述了解决思路和方法,在遇到问题提出解决方案时会有一定的指导作用。有些论文则会具体论述其实现细节,比如一篇论文Implementing Linearizability at Large Scale and Low Latency :

从开源软件和论文中提升自己

可以利用业余时间,动手做个小项目,从论文到工程实现,提高自己的代码能力。

总结

开发代码就如搭积木,每个开源工具就好比每个积木快,论文和具体开源代码的实现思路则是搭积木的粘合剂。只要有正确的指导思想,再配备正确高效的基础工具,代码开发真的可以做到如奶茶般润滑。但是这个过程是极其漫长的,需要长期的积累,才会在工作中潜移默化的提高自己的能力,送大家一句,以共勉。

在成功的道路上都是艰辛而且孤独的。

最后,每个人都有自己的学习方法体系,欢迎提出自己的意见积极讨论,谢谢大家!!


分享到:


相關文章: