嘿,朋友们!本文我将分享一些关于主动阅读和研究源码的一些想法。在我看来,阅读源码能够帮你成为一名更专业的开发人员。毫无疑问的是,阅读源码提高了我的软件开发水平。
应该阅读源码吗?
是的,你应该这么做!
好消息是,你日复一日开发软件时已经在这么做了。多年来,我看到各种统计数据表明,开发人员大多数时间都花在了阅读代码上,而非写代码上。
当你要开发一个新功能或者修复一个 BUG 时,你必须要先理解现有代码的逻辑。你可以通过阅读单元测试来了解代码的逻辑,因为单元测试应该能够清楚地表达代码行为期望,但是通常我们还是要深入到具体的代码实现中去分析。
本文将给出一个推荐的源码阅读形式。我在这里推荐大家要主动阅读源码,特别是阅读那些从未见过的源码。因为和从未见过的代码相比,阅读自己曾经编写的代码对我们技能的提高帮助不大。
如果你能够更好地阅读和分析源码,你以后就能更从容地编写新功能和解决 BUG。你可以通过阅读有关代码,快速获取工作所需的信息。正如我们可以训练自己更快阅读书籍一样,我们也可以训练自己更快地阅读和理解源码。
为什么要花时间阅读源码
让我们先思考孩子是如何学习读写的。在 Caroline Linse 写的《少年学习者》中,她说你能写出一个单词的前提是你之前读过它。在我看来,这听起来很合理。首先通过在上下文中阅读到单词,然后你开始理解它们的含义并学会正确地使用。
读书可以拓展你的阅读量,学到将来可能用在写作中的技巧。这也是我们为什么要在学校里学习文学的原因。最终,随着我们读的越来越多,我们有了辨识能力,知道哪些是更有用。
对软件代码来说也是如此。我是一个 C# 程序员,但是不管你是什么编程语言的开发者,每种编程语言都会有很多语法和关键字。你可以将这些简单的关键字和概念可合在一起编码出无限种可能性。有很多方法可以实现同样的效果,就像有很多方式表达出同样的含义一样。虽然从技术角度而言,不同的代码都可以实现同样的效果,但是有些方法却比其他方法更适合。通过阅读源码,我们会发现,有些方案可能比其他方案更有效。
不知道你有没有遇到过自己的同事甚至自己编写过难以阅读的代码?反正我有遇到过。难以阅读的代码很难维护,并且会影响开发进度。正如在语言中,段落结构不合理很容让人感到困惑,难以理解,代码也是如此。很多难以理解的段落或代码需要反复阅读才能理解其真正含义或意图。我们可以通过阅读更多的源码提高编码水平,从而避免编写出难以理解的代码。
提高技能需要刻苦地努力。学习那些比你工作经验更丰富的人的代码将会给你未来的工作编码带来帮助。举个例子,医生通过多年的培训才能拥有行医资格。这些医生最初和经验丰富的老医生一起工作,先观察模仿,然后才能独立工作。顶尖的医生也会主动学习他们专业领域的论文,从中学习新的技术和方法。
就上述描述而言,我认为软件开发领域做的不够。有些团队相对做得更好一些。结对编程和 Mob 编程(3 个或 3 个以上程序员一起编程)只是开发人员共享技能的方式之一。另外一个提高自己技能的途径是定期接触新的代码,并能够坚持下去。
在这个问题上我可以直言不讳吗?如果你没时间阅读,你就没时间写作,就这么简单。 ― 史蒂芬·金, 《写作这回事: 斯蒂芬·金创作生涯回忆录》
应该阅读哪些源码?
如果你认可我的上述观点,我希望你能接受将阅读源码当做日常工作的一部分的理念,以便可以通过阅读源码不断提高技能。
下一个问题就是你该读哪些源码?
从宏观上讲,我认为这个问题不重要,重要的是你有没有去阅读源码。请记住,并不是所有的软件代码都生来平等。你阅读一些源码会明显比阅读另外一些源码效果更好,但是不管好源码还是坏源码都可以帮助我们提高编码能力。
这并不是说你必须赞同你阅读的所有代码。阅读“糟糕”的代码也可以给我带来一些启示。如果你在阅读一些代码的过程中发现了自己不喜欢的风格或者读到了没啥用的方法,同样也可以节省我们自己的编码时间,因为我们可以避免犯同样的错误。
也就是说,你需要阅读代码来补充一些新的、更靠谱的实践方式(下面一节将讲述如何寻找源代码)。
阅读的源码的多样性至关重要,因为这将有助于你有意识(潜意识)地学习不同来源的模式。当你在不同的地方看到相同的方法、模式和编码趋势时,说明它更可信。
我把时间花在研究我经常使用的 C# 代码库的源码上。通过这种方式,不仅提高了我阅读代码的能力,还帮我更好的了解库函数的内部工作原理,进一步帮助我更好地使用它们,可谓是一箭双雕。
虽然我也不是经常这么做,但是我打算尝试阅读一些我很少或者从没有用过的编程语言代码。精通一门编程语言非常有用,但是拓展自己的语言范围也有诸多好处。如果你仔细思考下会发现,很多人学习第二种甚至第三种语言,并能够从中受益。他们和其他国家的人交流起来会非常容易,而且通过对其他语言的学习,又反过来促进了母语的学习和使用。
学习第二种编程语言不仅能够拓宽你的职业选择,而且还能让你注意到它和自己主要编程语言的异同。我们经常看到一种编程语言的特性会影响到另外一种编程语言。例如 C# 中越来越多的函数式语法,首先出现在 F# 的每个版本中。一些 .NET 的特性如 Channel 就受到了 Go 语言的影响。我们可以通过关注第二个编程语言来预先学习这些特性。
在哪里找优秀的源码
有很多潜在的源码来源。
GitHub
这里几乎拥有所有编程语言的源码。那么要从哪里入手呢?我个人更喜欢先学习微软的 ASP.NET Core 和 CoreFx库。我发现深入研究框架团队的高质量代码是一个很好的学习方法。
这些框架是非常好的学习资源,因为它们的代码的质量很高,而且从中也可以瞥见微软编码模式的影子。通过阅读和学习团队如何构建可拓展的框架代码,我个人收获很大。最近我花了一些时间思考任务并行库,在我编写的一些代码中发现了很多关于 CancellationTokenSource 的用法。通过学习微软的源码,我学到他们相关的常见用法。
GitHub 提供了很好的源码搜索功能,你甚至不需要下载代码就可以在浏览器中学习源码。如果你想深入学习,我更倾向于建议你将源码克隆到本地,这样学习起来更方便。
我还喜欢通过阅读我使用的库的源码如 Polly 和 MediatR来拓展我可以使用的功能。这让我接触到了其他的编程风格,帮助我加深对编码的理解。我并不是都喜欢或者赞同所阅读的源码,但是阅读源码有助于帮助我了解自己的编码习惯。通过阅读源码,我会更有意识地主动避开潜在的陷阱和糟糕的设计。
博客文章
网上有很多软件开发相关的优秀文章。你肯定可以找到带有示例代码的技术博客。因为这些文章的代码通常比较短小,所以更容易在短时间内理解消化。通常,博客配套的代码作者也会给出注释或者解释,你可以先对代码进行分析然后和作者的意图进行比对。
图书
有很多经典的技术图书,包括电子版和纸质版。这两种图书都会包含一些源码。去年我就通过阅读Konrad Kokosa 写的《深入 .net 内存管理》学到了很多编写高性能代码的知识。
StackOverFlow
你肯定在 StackOverFlow 上看过一些优秀的和普通的代码示例。在这里可以很容易地搜索问题和答案,可以学习到不同的编码风格,可以得到各种参考意见。如果想了解更多代码相关内容,可以去 代码审查区 学习。
内部资源
前面我讲过,让自己接触之前没见过的代码对读源码至关重要。我想补充的是,你还可以通过学习工作代码库中自己很少参与的项目来提高编码能力。可以花点时间去理解这些代码,搞懂他们的工作原理。如果有一天需要你去支持这些项目,你可能比源作者更熟悉这些代码。
当你加入一个新的团队时,你可以通过学习团队现有的代码来快速了解编码规范和常见的模式。这将加快你融入团队的速度,促进你的个人发展。
这不是一个非常详细的清单。不管你在哪里找源码,都应该花费更多的时间去深层次阅读和学习。用这种方式投入时间来提高开发技能非常值得。
如何阅读源码?
关于阅读源码,每个人都会有自己的喜好。按照你认为正确的方式去做就好了。在这里,我会分享自己的阅读源码的方法,你可以借鉴这些方法开启自己的源码阅读之旅。
通常我会将重点放在那些想学习的编码风格的源码或者那些能够加深我对编码知识的理解的源码上。正如前面我讲到的,这种投资将会得到丰厚的回报。
我通常会从 GitHub 上找源码。我会集中精力理解代码的意图。我会尝试从一个高抽象的函数作为出发点,然后逐步深入到内部。在学习代码时,我喜欢用 OneNote 做笔记,记录代码的流程。这些都是比较简单的笔记。这个过程与其说是在积累参考资料,不如说是帮我加深记忆和理解。通过将源码转为书面描述,我的印象更加牢固,对知识点的理解也会更好。
浏览代码并在心中形成一个逻辑图是一个非常棒的技能。如果你能够在阅读源码过程中培养出这种能力的话,下次你修复 BUG 时将会更加顺利。
一旦我对源码有个一个整体的了解,我将会更深入地研究下去。接下来,我会将源码克隆到本地并将其导入到 IDE 中。可以使用 IDE 的代码导航功能快速在源码中切换,进一步深入研究源码。此时,我会去思考作者这样写代码的原因是什么。我喜欢先自己去思考,然后和作者的实际代码进行对比。我会思考:像作者这么写法会更好、更有效?下次如果我也遇到类似的场景,要不要参考他的写法?
在阅读源码的过程中,我会发现自己编码时从未用到的 API。我发现当我编码时,我会倾向于使用自己已经熟悉的 API,但这可能并不是最佳的实现方式。有时候正是因为我们不知道还有其他选择,所以才继续使用已经熟悉的 API。阅读源码的过程中,如果遇到我从未用过的 API,我会查看它的描述和方法签名来了解它的用途。
阅读源码还提高了我使用 IDE 工具的能力。在浏览代码时,我会发现一些技巧或学会一些实用的快捷键,从而节省了很多时间。我还经常会把一个类拖到第二个显示屏的一块屏幕上,这样可以快速跟踪代码流。我写代码的时候也会经常这么做。 读源码时我也会努力学习自己不熟悉的语言特征或模式。通过阅读源码我快速掌握了 C# 的新特性。
如果有些代码理解不了怎么办?
莫慌,这绝对没问题。刚上来,你不可能理解自己读到的所有源码。而且有些不理解,这正是我们想要的效果。你就应该读新的代码或者包含新语法的代码,来提升自己的编码技能。阅读容易理解的代码,就像阅读一本非常简单的书一样,对你的帮助并不大。
你应该在大脑中尝试将代码拆分成小部分。思考这些代码是为了实现什么功能,为什么要这么写?作者是否用了一个方法解决了一个你从未思考过的问题?当你遇到某个语法不理解或者某个关键字不懂时,请停下来搜索帮助文档。有了实际的使用场景,再去查帮助文档理解就会更好一些。
如果你遇到从未用过的框架 API 时,如果有代码文档,可以查看代码文档。对于所有的微软库,公共方法都会包含 XML 注释。你可以直接阅读这些注释也可以通过访问.NET API 文档 来查询。
有意识的主动阅读源码的意义在于,这是你你主动分配自己的时间,为自己技能投资。而不是在工作中面临最后期限,要完成各种功能,还要修复各种 BUG。这样你将很少有精力去学习自己直接使用的代码之外的源码。这种情况对学习没啥帮助。
我从源码中学到了什么?
我从源码中学到了很多东西,这也是为什么我不遗余力地推荐大家学习源码。现代的手艺人会经常研究自己领域大师的作品,以期有朝一日能够达到他们的水平。开发人员也可以像他们一样向自己领域的专家学习来提高自己的技能。
就我个人而言,作为一个 .NET 开发人员,我发现学习微软的 .NET Core 和 ASP.NET Core 源码非常有价值。微软有很多优秀的开发人员,他们对语言或运行时特定知识的掌握更加专业。
我是一名自学成才的开发者,最近在 Twitter 上看到有人这么说(不过,我记不住他是谁了)。我通过各种尝试和各种错误中学习了 C#,并且我会主动学习源码。正如很多学者们研究伟大的文学作品一样,通过阅读伟大的代码,可以解锁很多秘密。
我向那些对软件设计感兴趣并且希望深入了解 .NET Core 框架的人推荐一个资源,该资源可以从 YouTube 上获取。.NET 团队每周会在 YouTube 上发布他们的 .NET 设计评审。在这些会议上,团队会审查对 .NET Core 的 API 变更的提议。我建议选择性观看这些会议,对于一些人来说用自己的时间去看会议可能有些太过“极客”,但这仍然是一个非常的学习途径。这个团队是由真正专家组成的,他们对语言、运行时和框架了如指掌,让人震惊。通过观看他们对提议的 API 的讨论,可以帮助我们理解一个广泛使用的框架必须考虑的问题。通过观看这些视频,我经常可以获得一些非常有价值的观点。
总结
我写这篇文章的主要目的是鼓励一些读者更加主动地阅读和学习源码。通过阅读源码,我学到了更多 C# 语言和 .NET Core 框架的知识,帮助我成为一名更优秀的开发者。定期投资几个小时来阅读源码,将在未来带来丰厚的回报。通过阅读源码,你将对不同的编码风格和技术有自己的看法。你将从更深的层次上了解你平时所用的框架的工作原理,反过来又促进你更好的使用它。你将可以更快地阅读源码,从而帮助你缩短从需求到编码完成的时间。