当前位置: 首页 > 科技观察

接管不好的代码,不要对你的老板客气!_0

时间:2023-03-16 20:18:07 科技观察

作者|艾萨克·莱曼译者|崔浩每个人都喜欢可读性强的代码。他们希望自己接手的代码是易读易懂的,从而减少交接的工作量,但并不是所有的代码都是易读的。可读性,接过前人的“屎山”对于开发者来说通常是一件很痛苦的事情。关于代码有一个流行的说法:代码被阅读的次数是它被编写的次数的十倍,而且产品寿命越长,这个比率就越高。考虑到这一点,我们似乎在“理解代码”方面的投资明显不足。开发人员往往更重视编写代码的能力,而不是阅读和解释现有代码的能力,尽管这种情况在日常工作中经常发生。前80-95%的开发时间应该花在阅读代码和文档上。在研究现有代码的过程中,你可能会学到很多东西,只有看完代码你才能说:“这个特性已经存在了,要不再加这个特性弊大于利”。本文将向您介绍一些实用的代码阅读策略,您可以根据自己的实际情况使用。1.重构局部变量和方法有时候,一段代码非常模糊,容易误导读者,甚至让人难以理解其含义。一种风险很小的方法是重命名局部变量和私有方法,以更准确地描述它们的作用。这些类型的修改不会影响当前工作文件之外的功能,只要注意避免命名冲突,它们就不会导致逻辑错误。如果可能,请使用IDE的重构工具(而不是文本查找和替换),这样您就可以一键重命名所有使用的内容。例如,考虑以下JavaScript代码functionib(a,fn){return(a||[]).reduce((o,i)=>{o[fn(i)]=i;returno;},{});}非常难读,方法名ib对于理解函数的作用没有用。不过,这并不妨碍您对其进行推断:因为reduce是在a上调??用的(并且它返回一个空数组),所以a应该是一个数组类型。回调参数i将是该数组的一个元素。reduce的第二个参数,一个空对象{},告诉我们回调参数o是一个字典(对象)。所以,通过重命名,我们可以得到这样的东西:dict;},{});}通过上面的调整可以看出,fn是将数组元素转为字典的关键。这揭示了函数ib的目的:将数组转换为字典,并使用自定义回调来确定索引每个元素的键。您可以将fn重命名为getKey,而ib应该命名为indexBy。重命名一些标识符有助于我们理解代码,而无需更改其逻辑并同时考虑所有部分。如果可能,强烈建议进行修改。毕竟,这提高了代码的可读性,这将有利于整个团队,同时它不会增加或改变程序的功能。2.弄清楚代码是如何被调用的大多数代码都是被其他代码调用的。如果你正在纠结一段代码,通过弄清楚它是如何被调用来理解它的功能是非常有帮助的。该方法可以重命名为ThisBreaksOnPurpose。然后编译,虽然在通过反射访问的情况下,运行时会看到错误,但是编译的错误提示会告诉哪里用到了这个方法。如果上述方法不可行,您可以通过文本搜索方法名称。如果幸运的话,此方法的名称在代码库中是唯一的。否则,您最终可能会得到更大的结果集,并且不得不费力地处理大量不相关的代码。3.搜索相似代码有时,即使所有的标识符都很好地命名并且用例很清楚,代码还是很难理解。并非所有代码都符合编码惯用语。有时特定操作不遵循编码约定。在最坏的情况下,有问题的代码出现在工作代码库中,同时也没有使用明显的习语。然而,真正独特的代码在长期存在的代码库中很少见,尤其是在单个表达式或代码行中。如果您花几分钟在您的项目中搜索类似的代码,您可能会找到一些解决整个难题的线索。全文搜索是其中最简单的。您可以选择要搜索的显着代码片段,搜索工具通常包括“全词”搜索选项,这意味着搜索care.exe不会返回scare.exertion之类的结果。如果您想进一步缩小范围,可以使用正则表达式而不是文本短语进行搜索。当然,有时即使是正则表达式也不足以缩小范围,没有人愿意花几个小时在搜索结果中挖掘可能无济于事的东西。还值得学习一些高级搜索技术。许多程序员更喜欢使用Unix的命令行工具,如grep和awk,或者在Windows上使用手写的PowerShell脚本。我的首选是JSPoweredSearch,这是一个VSCode扩展,可让您在JavaScript中定义逻辑搜索查询。4.运行单元测试在一个完善的代码库中,你可以通过单元测试来了解代码的状态。但是大多数代码库并不完美;出于效率原因,单元测试工作通常是不必要的,有时单元测试描述了过时的行为。不过,审查和执行代码测试是个好主意。至少,它们描述了代码的输入和输出。如果没有单元测试或者单元测试不够全面,你还有第二次机会保存。可以编写一两个测试来证明代码是否存在问题。如果发现问题,修复它然后提交更改,它会增加代码库的稳定性并使代码不言自明。您永远不必担心添加自动化测试会破坏现有功能。编写测试需要时间,但这样做可以大大提高代码执行效率。测试是代码工作的实际证明,并且进行单元测试可以让您确信代码的功能没有被破坏。5.使用Debugger工具一旦你进行了单元测试,就有一个很好的机制来帮助你一步步调试。在此代码的顶部设置断点或添加断点/调试器语句。然后运行测试。一旦遇到断点,执行就会暂停,您可以一次前进一行,进入和退出函数,并检查范围内所有变量的值。如果您知道哪些用户操作触发了相关代码,您可以设置断点并正常运行程序,与程序的界面进行交互。如果你这样做,反馈循环会更长,但它也会使用更真实的数据,这可能有助于你发现空引用和边缘情况。自上而下的逐行调试对于运行数十或数百次的代码可能不是很有用,例如嵌套循环。对于这样的代码,你可以在每个循环中添加聚合变量,这样你就可以在循环结束时看到总数。很多IDE还允许设置条件断点,通过设置条件可以让循环暂停,进入断点查看对应变量的值。6.搜索知识库如果您的团队在开发过程中编写文档,您可以快速跳过这一步。文档不应该是唯一的真实来源,您应该依靠代码来了解您的程序的行为方式。文档虽然擅长解释代码的“How”,但通常更擅长解释“Why”。有时你明白一段代码在做什么,但从另一个角度看有些地方不对劲。因此,您应该尽一切努力了解原始程序员在更改之前编码的信息或约束。一份好的内部文件还可以让你找到知道真相的队友。如果您已经走到这一步并且完成了足够多的工作,那么是时候寻求帮助了。确保让其他人知道你在做什么以及你试图解决什么问题,他们很可能会注意到你的盲点。7.使用版本控制注释看到这里,你已经学会了几种行之有效的代码阅读策略。但即便如此,也可能存在无法解决的问题:一个奇怪的设计决策,一种打破代码库编码模式的方法,一种没有明显原因的代码特质。版本控制系统可以显示代码存储库中任何代码行的作者和提交。在Git中,它是gitblame命令。大多数系统称其为“蓝色”或“注释”。您可以在命令行或IDE中运行此命令。将出现的是逐行的提交列表:提交哈希、提交消息和作者。如果该行代码的最后一次提交没有意义——例如,它是格式或空格更改——您需要浏览文件的更改历史记录以找到引入该行代码的提交。同样,版本控制系统有工具可以帮助您做到这一点。一旦你有了PR和ticket,你不仅有代码的背景,还有参与其中的人:代码的作者,PR审查者,任何评论或更新ticket的人,签署QA的人。如果前面的方法都不管用,是时候找前辈聊一聊了。8.先理解,再编码通过以上步骤的学习,可能对你有所帮助,尤其是对代码背景的理解和功能的实现。在您继续前进之前,还要考虑重构代码以使其清晰,创建新文档,在这里投入的任何时间都会为您和您的团队与代码交互带来回报。有效阅读代码的能力是让你快速通过技术面试并成为任何团队重要成员的秘密武器。善于写代码的程序员很有价值,善于阅读代码的程序员更有价值。当生产中出现错误或需要紧急开发新功能时,第一步也是最重要的一步是了解阅读代码可以让您顺利到达彼岸。原文链接:https://stackoverflow.blog/2022/08/15/how-to-interrogate-unfamiliar-code/译者介绍崔浩,社区编辑,资深架构师,18年软件开发和架构经验,10多年分布式架构经验。