作者 | 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!