成为杰出软件工程师的秘诀:阅读代码
从Redis截取下来的代码段
如果有一天醒来,你决定要成为一名伟大的作家,那么你会得到两个简单的建议:不停地写,然后不停地阅读。
在软件工程行业,很多人都会编写代码,但很少有人花时间阅读代码,特别是在日常工作之外的代码,这是错误的行为。在职业生涯早期,你应该表现得像一个作家,抓住机会去阅读各种代码。
广泛并频繁地阅读,这可能是一般的软件工程师与卓越的软件工程师之间的区别吧。
为什么要阅读代码呢?
伟大的作家是由他们所读过的作家造就的。例如,琼·狄迪恩,16岁便能打出海明威所写的句子,于是她学习到如何写句子。或者亚伯拉罕·林肯,后来所写的抒情诗就受到了他心爱的《圣经》(詹姆士王译本)的启发。
同样,查看不同的编码实践练习会让你在编写代码时想法更加丰富,而阅读他人代码也会让你了解新的语言功能以及不同的编码风格。
阅读依赖板块将使你成为更高效的程序员。你将了解依赖项提供的完整功能,确切地知道它们是如何工作以及进行权衡的。当出现问题时,你会知道如何调试。
以轻松心态阅读代码还可以避免过于笃定自身所编写的代码。你读的代码越多,那么当推广他人编写的代码时,你就会更加包容,而非建立自己的代码。这种改变将降低你被“非在这里发明”综合症所困扰的可能性。
无论是网页开发人员、数据工程师还是密码学家,培养定期阅读的习惯都会让你学新的工具和产品,不同于日常工作的所见所闻。
作为一位网页前端工程师,读取光线跟踪器代码库的一小部分将使你看到完全不同的约束集。作为一名数据库工程师,阅读一些十分抽象的网页代码可以向你展示用户的想法。对所有工程师而言,你将找到定期阅读每天一定量的工作语言之外的语言的价值所在。
正如唐纳德·克努特所言,“[阅读代码]十分有益,因为它可以启迪思维。阅读他人的作品越多,你就越有能力在未来创造属于自己的......”
以下会教你如何在阅读自身代码时感到尽可能地轻松与高效。
如何阅读代码?
找到代码库——像读一本典型的书一样从头到尾地阅读——这是失败的尝试(但讽刺的是,这也就是计算机阅读代码的方式)。
从头开始阅读意味着你会忽略一些重要内容,对即将到来的结构毫无头绪。被动阅读——你不编写测试或者修复错误的代码——会阻止你真正将代码内化。
与书不同,几乎所有的朋友都在努力地尝试读代码,但是他们的脑海里却没有特定的目标。在阅读新的代码库之前,请确保好你有想要实现的目标。这将使代码库看起来更易于管理,并在旅途不可避免地变得艰难时提供动力。
可以用四种方法来处理任何复杂的代码库(简称RSDW):
· (R)un运行: 编译、运行并且理解代码应该执行的操作。
· Examine(S)tructure 检查结构:学习一些高级的结构和检查关键的整合测试。
· (D)ive in跟寻:遵循关键流程并阅读重要的数据结构。
· 编写测试: 编写测试并确定简单功能和修复错误。
RSDW方法是一个起点,但随着时间推移,你应该将其自定义为适合自己的方法。有些人发誓只写测试和修复错误,而他人总喜欢从检查整合测试开始。
不过,首先,还是要从RSDW方法开始。
1. 运行(Run)
阅读代码的第一步不是实际地去读取代码,而是去使用软件。当你了解了软件所提供的功能以后,才能去阅读代码。在这个阶段,你应该能够对代码进行一个总结,并且对输入和输出有一定的了解。使用该软件会强制你运行它。这意味着跟踪依赖关系,在某些语言中,编译代码。对于图书馆来说,这意味着要调用一些流行的功能。这是运行测试并查看输出消息的时间。如果第一次无法运行系统,那么现在是记录他人运行软件实际需要的最佳时机。
2. 结构(Structure)
接下来,确定代码中最关键的部分。这个过程是与阅读一本书最不同的部分。你必须转换思维来识别代码中的关键联系,而不是从头再开始。首先要了解代码的结构。至少,运行一些自动化工具(例如tree和cloc)来找出代码库的语言和文件。找出关键的文件,看看修改的文件,并使用其它任何先进的工具查看最重要的集成测试,列出调用的函数。标记这些测试供以后使用。还有一种简单的方法可以将此过程简化:找到之前处理过代码的人。理解结构是白板会议的首要任务。
3. 深入了解(Deep Dives)
一旦有一块土地,就尽管去挖掘。
阅读代码时,你应该查看代码流(查看正在创建的操作)并查看数据结构/对象(存储操作结果的位置)。
在你发现的一些关键的整合测试,重要的模式识别学会中或者在对源文件的检查中选择三到五个关键流程,然后深入地去了解。我们应该从特定操作的最顶端开始并跟踪代码。一些开发人员非常相信调试器可让你逐步完成这些代码。其他开发人员更喜欢构建统一的建模语言(uml)图或者火焰图。
FlameGraph来源FlameGraph Repository
在其他时候,你可以停在一个重要的功能中间的断点处,然后在这一堆数据中工作,目的是了解你是如何到达那里的。如果你决定手动跟踪代码,请确保编辑器的设置,使用“转到定义”和“查找所有引用”的快速导航。
对于数据结构,请检查数据类型以及何时设置关键变量。使用调试器在关键时刻查看这些数据结构。除了整合测试外,查阅重要的“pull”请求是一种处理新代码库的有效方法。永久性数据通常更容易理解,因为它封装了独立功能,并且提供了除代码添加的原因和方式之外的叙述背景。
在深度了解期间,保持打开两个markdown文档,第一个是“升级编码”文档,列出正在看到的新语法和觉得有趣的代码模式(其他人称之为词汇表)。第二个是列出了对代码库开发人员所提出的关键问题的文档。 在这个阶段,需要注意到差距,还会添加文档。
4. 编写代码(Write Code)
在文学中,阅读和写作指的是不同的方向,与其不同的是,“阅读”代码的关键部分在于编写代码。没有编写代码,内化代码库几乎是不可能的。这两种简单的方法是编写测试并解决简单的功能/错误。写作测试是一种积极的阅读形式,迫使您特定交互的实际输入和输出。编写测试以一种单独读取的方式在记忆中打印代码。
单元测试是一种简单的方法。一旦掌握了基础知识,你就可以转向整合测试,迫使自己理解代码库中越来越多的部分。有时候甚至会重写现有的整合测试,来测试对关键工作的理解。
另一种简单的方法是编写简单的功能或解决容易出错的问题。这两项任务都不需要完全了解代码库,但仍然迫使你面对代码。提供错误修复和文档也是回馈依赖关系的简单方法。当你极其需要它时,这些方法可以快速获胜。通过在一些更广泛的课程中增加RSDW,阅读代码将变得不那么令人生畏。
阅读提示
该RSDW过程不是教条。工程师不可避免地想出了他们喜欢挖掘新代码库的个人方式(这个过程也因语言,可用的工具以及你面前的代码库类型而有很大差异)。
尽管如此,当你看到新代码时,RSDW流程确实提出了一种系统方法。它鼓励对代码进行主动内省,无论是编写测试还是主动使用调试器来查询数据结构。 阅读代码的过程与阅读书籍的被动过程大不相同。
阅读新代码很费时费力。你正在错综复杂地回溯代码流并尝试同时拥有数十个新的数据结构和功能。当你接近新的代码库时,要休息一下。开始使用新的代码库时,需要一整天的阅读时间才能感觉到高效。虽然培养良好的阅读技巧至关重要,但对于你所阅读的内容进行深思熟虑同样重要。
应该读什么代码呢?
职业生涯早期,你应该花60%的时间阅读代码。也许其中三分之一应该是你实际构建的直接代码库之外的代码。这是一个需要非常多的时间来填补的事情,所以你应该读什么呢?
开始阅读的最简单方法和最高投资回报率是学习依赖关系。把依赖工作内化的方式可让你更轻松地在整个系统中进行调试和推理。另一个高投资回报率路径是选择与你交互的公司的重要系统,并通读它。这不仅对你的工作非常重要,而且关键的是,专业代码库与开源代码库不同。除了与你互动的直接系统外,还要广泛地开放性地阅读。在我职业生涯早期,我建议你在早上或晚上留出一个小时来阅读日常工作之外的代码。经过一天辛苦的工作后,这听起来很痛苦,但选择一个令人兴奋的代码库并尝试阅读。
例如,Redis被称为C中的重要起点。对于不太可读的并且更复杂的代码库,这种简单的启动方式是读取特定的子系统。
辅助项目是一种很有影响力的阅读方式,因为它们会迫使你接触一个不一样的世界。你需要阅读新的依赖项并探索现在正在构建的不同代码库。虽然它看起来不像是阅读,但这是一个迫使你积极阅读你将要使用内容的方式。
在外面工作时,你应该阅读与你日常工作大不相同的东西。如果你已经习惯了这种高层次的抽象,学习一个抽象度比较低的(或三级)。如果你是专注于一种语言,那么请在空闲的时候选择另一种语言来阅读。如果你一直不得不考虑一个限制问题(例如,图形编程中下一次屏幕刷新的时间),那么找到另一个约束问题(例如,在移动编程中节省电池寿命)。
阅读代码的另一个好方法是阅读和重写所尊重的码农所写的东西。去阅读他们的代码库并且去及时了解他们最近的工作。
斯蒂芬·金曾经劝告作家们,“如果没有时间阅读,你就没有时间(或工具)来写。这就是那样简单。“同样,对于软件工程师来说,编写新代码可能是最有趣的,但主动地积极地阅读代码会将你从束缚中逃离出来。