探索大型开源代码库的通用指南

探索大型开源代码库的通用指南

– 机翻摘抄,原文见标题链接

1、开始使用存储库

心理建设:探索新的存储库当然是一项艰巨的任务

许多角度都在起作用——熟悉语言、理解所使用的工具或框架、组件如何相互集成、开发人员使用什么范例等。
本文试图提供一下方法论的指导,按照我的习惯,可能更倾向于从给出实际例子的情况体现该方法,可能会为了逻辑紧凑而放弃部分指导,还是希望大家看原文。

1.1、用它

熟悉任何开源项目的最佳方式是使用它。

了解项目的依赖项、功能和重要的组件/类。尝试集成尽可能多的特性——记住——你的首要目标是探索这个项目的广度。

如果上述步骤不顺利,反思一下是因为某种工具、语言、框架还是其他原因?如果找到原因,请找它相关的文档来读,如果文档太TM 多了,先看看教程或视频。如果还有疑问,我去测一下智商?NO, 正确做法是在讨论平台(Github discussion, Slack, Discord, etc) 联系下作者,肯定是作者写的有问题。

1.2、查看最早的提交

废话文学:

总是先做困难的部分。如果困难的部分是不可能的,为什么要在简单的部分上浪费时间呢?一旦困难的部分完成,你就可以自由回家了。

总是先做容易的部分。你一开始认为容易的部分往往被证明是困难的部分。完成容易的部分后,您可以将所有精力集中在困难的部分。

  • A. Schapira

初始提交通常会包含项目的全部要点。通过分析它们,您可以了解该存储库的初始目标。

1.3、测试用例、规范和从源代码构建

阅读测试代码往往比应用程序代码更平易近人,可能是因为程序员不会在晚上 8 点匆忙编写测试

– arandr

1.4、使用工具来帮助理解

很多高层次的图片通常能很清楚的阐述清楚项目的架构啥的,咱最好能背下来,这样下次想给新人介绍的时候不至于不知道从何说起。通常这类用 UML 图描述,llvm 更高级,它可以生成 dot 描述的图。

如果是python 项目,有一个很棒的工具 pyreverse

1.5、Git 日志技巧

可以使用版本控制来识别任何开源代码库中最常编辑的文件。这些通常是完成所有工作的文件(80/20 规则),您可能需要了解它们。

# For top 10 most edited files
git log --pretty=format: --name-only | sort | uniq -c | sort -rg | head -10

# For top 50 most edited files with file_name/directory_name containing the word - NAME
git log --pretty=format: --name-only | sort | uniq -c | sort -rg | head -50 | grep NAME

1.6、搜索

只有当一个人愿意忍受悬念和经历寻找的麻烦时,他才能有效地思考 (One can think effectively only when one is willing to endure suspense and to undergo the trouble of searching.)

---- J. Dewey

在浏览大型代码库时,搜索工具尤为重要。如果代码在 Github 上公开,您可以导航到其存储库,按下/以启动 Github 的搜索工具,键入您的查询,并通过突出显示获得即时搜索结果。

– 现在可以用 Ctrl+k

对于本地存储库,使用一个简单的 grep 命令应该足以满足大多数目的

# 参数注释都不清的同学好好反思下
grep -rni $"PATTERN" *

# 搜索特殊后缀文件
grep -rni . --include \*.EXTENSION

使用ctags它并将其与 vim 集成是另一种搜索大型代码库的强大方法, 当然 IDE 更方便,但同步麻烦。

2、发现问题

深有同感

在发现阶段,您的目标是提出一个好的(书面的)您想要处理的问题列表。一个好的问题是:

  • 你有兴趣从事
  • 需要您已经拥有或可以在课程期间合理学习的技能

建议首先搜索带有 help wantedgood first issueMLHhacktoberfest 标签的问题。导师还建议您在奖学金开始时从较小的简单问题开始,然后在整个计划中逐步解决复杂和更困难的问题。

最后,选择符合上述标准的 3 到 5 个问题。把它们写在一个你可以做笔记并扩展它们的地方。

3、规划

亨利·福特的工厂一直是互联网上流传的一个奇怪故事:福特工厂中的一台巨大蒸汽机开始出现故障,福特的工程师都搞不清楚到底发生了什么。但是,当这位天才(通常是尼古拉·特斯拉或查尔斯·普罗透斯·斯坦梅茨)介入时,他能够将问题隔离为一个微不足道的小部分,需要进行较小的修正。最终账单是 10,000 美元。

福特当然是难以置信的,因为这个人所做的只是在受影响的区域做一个十字,所以这位天才给出了他的 breakup:

指出该部分 $1

