打开网易新闻 查看更多图片

作者 | Kevin Peters

译者 | 弯月

出品 | CSDN(ID:CSDNnews)

以下为译文:

在担任软件工程师的那几年里,我研究了很多代码库,可能有数百个之多。大多数时候,我都很发愁找不到相关的代码。一般我只能问别人,或者查看相关的文档。渐渐地,我就能看懂这些代码了。有些人理解代码的速度比较快,而有些人则比较慢,不过不用担心,慢慢地你也能看懂。大多数代码都很复杂。但是我发现了一个简单的工具,可以帮助你更轻松地理解代码。这款工具名叫 code-complexity(https://github.com/simonrenoult/code-complexity),使用方法如下:

npx code-complexity . --limit 20 --sort ratio# You can also use --filter '**/*.js' to use glob patterns to filter files

返回结果:

FILE

COMPLEXITY

CHURN

RATIO

src/cli.ts

103

8

824

test/code-complexity.test.ts

107

7

749

.idea/workspace.xml

123

6

738

这个列表显示出了最大的文件以及改动最多的文件。这些文件对于理解应用程序至关重要。你需要仔细阅读并理解这些文件。至于这些数据的详细信息,请参见下面的介绍。

复杂度与变动

首先,我们来看看复杂度(COMPLEXITY)和变动(CHURN)。这些是掌握快速理解代码库的技巧的基础知识。

什么是复杂度?

复杂度有很多种定义方式。通常,我们通过函数的嵌套层数来衡量代码的复杂度。由小型函数以及行为的组合构成的代码通常更易于阅读和理解。因此,我们可以认为复杂的代码包含一些嵌套的函数。嵌套很难跟踪,因此我们可以寻找一些其他的指标。

一般函数比较大的代码,文件也会比较大。如果人们喜欢将所有代码都放入一个函数中,那么他们往往也会将所有代码放在一个文件中。因此,从理论上讲,我们也可以将代码行数作为衡量标准。这类的工具包很多,sloc 就是其中一个。该工具能够输出文件中的代码行数。但你不需要直接使用这个工具,我前面提到的工具默认就包含该工具。

因此,简而言之,我们可以认为复杂的文件要么拥有很多嵌套,要么文件本身很大。这两种情况通常会一起出现,这是好事,因为分析文件的长度通常比嵌套容易。

什么是变动?

变动大的文件指的就是发生了很多变化的文件,很多人都对这个文件进行了修改。但是,这一点可以衡量吗?git 的历史记录可以告诉我们文件签入的频率。因此,我们可以确定文件的变化情况。通常,这类的文件都是应用程序的重心。尽管配置文件会经常发生变化,但我们可以在分析的时候将它们排除在外。

我们可以通过复杂度+变动了解到什么?

在介绍了复杂度和变动的含义之后,下面我们来看看我们能够通过二者了解到哪些信息。变化非常多,且非常复杂的文件通常都应该重构。在大多数情况下,这些文件都是应用程序的核心。应用程序的基本逻辑都包含这些文件或相关的文件中。下面我们来看看如何进行进一步分析。

仔细检查文件

检查文件的方法很简单。首先,我会查看文件,看看调用了哪些导出函数。我会将它们记下来。内部函数暂时不重要。了解所有导出函数后,我会进一步检查是否有单元测试。如果这些函数也有参数,那么我也会将它们写下来。我们可以使用 TypeScript 或 Flow 类型,理解整体的代码结构。

我们可以通过单元测试了解函数。你只需要看看输入、函数名称及其返回值即可。在大多数情况下,类型就可以表明一切,而单元测试可以向你展示函数的一些极端情况以及使用方法。这些信息就足以理解函数了。当然你也可以更深入地了解函数,但没有这个必要。为什么?请参见下面的介绍。

为什么不需要了解每个细节?

详细了解函数固然很重要,但在刚入职期间,你还有许多其他更为重要的工作。你无法在短时间内理解应用程序的每一部分,但是熟悉核心部分可以方便你了解应用程序的核心逻辑在哪里执行。

有了这些知识,你就可以接手第一个需要解决的问题了。理想情况下,团队会为刚来的新人准备一些小任务,帮助你快速入门。如果没有,你也可以问问经理或团队中的高级工程师是否有合适你的任务。你需要展示出你对代码库的了解,才能让他们看到你的知识水平。

一般,第一个任务最好与团队中的其他软件工程进行结对编程。你可以主动申请输入代码,让他们在边上观看,这样你就可以学习如何浏览代码库了。由于有人在旁边指导,而且你担任的任务也不难,所以你不需要深入细节。你可以在以后改 bug 或添加功能的时候,再深入了解代码的详细信息。你担任的工作越多,对代码库的了解就越深入。但是,我们还是需要经常回顾变动和复杂度,因为它们会随着时间而变化。

调试细节?

为了真正熟悉代码库,你还需要注意一个重要的方面:调试。可能在担任第一个任务的时候,你就学会了如何在本地运行应用程序、运行单元测试以及集成或 E2E 测试。在实现功能的时候,这些知识非常重要,因为添加测试可以确保应用程序能够按照预期运行。通常,这些测试会覆盖很多代码,而且通常都很抽象。因此,你必须学习调试代码。由于大多数测试都在 Node.js 环境中运行,所以我们需要快速学习如何调试基于 Node.js 的应用程序。大多数工程师都会在调试中使用 console.log,但如果你需要跟踪的代码结构非常大,则我建议你使用合适的调试器。JavaScript 和 TypeScript 支持关键字 debugger,但是,你很难利用 debugger 运行测试套件,而且调试体验也不好,因为在使用 Node.js 时,启动一个浏览器实例并将其调试工具连接到程序还是有些难度的。还有一种办法是,使用 IDE 或编辑器来连接调试器。例如,Visual Studio Code 支持直接在 IDE 中调试 Node.js 应用程序。

调试本身就是一门艺术。你应该习惯使用断点以及“ step over ”和“ step into ”等调试功能。这些功能在调试嵌套函数时非常有方便。

示例

下面,我们使用文本介绍技巧来探索一些代码库,以说明如何找出应用程序的核心,以及如何通过上述方法更快地熟悉代码库。

Blitz.js

Blitz.js 是一个建立在 Next.js 之上的框架。该框架的描述为:面向 JavaScript / TypeScript 的 Ruby on Rails。该框架的开发已经持续了一年多,下面我们就来看看他们的逻辑核心放在何处。

第一步是将代码库克隆到本地文件夹,然后运行:

npx code-complexity . --limit 20 --sort ratio

输入结果如下表所示:

FILE

COMPLEXITY

CHURN

RATIO

nextjs/packages/next/compiled/webpack/bundle5.js

91501

1

91501

nextjs/packages/next/compiled/webpack/bundle5.js

91501

1

91501

nextjs/packages/next/compiled/webpack/bundle4.js

74436

1

74436

packages/cli/src/commands/generate.ts

228

28

6384

packages/cli/src/commands/new.ts

177

35

6195

packages/generator/src/generators/app-generator.ts

235

23

5405

packages/generator/src/generator.ts

283

19

5377

packages/server/src/stages/rpc/index.ts

184

28

5152

packages/server/test/dev.test.ts

190

27

5130

packages/core/src/types.ts

160

28

4480

packages/server/src/next-utils.ts

176

25

4400

packages/generator/templates/app/app/pages/index.tsx

240

18

4320

packages/server/src/config.ts

116

37

4292

packages/core/src/use-query-hooks.ts

184

22

4048

nextjs/test/integration/file-serving/test/index.test.js

3561

1

3561

examples/auth/app/pages/index.tsx

210

16

3360

packages/cli/src/commands/db.ts

75

44

3300

.github/workflows/main.yml

132

24

3168

packages/cli/test/commands/new.test.ts

141

19

2679

examples/store/app/pages/index.tsx

181

14

2534

packages/display/src/index.ts

158

16

2528

如你所见,很多不相关的文件已经被过滤掉了,对于初步分析而言,这就足够了。

我们看到了很多非常重要目录:

  • packages/cli

  • packages/generator

  • packages/server

  • packages/core

如果此时我们接到一项任务,那么至少我们知道去哪里找相关的代码。首先,我会设法了解 packages/core 文件,看看它们在做什么。如果有测试的话,还应该看看测试,这样就可以让你对 Blitz 有很好的了解。

React.js

如今,React.js 几乎是每一位 Web 开发人员都熟知的前端框架。但大多数人并不知道这个代码库的结构以及核心部分。下面,我们就来看一看。

npx code-complexity . --limit 20 --sort ratio

运行上述命令,可以得到如下结果:

FILE

COMPLEXITY

CHURN

RATIO

packages/eslint-plugin-react-hooks/**tests**/ESLintRuleExhaustiveDeps-test.js

7742

51

394842

packages/react/src/**tests**/ReactProfiler-test.internal.js

4002

95

380190

packages/react-reconciler/src/ReactFiberWorkLoop.new.js

2373

139

329847

packages/react-reconciler/src/ReactFiberWorkLoop.old.js

2373

114

270522

packages/react-dom/src/server/ReactPartialRenderer.js

1379

122

168238

packages/react-reconciler/src/ReactFiberCommitWork.new.js

2262

71

160602

packages/react-devtools-shared/src/backend/renderer.js

2952

54

159408

packages/react-reconciler/src/ReactFiberBeginWork.new.js

2903

53

153859

scripts/rollup/bundles.js

760

199

151240

packages/react-reconciler/src/ReactFiberHooks.new.js

2622

56

146832

packages/react-dom/src/client/ReactDOMHostConfig.js

1018

140

142520

packages/react-reconciler/src/ReactFiberHooks.old.js

2622

50

131100

packages/react-reconciler/src/**tests**/ReactHooks-test.internal.js

1641

74

121434

packages/react-dom/src/**tests**/ReactDOMComponent-test.js

2346

51

119646

packages/react-dom/src/**tests**/ReactDOMServerPartialHydration-test.internal.js

2150

49

105350

packages/react-noop-renderer/src/createReactNoop.js

966

109

105294

packages/react-reconciler/src/ReactFiberCommitWork.old.js

2262

46

104052

packages/react-reconciler/src/ReactFiberBeginWork.old.js

2903

35

101605

packages/react-reconciler/src/**tests**/ReactIncrementalErrorHandling-test.internal.js

1532

62

94984

packages/react-refresh/src/**tests**/ReactFresh-test.js

3165

29

91785

我们可以看到如下两个文件夹对于理解该代码库非常重要:

  • packages/react-dom

  • packages/react-reconciler

了解 React Fiber 以及 react-dom 的部分渲染器可以让你对 React 的体系结构有很好的了解。尽管 React 代码非常复杂,但该代码库有非常详细的注释。

Venom:Whatsapp 的 TypeScript 客户端

Venom 是用来连接 Whatsapp 的一个库。你可以通过这个库发送消息并执行各种操作。下面,我们来运行如下命令:

npx code-complexity . --limit 20 --sort ratio

输出结果:

FILE

COMPLEXITY

CHURN

RATIO

src/lib/jsQR/jsQR.js

9760

5

48800

src/lib/wapi/wapi.js

474

44

20856

src/api/layers/sender.layer.ts

546

36

19656

src/lib/wapi/store/store-objects.js

362

24

8688

src/controllers/initializer.ts

178

48

8544

src/lib/wapi/jssha/index.js

1204

5

6020

src/api/layers/retriever.layer.ts

171

29

4959

src/types/WAPI.d.ts

203

24

4872

src/api/layers/host.layer.ts

258

17

4386

src/api/layers/listener.layer.ts

206

21

4326

src/controllers/browser.ts

141

29

4089

src/controllers/auth.ts

192

21

4032

src/api/model/enum/definitions.ts

589

6

3534

src/api/whatsapp.ts

95

30

2850

src/lib/wapi/functions/index.js

97

24

2328

src/api/layers/profile.layer.ts

82

22

1804

src/lib/wapi/business/send-message-with-buttons.js

323

5

1615

src/api/layers/group.layer.ts

115

14

1610

src/api/layers/controls.layer.ts

76

20

1520

src/api/model/message.ts

114

11

1254

我们可以看到下面这几个目录很重要:

  • src/lib

  • src/api

  • src/controllers

我们可以看到 src/lib 中的文件是自动生成的。理想情况下,我们可以将它们过滤掉。我们再来看一看其他文件。

我们可以看到,src/api/layers/sender.layer.ts和src/api/layers/retriever.layer.ts 并不复杂,但是有很多变动。也就是说,每次添加或删除功能都会改动这些文件。这些是应用程序的核心文件,如果想了解代码库的结构,那么首先需要熟悉这些文件。

总结

希望本文对你有所帮助。熟悉一个陌生的代码库非常困难,尤其是在不断变化的 JavaScript 世界中,更是难上加难。但你可以利用本文介绍的工具和方法,更轻松地了解代码库。

原文链接:https://www.kevinpeters.net/the-fastest-way-to-understand-new-code-bases

声明:本文由CSDN翻译,转载请注明来源。

CSDN 问答上线《冲榜分奖金》活动!每周采纳榜前五名的答主可获得现金和会员卡,剩余用户会随机抽取送出幸运礼物!后台回复关键词“冲榜”可获取当前排名和活动规则

☞从科大讯飞跳槽到腾讯被判赔 1200 万;华为多款机型将取消充电器;苹果春季发布会定档4月21日|极客头条 ☞叫板英特尔,英伟达发布首个 CPU,集齐“三芯”! ☞力排众议,自由软件之父 RMS 正式回归 FSF!