👨‍💻关于源码阅读
00 min
2023-4-22
2024-3-1
type
status
date
slug
summary
tags
category
icon
password
🌟
明确源码阅读的收益点:(如果没有你想要的,Just Quit~
  • 工作需要:可以应用到工作中的算法和实践
  • 能力提升:少走弯路,学习最佳实践
  • 艺术鉴赏:品味高手写的代码
  • 灵感汲取:跨领域的灵感(eg. OS、网络相关的)
文中介绍的每种方法,我建议你都可以试试,体会一下~
 

常规流程

最最最常规的源码阅读流程
  1. 学习官方资料
    1. 是什么
    2. 做什么
    3. 怎么用
    4. 设计原理
    5. 局限性
  1. Debug
    1. 把项目跑起来
    2. 跑官方demo或者单元测试,构建一个使用场景
  1. 第一遍先BFS阅读,第二遍BFS+DFS阅读,第三遍DFS阅读
  1. 对于无法Debug的问题,通过IDE阅读,从单元测试入手寻找代码位置
  1. 绘制思维导图或者流程,架构图,对核心数据结构可以绘制UML图
 

进阶流程

我也忘了这招哪学的,但是个人觉得比常规法强!
核心就是:删代码!
🖥️
流程如下:
  1. 浏览git commit节点,了解项目进展;
  1. 切到不超过5k行左右的节点,浏览此时的项目,把握主干核心;
  1. 删减至500-1000行。
这时候,剩下来的就是骨干了,代码明显会清爽很多~我们这时候也可以实现相同接口,实现自己的版本。
 

缺陷

常规流程看似很完善,流程123列的好好的,但是其实是有坑点的——很容易失焦(你或许知道我在说什么);进阶流程虽然一定程度解决了这个问题,因为删完就剩骨干了,但是这种方法其实更难.…..因为你至少得知道什么能删(枝叶、杂草),什么不能删(核心、主干)。
因此,我们期望探寻一种更有效的源码阅读方法。
没有说上面两种不好,各有用武之地。
 

源码结构

源码结构一般是错综复杂的网状结构
正因如此,这项工作很难;也正因如此,源码并不适合线性阅读。所以最好的源码阅读方式是:
📌
带着问题找相关模块阅读。粒度越细越好(eg. 函数)。
目的明确,不容易失焦,也不用删什么代码,要学啥就看啥。

Have A Tryyyyyyy!!!

比如,我要我想知道redis的zset怎么实现的,用了什么数据结构和算法,怎么和整个redis项目关联起来的,我们就可以找到/src下的t_zset.c文件。(以redis-6.2.4为例)
  1. 首先会看到像下面这样 Copyright 相关的信息,我们可以先跳过。
  1. 接下来一般就是文件介绍/API。
(别说怕英文,翻译工具和协助工具多的是;我后文推荐了)
你会感叹:啊~原来就是跳表呀~
  1. 然后我们就会看见一些数据结构定义、具体实现等
这zset的生命周期函数(crud)我是看见了,但是它的数据结构定义呢?我们一般阅读源码都会用IDE吧,比如vscode,我们直接【ctrl/cmd+左键】点进去看就行了(vim佬忽略)。你会发现进入了server.h这个文件:
你会感叹:啊~好家伙~在这呢~
这时候你或许又会问:dict是啥呀?我还是那句话:要学啥就看啥。自行点进去看就行。
 

工具推荐

  • IDE:vscode
  • 翻译:有道词典、Google翻译
  • 代码阅读AI助手:Cursor(微软家的,接了GPT4)、Monica浏览器插件(接的ChatGPT,每天30次免费互动)
 

大忌

:造轮子前,先要成为Power User。
不要不了解一个东西,一上来就看源码!!!至少看过官方文档!!!
 

认识代码工程模块

接口定义

即抽象,需要最优先阅读,这是顶层设计,关注“是什么”。

模块实现

是具体流程的实现,关注“为什么”,要用宏观的视角看它在整个项目中的一个角色、地位,尽可能能梳理出模块依赖图和流程图,这时候不要陷入实现细节。
多想想这些问题:
  • 这个模块的公共接口是什么?
  • 什么需要验证?
  • 这些变量会包含我们认为它们包含的内容吗?
  • 这还涉及哪些其他部分?
  • 添加新功能时更改它有什么风险?
  • 什么可能会坏掉?
  • 有测试吗?
  • 这些变量的生命周期如何?
    • 谁初始化这个?
    • 什么时候变?
    • 谁改变它?
    • 与此同时,这些信息是否在其他地方?
    • 它总是不一致吗?
  • 有没有隐藏的状态机?
  • 这段程序开销多大?
  • 它是怎么走到这一步的?
  • 模块之间如何依赖调用?
  • 该状态是否明确地通过参数传入?
  • 是否假定它作为实例变量或属性存在?
  • 有没有单一的路径可以到达那里,并在一个明显的地方建立状态?

算法

算法代码是实现代码的一种特例,关注“怎么做”。(看数据结构+算法)
它不那么暴露于外界,它是程序的核心,通常是业务逻辑或软件的核心流程。

胶水

组织、连接各个模块,也是很容易被忽略的一部分,但其实很重要。包括:
  • 输入参数,调用函数
  • 注册、回调
  • 打中间件
  • 错误处理
  • ……

配置

配置分为两种:
  • 配置文件
  • 代码配置 ⇒ 特别小心这种
多多关注机器资源、环境、敏感信息等问题。

任务分配

看看有没有定时任务,后台任务,有没有map-reduce之类的,关注它们在项目中的地位。