前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从源码中学习(阅读源码,初学者的有效成长方式)

从源码中学习(阅读源码,初学者的有效成长方式)

作者头像
硬核编程
发布2021-06-17 20:34:00
3990
发布2021-06-17 20:34:00
举报

前言

上周我在和一位年轻程序员聊天时,他问到我:“如何阅读源码?”,我们讨论了一段时间,我还列举了几种有效阅读源码的方式。然后他说:“你应该就这个话题写篇文章,这对初学者很有帮助,而且这种经验无法从书籍和教程中获得。” 那么开始吧,下面是我关于阅读源码的小技巧。

为什么我们需要读源码

我们程序员每天都要和源码打交道。经过数年的学习,大多数程序员可以“写”代码,或者至少是拷贝并修改代码。而且,我们教授编程的方式强调编写代码的艺术,而不是如何阅读代码。当我说“阅读代码”,我是指有意地专门阅读代码

众所周知,编程和写作有诸多相同之处。唐纳德·克努特甚至引入了文学编程(literate programming) 编程范式。编程与写作有相同的理念:表达我们的想法 。还记得你在学校是怎么学习写作的吗?我们的写作能力来源于从小学开始直到现在的大量的文本阅读。多年以来,我们阅读了不同难度的伟大作家的作品,并练习了多种写作技巧。

“如果你没时间读,你就没时间(或工具)写,就这么简单。” —— 斯蒂芬·金,《写作这回事:创作生涯回忆录》

正如斯蒂芬·金所观察到的那样,一个作家必须广泛而频繁地阅读,才能形成自己的声音, 并学会写出促使读者拿起书并痴读的句式和故事结构。 和读书一样,有意地阅读代码可以帮助程序员加速成长,尤其是对中级(intermediate)程序员而言。 这样做有三个好处。

站在巨人的肩膀上

我们从他人身上学习。优秀的源代码就像文学杰作,它不仅仅只提供了知识和信息,还提供了启迪。

通过浏览Linux内核、Redis、Nginx、Rails或其他著名项目, 你可以从全球范围的成千上万的顶级程序员那里汲取智慧。在这些项目中可以找到无数的良好编程示例、编程范式选择、设计和架构。向他人学习的另一个好处是能够避免常见的坑,大多数坑早已被他人踩过。

解决困难问题

在你的职业生涯中,你终将会碰到谷歌都无法解决的问题。如果你还没碰到过这种问题,这只是因为你编程的时间还不足够长 :)。阅读源码是调查这类问题的好方法,也是学习新东西的好机会。

扩展你的边界

大多数程序员只在少数特别领域编过程。一般而言,如果你不时常推自己一把,你的编程技能会维持在你同事间的平均水平。不要满足于修补bug或在现有系统中添加琐碎特性的工作。相反,你可以试着扩展到一个新的领域,持续尝试找到一个你在日常工作中接触不到、但你感兴趣的领域。这将从整体上拓宽你对编程的理解。

应该读什么样的源码

综上,阅读源码是有益的。那么下一个问题,有这么多优秀作品可供选择,我们该选择并阅读什么样的源码呢?你必须从选择目标开始。如果不在这个步骤上下点功夫,你从源码中学习的效果就会打折扣。这里有一些典型场景:

  • 当你想学习一门新语言。学新语言可不只是学会语法 。不管怎样,阅读源码是一个非常有效的学习新语言的方式。我从rust-rosetta 项目中学到了很多Rust语言知识。Rosetta Code 是一个收集同一批通用任务在不同语言上的解决方案的项目,这是一个可用来学习新语言的有用资源。
  • 当你想了解一个特殊的算法或实现。例如,我们都会使用标准库中的sort函数,你有没有好奇过它是怎么实现的?或者当你要使用Redis中的Set结构,它是用什么数据结构实现的?为了解决这些疑惑,你只需要读源码中与之相关的实现部分,通常只有很少的文件或函数。
  • 当你在特殊的框架中编程。这意味着你对该框架已经有了一定的经验, 这是个阅读一些框架本身的源码的好机会。很显然,了解框架的源码有助于提高你对框架的理解。
  • 当你想拓展进入新的领域,你可以阅读这个领域的经典著名的项目的源码。比如说,如果你在做Web开发的工作,你对分布式系统感兴趣吗?如果你的答案是“是”而且你懂Golang,也许etcd 是你的选择。你想钻研操作系统的内部构成吗?那么也许xv6 是一个好的开始。我们处在一个许多优秀开源项目都托管在了Github的好时代,请试着寻找一些这种项目。