9999 美元的工程知识,用于将问题隔离到系统的一个部分

– 好好学学

故事就是这样,当您查看庞大的代码库并希望添加一个小修复程序时,您可能会发现自己处于 Nikola Tesla 的位置。不要害怕,因为您不需要成为天才,您只需要一些基本原则,这些原则可以让您将问题缩小到代码库的一个小的、可管理的部分。

3.1 充分利用问题描述

在许多情况下,您可以省去自己的侦探工作,因为项目的维护者通常已经确定了修复将触及代码库的哪些区域,并且会在问题描述本身中提供此信息。

从头开始没有意义,因此请确保您已查看问题描述中已有的所有信息。

3.2、不要试图遍历整个代码库

当您刚开始时,您可能会想要尝试理解所有内容。这不仅没有必要,而且还会严重损害您的贡献能力,因为 10 次中有 9 次您只会更加困惑。

大多数存储库已经存在了相当长的时间,有几个人贡献和扩展了代码库,使其发展成为现在的样子。在大多数情况下,根本不可能理解那里的每一行代码,您应该尝试从战略上解决问题。

大多数优秀的开源项目的结构都非常好,文件夹层次结构和文件名大多是不言自明的。通常,这些层次结构遵循自上而下的方法:较大的子系统文件夹包含它们的子部分。您需要逐渐将要处理的子系统归零,随着文件夹层次结构的向下移动,最终,您会将工作范围缩小到项目中的几个文件,这是您应该的空间仅限于在处理该问题时。

如果您正在修复错误,问题可能源于系统中的其他地方,但您选择的文件是一个很好的起点,您可以从中尝试追踪问题的根源。探索代码库的一小部分肯定比试图掌握正在发生的一切更容易。

Aside - Paper Cut Principle

当您处理代码库中的几个小问题时,对代码库的基本理解会提高,直到您对代码库中的一切工作方式有所了解。这就是“局外人”如何熟悉代码,并随着时间的推移使用其中的一小部分。

3.3、弄清楚你的部分如何适应

现在您已经确定了修复的范围,您应该将其他所有内容都视为黑盒。确定您的代码部分获得的输入类型、使用方式以及期望从中得到什么。

所有这一切看起来都非常抽象,但 基本思想是您无需了解所有其他内容的实现方式即可添加任何新内容。您假定其他一切都符合他们的规范,然后尝试探索您关注的代码库的一小部分。

当然,对于每一次更改,您都 需要查看代码库的多个不同部分,并且有很多错误的部分。然而,这只是糟糕的软件,在成熟的代码库中,您通常会有一个 明确定义的区域 可以专注于此。

3.4、重现问题

如果您正在努力消除错误,那么在计划修复之前您应该采取的绝对第一步就是实际重现该问题。重现问题的行为本身就是让你完成设置项目的动作,确保它运行并且所有配置都正确,最后重现问题。

有一种简单的方法来重现问题在很多方面都有帮助。它有助于加快开发速度,您可以(并且应该)更进一步并尝试编写一个测试来捕获这种行为。有了这个,您不仅可以快速运行测试,还可以确保项目的未来版本不会意外导致问题再次弹出。

3.5、结构化理论

您已经探索了问题,缩小了兴趣范围,现在已准备好解决您的问题。如果您已经找出错误的根本原因,那么您可以继续制定解决方案,但如果您陷入困境,可能有助于您摆脱困境的一件事是创造性地思考问题的潜在原因。重新解决并尝试验证是否存在任何原因。

当你试图想出一个解决方案时,它有助于集思广益解决问题的多种方法,因为你将能够比较和对比几种方法并归零最佳方法。

破解它,然后做对!

在庞大的代码库中编辑文件时,您可能会陷入分析瘫痪状态。许多想法可能会在您的脑海中闪过,而且通常情况下,由于对代码质量的担忧,您只是停滞不前而不是继续前进

深深有同感

这就是为什么分两个阶段进行很重要。第一个让它工作的地方,直到它保留在你的机器上。有些东西可能是硬编码的,一些部分可以优化,但重要的是你有一些东西可以工作将其从工作状态改进到健壮状态比尝试在第一次就把一切都做好要容易得多

进入 迭代的精神,不要害怕对代码进行更改。完成概念验证后,您可以继续使其正确。

4、编码和指导

4.1、来自导师和维护者的反馈

来自导师和维护者的反馈
另一种有效的(调试)技术是向其他人解释您的代码。这通常会导致您向自己解释错误。有时只是几句话,然后就尴尬地 “算了,我明白了,打扰了”。这非常有效;您甚至可以使用非程序员作为听众。一所大学的计算机中心在服务台附近放了一只泰迪熊。有神秘 bug 的学生必须先向熊解释它们,然后才能与人类辅导员交谈。

