如何加入团队并学习代码库
本文最初发表在作者个人微博,经原作者 Samuel Taylor 授权,InfoQ 中文站翻译并分享。
我换团队的次数比我实现平衡二叉树的次数还多,但愿有人教我怎样加入一个新团队。尽管学习一个新的代码库很令人畏惧,但我还是发现了一些有用的经验。
当加入一个新团队时,你至少要做三件事。你可以按自己喜欢的顺序来做这三件事情,但是这三件事情都应该尽快地做完。
首先,你需要建立一个开发环境。
在做这件事的时候,要注意你究竟在设置什么。举例来说,如果你需要在本地运行 Redis,这是一个很好的提示,它会在某处执行一些缓存。请注意,你运行内部项目的次序可以帮助你理解依赖性。如果在你提出模型服务之前,需要先运行特性存储,就会提示模型服务可能依赖于特性存储。这种依赖性开始暗示整个体系架构。
记录你正在运行的特定命令及安装的软件包。编写设置文档后,你肯定会遇到一些变化,更正这些变化或许能让你为新团队提供一些速胜捷径。此外,最好知道怎么“破坏”Python 的系统安装程序。
理想情况下,你所研究的代码应该有一些自动测试套件。开始试验和理解代码的一个好方法是,成功地运行这个测试套件,然后完全随机地修改代码基,看看有什么漏洞。
第二件要做的事情就是理解一些架构的概况。
一些团队会有针对问题描述的文档,如果这个文档是对现实的精确描述,那么你当然应该努力去理解。不管怎样,最好让团队中更有经验的人员为你做概述。他们应该知道文档的最近更新的情况(如果确实存在的话),也能够为你描述和 / 或绘制架构。你可以考虑问下面几个示例问题。
- 你有哪些仓库(或部分仓库) /最经常使用的仓库有哪些?它们各自是做什么的?
- 代码在哪里运行?(例如:EC2 实例、Google 的 Kubernetes 引擎、内部部署)
- 部署管道是什么样子?某个功能如何从笔记本计算机到生产中上线?
- 有没有一些服务、包、类或文件令人感到头疼?特别不可靠或容易出错?
- 有没有使用或者依赖外部 API、供应商或者产品?(例如:SendGrid、DataDog、MySQL)
和环境设置一样,你也可以做一些简单的事情来帮助团队,那就是记录架构概述(或者更新现有的文档)。把你学到的东西写下来,把画好的图拍下来,然后把这些信息张贴在团队可以看到的地方。一定要在你的变化上注明“截至”日期。即使是稳定的项目也会在足够长的时间内表现出一些变化,注明截止日期将有助于将来的读者判别是否该相信这个文档。
加入一个新的团队,第三件要做的事情就是开始了解这家公司。
若你是公司的新员工,请明确公司的使命、产品供应及目标。接着尝试去理解你的团队是如何融入其中的。例如,问题如下:
- 我们的团队怎样才能对公司的目标产生影响?
- 如果我们的代码被严重破坏了,谁会生气呢?这事会发生多快?
- 我们与哪些其他团队的互动最多?他们拥有哪些服务 / 代码库?我们是否与其他团队共享部分代码库?
对团队在公司中的地位理解不清楚,你就注定会失败。你可能没有足够的背景来完成工作。
思维方式
我坚信,学习一种新的代码库,最好的方法就是实现真正的功能(甚至是一些小功能)。身为独立的个体贡献者,加入这个团队的全部意义就是要做些什么,没有什么比花时间去做这些事情更好的方法了。通过你的技巧和理解能力的积累,随着时间的推移,你可以完成越来越大的项目。
要完成一些任务,就需要阅读代码。但是,这里的“阅读”可能会成为一个误导词,因为阅读代码与阅读小说截然不同。这些代码通常是有组织的,且非常接近(在同一目录、包、类或文件中)相关代码。你们能想像这样写一部小说吗?如果 Tolkien 把所有两个角色互相打斗的场景都放在相邻的书页里,而所有带有魔法的场景都发生在一本单独的书中?多么荒唐啊!
尽管学习代码让我学到了阅读代码的基本知识,但是从未有人教过我如何阅读一个巨大的代码库。为了达到这个目的,我们必须采取某种思维方式,平衡好每个复杂细节的理解与快速产生效果的关系。迅速做出改变可以帮助你在团队中树立声望,并使你更快地获得精确 / 复杂的理解,而不必事先去了解所有东西。
我的经验法则是,只要能够充分地表达它的功能,且不需要确切地知道它是怎么做的,就可以了。这一过程叫做“分块”,它基于这样一个事实:一旦你对某个代码单元有了基本的理解,“你就不必记住底层的所有细节”(Oakley)。假如你担心无法理解所有的细枝末节,那就做个笔记,然后再回来更全面地理解那部分内容。
这种理解会递增:首先,你理解各种服务的作用。随后,确定你需要修改的具体服务,并开始理解该服务中的各个模块。通过修改模块,你将开始了解所包含的类别。这个递归过程的基本情况是单行。
切记,不同的团队可能用不同的方法来执行相同的概念或模式。了解你当前的团队为何选择这种方式,作为新队友或许可从中找到帮助团队的另一种方式。你的新团队很可能从未听说过你所喜欢的酷炫方法,同样也有可能你的方式在某些你不知道的方面更糟糕。不管是哪种情况,都有人能学到东西。
我最后提出的想法是,在我们深入讨论之前,要尽可能地从代码路径和数据流两方面来理解代码。思考哪些对象知道哪些信息,以及这些信息是如何在系统各部分之间流动的。
步骤
我建议在任何代码库中工作时都采用这个流程。
- 找出与当前任务最相关的代码部分。
- 充分理解这些代码,以便对你需要进行的更改形成假设。
- 做这个修改,然后验证你的假设。有时候,最好的办法就是在 UI 中单击,或运行特定脚本。有时候最简单的方法就是写一个测试,描述一下你想要的行为。
- 如假设不正确,请返回步骤 2。了解为什么这种改变没有产生你所想要的效果,并提出新的假设。
- 一旦你有了可以工作的代码,就提高它的质量。编写一个测试(或几个测试),记录你所做的行为改变。重构你的代码,使其更加清晰和有风格。
这是一种科学的方法,引导我们逐步获得正确的、高质量的代码,而不需要去理解所有与我们相关的变化。
工具
当然,你只需要使用一个文本编辑器和一点耐心就可以解决这个问题,但是在上述确定的过程中,有许多工具可以帮助我们更有效地阅读代码。
识别相关代码
虽然随着时间的推移,随着对某部分代码的熟悉,第一步会变得简单,但我们经常会在第一步开始时完全迷失了方向。下面提供了一些有用的方法:运行代码、项目搜索和代码搜索。
运行代码有助于你理解它,知道存在什么东西,然后再开始改变它。这可能意味着在本地重现一个 bug,在 UI 中找到新功能的位置,或者任何其他事情。当你这样做的时候,在调试器中逐步完成执行将为你理解正在发生的事情提供一个好的开端。
我所说的“项目搜索”,是指搜索作为软件开发生命周期的一部分而创建的构件。问题跟踪器,如 JIRA/Asana/Pivotal Tracker 等,GitHub 和 GitLab 等工具中的拉取请求和问题,以及 git 历史本身,都非常有用。几乎没有任务是真正新颖的,所以我们常常通过寻找过去相似的工作来理解它。试试不同的关键词吧。有时候,你会发现拉取请求执行的内容非常类似于你要做的事情,你可以将其作为指导。试着从零开始预测一些事情,尽管有时候是必要的,但要适应它要比从一个例子开始更加努力。
代码搜索就像它听起来的那样。如果你要在本地签出代码,我强烈建议使用一个专门用于递归搜索的工具,如 ack、Silver Searcher(ag)或 ripgrep。但你并不总能在本地检出公司的每个代码片段,有时候,能够进行详尽搜索是有用的。像 OpenGrok 或 Sourcegraph 这样的工具对这种用例非常有用。GitHub 和 GitLab 还提供在特定组织中搜索所有代码的方法。
不管你用什么工具,试一试你认为可能有关联的关键字。可以考虑改变区分大小写。对特定文件类型进行过滤可能会得到更好的结果。
理解代码
使用不同的搜索工具,我们可以得到一组相关的位置。通过这种方式,我们就进入了流程的第二步:充分理解代码,从而对必要的修改形成一个假设。在这方面,我们所讨论的搜索工具非常有用(如果你遇到一个不熟悉的类的用法,请对其进行搜索并阅读你找到的内容)。
好的 IDE 是另一个非常有用的工具。我喜欢 JetBrains 的产品(我与他们没有任何利益相关),尽管我相信在竞争产品中也有类似的功能。JetBrains 的 IDE 可以帮助你通过直接链接到函数或类的定义,更高效地浏览代码。在 Mac 上,默认情况下,按住 Cmd 键,在函数或类名上悬停鼠标,然后单击,就能够立即跳转到定义,这完全改变了游戏规则。
另一个超级有用的 JetBrains 键盘快捷键是(默认情况下)双击 shift。这将弹出一个搜索栏,可以找到任何东西(类、函数、文件名)。
在阅读代码时,请确保将你的认知负担降至最低。记住要建立“分块”,即头脑盒子,在里面你不需要记住所有的细节。考虑做笔记,写下文件名和行号,画小图。读写代码是工作中对认知要求最高的部分,因此要抓住一切机会使之变得简单。
这期间,你可能会陷入困境或迷失方向。求助没问题。用 git blame 查看哪些人正在处理你感到困惑的代码,然后询问他们。你也可以使用 git blame 找到相关的拉取请求或 JIRA ticket,这些可能有助于获取上下文。
使用库
有时候,在第三步中,我们需要与外部库合作。在一个理想的世界里,所有库都有很好的文档来帮助你理解关键的抽象概念,从而快速地提高生产力。唉,但我们并非生活在一个理想的世界里!很多项目都有很好的文档。许多项目确实有很好的文档。但其他的项目可能更容易通过更广泛的社区来了解。考虑用 DuckDuckGo 或 Google 这样的工具在网上搜索。看看 StackOverflow 上是否有例子。
最近,我意识到 GitHub 允许用户搜索所有公共代码。因此,我们可以找到人们使用我们关心的库和 API 的实际例子。尝试搜索要使用的特定方法名。或者搜索包的名称,然后在出现的各个仓库中搜索。考虑只过滤到你关心的语言。
我发现,GitHub 搜索根据“最近被索引”对结果进行排序,比默认搜索提供更多、更有用的结果(默认搜索一次又一次地为我复制和粘贴同一个示例)。如果你对结果不满意,可以尝试不同的排序顺序。
结语
当我们围绕真实的 ticket 进行学习时,不仅学得更快,而且还能同时发挥作用,并开始在团队中树立威信。在前面的工作中并使用好的工具来寻找这些工作),我们可以加快学习和发挥作用。你要知道,虽然加入一个新的团队很不容易,但是也不一定很难!运用科学方法。按照这些实践。看看这些工具。在给人留下好的第一印象的同时,你会对自己的能力充满信心。
作者介绍:
Samuel Taylor,帮助科学家和研究人员通过优秀的工程设计产生真正的商业影响,引以为豪的事情包括帮助学生学习代码。毕业于贝勒大学计算机科学系,曾在 TripAdvisor 和 Indeed 等公司工作。目前在德克萨斯州奥斯汀市担任机器学习工程师。
原文链接:
https://www.samueltaylor.org/articles/how-to-learn-a-codebase.html