记住,选择与你当前的编程技能与知识水平相当的项目。 如果你选择了远超你当前技能水平的项目,最终你会感到沮丧。读一些相对较小的项目,接着读更大的项目。如果目前你不能理解某些特定的代码片段,这意味着你有个知识缺口(knowledge gap)。把代码放到一边去,试着读一些相关的书、论文或其他文档,当你更有信心时再回来接着读代码。我们总能在一个模式中取得进展:读(代码、书、论文),写,更多的读,更多的写。

如何读源码

《How to read a book》 是一本指导人进行明智地阅读的书。作为初学者,我们值得投入时间和精力去思考我们应该如何阅读代码。 阅读代码不是件容易的事。 光是阅读源码是不够的,你要试着去理解他人的设计和想法。

预先准备

为了更有效率地阅读代码,你需要提前在手边准备这些东西:

  • 一个你可以熟练使用的编辑器。你需要拥有快速搜索关键字或变量名的能力。有时你需要查找函数的引用和定义。和你的编辑器相处融洽些。为了更加有效率,试着学习仅使用键盘操作编辑器。这会使你专注于代码而不受打扰(译:指额外思考编辑器操作)。
  • 掌握基本的Git或其他版本控制工具的技能,这样你就能比较代码在版本间的差异。
  • 与源码有关的文档。文档可以为你的阅读提供参考,尤其是设计文档、编码规范等文档。
  • 具有一定的编程语言与设计模式的知识和经验。这对(阅读)大项目是强制性的。如果你很了解一门编程语言,你也会了解关于源码组织与编程范式的最佳实践。当然,这需要时间来积累。要有耐心。
  • 流程与技巧

阅读过程不是线性的。你不会就那么一个接一个地读源文件。相反,大多数时候我们会从顶到底地阅读代码。下面是一些更有效率阅读代码的小技巧:

结合上下文阅读代码

当你阅读代码时,请持续提出问题。例如,如果一个应用有缓存策略,一个好问题就是:如果键无效了会怎样?缓存中的值如何更新?带着这些问题阅读代码,就是结合上下文。或者说因为你有了一个目标,你会变得享受阅读的过程。你甚至可以自己做一些假设,然后在代码中寻找验证。

你有点像侦探:你想发现代码的真相,代码的逻辑,代码是如何像故事一般上下流动的。

把实例跑起来并与之交互

源码就像乐高积木,只是已经组装好了。如果你想了解它们是怎么组装在一起的,你需要和它交互,有时甚至要把它拆开。阅读同一模块的老版本同样有帮助。从Git中阅读版本差异,试着弄清楚特定的特性是如何实现的 (修改日志在这个场景很有用)。举个例子,我发现Lua的第一个版本相当简单,这可以帮助我了解作者最初的设计理念。

Debug是另一种与代码交互的方式。试着在代码中加一些断点(或打印一些变量值), 然后弄明白打印到控制台中的所有输出。

如果你对代码了解比较透彻了,试着对代码做一些修改,重新build并把它跑起来。最简单的方式是试着调整配置项,去看不同配置的运行结果。之后你可以试着添加一些细微的特性。如果这些特性对其他人也有用,你应该把代码贡献到上游。

了解数据结构间的关系

“糟糕的程序员担心代码,优秀的程序员担心数据结构和它们的关系。” -Linus Torvalds

数据结构是一个程序中最重要的元素。用笔或者你喜欢的其他工具画出数据结构间的关系。这个图就是源码的映射。你会在阅读过程中时常参考这个图。一些工具比如scitools 可以用来生成UML类图。(译:这个方法用在写代码中能节约翻Model声明文件的时间,推荐用纸笔,不占屏幕)

了解模块间的依赖关系与边界

大项目中会包含许多模块,一个模块经常只拥有单一职责。这有助于我们减少代码复杂度,在适当的层级上做抽象。模块的接口是抽象的边界,我们可以一个接一个地阅读模块。如果你在阅读一个使用Make构建的C/C++项目,Makefile是了解模块间如何组织的好切入点。

边界本身也很有用。优秀的代码组织得很好,变量名与函数名的命名风格体现着可读性。你不需要阅读全部源文件,你可以忽略不重要的或你熟悉的部分。如果你确定一个模块是仅仅是为了被解析而设计的(just designed for parsing), 那么你已经大致了解了它的功能;那么你就可以跳过不读这个模块。当然,这将大大节约时间。

使用测试用例

测试用例也是帮助代码理解的一个很好的补充。测试用例就是文档。 当你在阅读一个类时,试着把对应的测试代码一起读了。测试用例能帮你弄清一个类的接口,和该类的典型用法。集成测试用例可以让你顺着走过程序的整体流程,适合输入一些特殊值并debug运行。

点评

为什么不在花了不少时间阅读一个项目后,写一篇代码点评呢?就像写一篇书评一样。你可以写下代码中好的和不好的部分,还可以记下你从中学到了什么。攥写这类文章可以帮助你阐明自己的理解,也有助于其他人阅读源码。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 硬核编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档