---- B. Kernighan & D. Pike(在《编程实践》第 123 页)

如Arandr正确提到的那样,与经验丰富的维护人员交谈并向新贡献者解释您的理解是一种积极的习惯。它们都涉及对代码库的积极思考,通常比尝试试错策略更快。

安排与您的 MLH 导师/代码维护者会面以检查您的计划。尽可能为您的会议做好最详细的计划。理想情况下,计划可以是更改的细分,其中细分是 - 进行此更改所需的主要步骤是什么?这里的一个很好的经验法则是您使用的每个动词都应该在自己的步骤中。

良好的步骤分解示例:

  • 创建一个名为的新类myApiService.js
  • getApiResponse将函数中的代码提取myComponent.js到它自己的类中。此类中的公共方法将是…
  • 编写一个新测试来涵盖参数未发送到xyz函数的情况。

在会议期间,导师/维护者将为您提供对计划的澄清和改进。他们可能会要求改进您计划的某些方面或直接进入验收阶段。

4.2、调试、日志记录和分析器

调试是一门需要进一步研究的艺术……最有效的调试技术似乎是那些设计并内置到程序本身的技术——当今许多最优秀的程序员将近一半的程序用于促进调试过程另一半;前半部分…最终将被丢弃,但最终结果是生产力得到了惊人的提高。
另一个好的调试习惯是记录每一个犯下的错误。尽管这可能会很尴尬,但这些信息对于任何研究调试问题的人来说都是无价的,它还会帮助您了解如何减少未来错误的数量。

---- D. Knuth(计算机编程艺术,第 1 卷)

调试器是每个程序员武器库中最强大的工具之一。理想情况下,为了理解某些函​​数调用,您应该选择一个请求流、发起一个请求,然后让调试器引导您完成整个请求流。当您查看调试器引导您完成的不同文件时,您正在使用您的视觉记忆。您将记住代码的组织方式以及文件的外观。对于许多调试器(例如gdb和pdb),命令集几乎保持不变。作为基本必需品,您应该熟悉以下命令 -

  • l- 显示当前行及以下的代码行
  • p- 评估当前上下文中的表达式并打印其值
  • s- 单步执行代码
  • n- 下一行代码(例如:如果你不想运行 sayargsort()而想跳到下一行,你可以使用n)
  • q- 退出调试器
  • b- 设置断点(取决于提供的参数)

在某些情况下,使用数据断点可能是有利的。数据断点允许您在存储在指定内存位置的值发生变化时中断执行。例如 - 观察变量X到的变化NULL,找出谁过早释放内存并留下悬空指针,在到处访问全局数据时观察流是它的一些用例。Shog9 在 StackOverflow 上提到了一个更全面的用例。

在这一点上,一个经常被问到的问题是——打印语句还不够吗?这要看情况!Glen K. Peterson的以下回答很好地描述了这个论点 -

对于纯粹的软件问题,我发现思考问题并测试系统以更多地了解问题比逐行调试代码有用得多。使用 print 语句,我有一个在命令行或日志文件中发生的所有事情的列表,我可以查看并重建发生的事情,比使用调试器更容易地向前和向后移动。
最难解决的错误通常可以通过远离计算机理解问题来解决。有时用一张纸或白板,有时答案会在我做其他事情时自行显现。最棘手的错误通过仔细查看代码来解决,就像玩 Where’s Waldo 一样。所有其余的似乎最容易使用打印语句或日志记录语句。
不同的人有不同的风格,不同的风格适合不同的任务。打印语句不一定是调试器的一步。根据你在做什么,它们甚至可以做得更好。特别是在没有本地调试器的语言中(Go 有吗?)。
在以下情况下 - 您的程序失败的部分非常大;该程序使用非线性流量控制方法;是多线程的;实时运行;或执行破坏性操作,例如写入文件 - 更好的替代方法是使用日志记录和断言,正如slugfilter 在 StackOverflow 上的简明解释。

MIT 讲师 Robert Miller 和 Max Goldman 在他们的 6.005:软件构造课程的阅读材料中提供了调试的详细解释。

从Python 文档中解释,Profilers 提供程序的确定性分析。其中配置文件是一组统计信息,描述了程序各个部分的执行频率和时长。它们将帮助您了解程序的哪些部分占用了大部分时间和/或资源,以便您可以专注于优化这些部分。麻省理工学院的 Missing Semester阅读材料中提供了一份详细介绍分析器的精彩指南。

综上所述 -

调试是令人厌恶的,不情愿地执行,并且永远吹嘘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值