技术人成长之源码阅读心法

文章目录

    • 一、如何阅读源码?
      • 1-1 源码解读基本流程
    • 二、高效阅读心法
      • 2-1 把握核心结构
      • 2-2 站在巨人的肩膀上
      • 3-3 提出问题,找寻问题答案
    • 三、代码精读:踏上调试之旅
      • 3-1 调试法思路
        • 倒序法
        • 正序法
      • 3-2 有所痕迹
        • 画图
        • 记录关键的堆栈信息
      • 3-3 掌握原理要看数据结构

一、如何阅读源码?

优质的开源项目,不论是从业务概念上的抽象,还是实实在在、反反复复的调优、验证,很可能是凝聚了一个团队几年的心血,甚至有着庞大的体系。

开源的项目已经为软件生态注入了强大的血液。一个优秀的团队,务必有这样的先行者——他们无惧未知、勇于先行,在缥缈的线索中逐渐抽丝剥茧、持续深耕,学习过往经验、承前而启后。这个过程中,搜集资料、解读开源,便是一门程序员的必修课。
那我们如何有效的阅读源码呢?

1-1 源码解读基本流程

在总结源码解读思路之前,不妨先想一想我们是如何构建一个项目的呢?粗略的讲,大概是这样的步骤吧:
技术人成长之源码阅读心法_第1张图片

那么,解读源码的时候,其步骤也大体类似,只不过写代码的人不是自己罢了。根据以往源码阅读的经验,我们大概可以总结出这样一条经验:

  1. 把握模块划分;
  2. 通过配置深入了解软件功能;
  3. 解读配置加载流程;
  4. 提出核心问题,见招拆招~

二、高效阅读心法

2-1 把握核心结构

越是优秀的开源项目,其在模块设计上更加注重解耦,各个模块各司其职,才得以组成一个可持续维护的项目。阅读源码前,不防看一下系统提供的架构图,对各个模块的职责有一个基本的了解,并能基本理解作者对模块划分的依据。

2-2 站在巨人的肩膀上

今天你所遇到的问题,早在很久之前就有先驱者们探索过了。所以,我们一定要利用好互联网上的资源,为自己将要涉足的这片“土地”有基本的了解。甚至可以先参考一下别人对这款软件源码的解读,以便自己更好地找到学习的方向。
如果没有,那你就是先驱者啦!我们也可以留下自己的脚印供后来人欣赏、借鉴~

3-3 提出问题,找寻问题答案

这样可以带有目的性地来阅读源码,效果往往会比较好。逐渐地,我们也会形成自己的一套提问的方法论。比如我会这样提问:

  • 先读配置文件,了解配置文件核心参数的结构和含义。配置文件的结构凝聚的便是软件功能的核心结构;接下来再去了解各个参数背后的含义,这样我们便对该软件基础功能有了较为深入理解。
  • 找出系统启动的入口。

三、代码精读:踏上调试之旅

调试是源码阅读的最好方式”,这句话放在源码学习的过程中一点都不为过。
调试过程中,我们不仅可以结合业务操作对代码入口的进行梳理。
另外,在了解业务的基础之上,通过调试能够让我们直观地看到程序在运行中的数据,这样我们就可以更加深入了解作者的代码设计和开发思路。

3-1 调试法思路

倒序法

调试一般用到的源码阅读方法就是倒序法。熟悉Java堆栈日志信息的同学,很容易就能理解,问题一般出在栈顶的代码里。这里要么有异常、要么有一条显眼的日志。通过这里,我们再查看堆栈信息,就可以把握程序的执行逻辑了!
通过倒序法,我们可以精准打出一系列的断点。最终我们还需要配合正序法,完成逻辑的串联。

正序法

正序法是用来把倒序法标记的源码断点串联起来。配合功能测试,我们按照正序的方法的理解源码的真正的执行逻辑。

3-2 有所痕迹

好记性不如烂笔头。再强的理解能力,都比不上沉淀。我学习源码的时候,一般会通过画图或者笔记的方式把走过的路记录下来——它们好似我的脚印,等我回头眺望的时候,总能够给我以明确的指示。

画图

用图说代码是一个学习源码的不错的方式:一来可以清晰剖析代码结构,二来通过记录源码关键位置,回过头来再看时节省时间,且有迹可循;三来可视化效果比较好,降低沟通成本~
接下来,我们查看一个Dolphinscheduler源码解读的案例。

阅读源码的同学可以移步:https://www.toutiao.com/i7025583458269479454/

技术人成长之源码阅读心法_第2张图片

记录关键的堆栈信息

堆栈信息就是代码森林里面的坐标,记住这个坐标,我们便不再迷路。

3-3 掌握原理要看数据结构

举个过往的例子,刚开始学习Netty的时候,总是会纠结于pipeline中的handler的执行顺序,生怕放错了顺序,导致了错误的执行。因为在学习Netty的时候,教程中并没有提出出站处理器和入站处理器的数据结构,而是云云了一大堆所谓的规则,诸如:

  • 前面的入站处理器需要调用super.channelRead(ctx, msg)或者ctc.fireChannelRead(msg),消息才能向后方的入站处理器传递——所谓,“击鼓传花,不能有人偷懒”;
  • ChannelHandler的执行顺序:ChannelInboundHandlerAdapter是按添加顺序,ChannelInboundHandlerAdapter则与添加顺序相反。

这些总结最多只能算是“规则”或“特征”,如果我们陷入了记忆规则的思维模式上,我相信,学习编码一定是个很累的过程。因为,再多的记忆也无法理解其本质。
还记得我们在中学时代就开始学习的数学中经常会提到两个概念吗——定理性质

数学定理:定理是指在既有命题的基础上证明出来的命题,这些既有命题可以是别的定理,或者广为接受的陈述,比如公理。
数学性质:是数学表观和内在所具有的特征,一种事物区别于其他事物的属性。

子涵认为,定理更加偏向原理,性质更加偏向特征。我们应该把握原理,因为通过原理来推断性质,是一个水到渠成的过程。在学习编程的过程中,要想把握原理,就需要掌握其数据结构。
技术人成长之源码阅读心法_第3张图片

Netty消息处理的pipeline各个其实是一个“双向链表”结构:读消息的过程,就是next指针向后轮询的过程,当该处理器是入站处理器时,执行读操作;写消息的过程,则正好相反。
我相信,把握了这个结构,我相信聪明的你一定可以随心所欲地定义Handler的顺序了。

感谢您的赏读~
如果您对我的文章感兴趣的话,欢迎留下您的问题让我们一起探讨!一起进步!!还可以关注我的微信公众号哦~

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ih68eiNw-1622215244567)(https://gitee.com/cowboy2014/cloud2020-config/raw/master//pictures/%E6%89%AB%E7%A0%81_%E6%90%9C%E7%B4%A2%E8%81%94%E5%90%88%E4%BC%A0%E6%92%AD%E6%A0%B7%E5%BC%8F-%E6%A0%87%E5%87%86%E8%89%B2%E7%89%88.png)]

你可能感兴趣的:(Java实战宝典,吾爱开源,源码学习经验,java,python,技术成长,netty)