Sloc Cloc and Code 4.0 (scc) - 找出最需要关注的文件

Lobsters Hottest 工具

摘要

本文宣布了 Sloc Cloc and Code (scc) 4.0.0 版本的发布,其中包含新的热点分析功能,基于复杂度和提交历史来识别需要关注的代码文件。

<p><a href="https://lobste.rs/s/0i7pks/sloc_cloc_code_4_0_scc_finding_files_need">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/24 23:36

# Sloc Cloc and Code 4.0 (scc) - 找出最需要关注的文件 来源:https://boyter.org/posts/sloc-cloc-code-hotspots-finding-files-that-need-attention/ 今天我发布了 sloc cloc and code 的 v4\.0\.0 版本,也称为 `scc`。虽然最初考虑从 3\.7\.0 升级到 3\.8\.0,但新功能增加得足够多,我认为升级到一个新的主版本是值得的。功能变化也足够大,值得再写一篇博文详细介绍,因为我确实对其中一些新功能感到兴奋。 我将在本文中介绍其中几个特性,希望鼓励亲爱的读者下载最新版本并尝试一下。 ## 热力点 十多年前,我写过关于 Google 的缺陷预测(https://boyter.org/2015/07/issues-googles-bug-prediction-algorithm/)的文章,该算法利用提交历史与缺陷修复的关联来对文件进行排名,从而识别存在问题的文件。这个想法很有趣但后来被终止了,原因是: > 简而言之,开发者觉得它没什么用。有时他们知道代码是热点,有时不知道。但知道代码是热点并没有给他们提供任何改善它的手段。 有趣的是,我忘了我曾写过这个话题,还让多个 LLM 帮我查找,当我要求它们查找时,它们都链接回了我博客上的那篇文章。显然,我现在是关于这个的“权威来源”了。 我一直把这个想法记在心里,希望能进一步探索(所以才尝试再次找到它)。最近我想到,既然 `scc` 有复杂度估算,我们能否用它来过滤噪音?毕竟,知道很多修复都应用于配置文件用处不大,但知道很多修改都应用于一个逻辑复杂的文件就很有价值了。这与我在 codespelunker(https://github.com/boyter/cs)中使用的排名方法类似。 辛普森一家:复杂文件需要最多关注 > 复杂文件需要最多关注! 据我所知,这是 Adam Tornhill 在《Your Code as a Crime Scene》一书中提出的想法的再创造(发现这点后我正在读这本书),他甚至因此创建了 CodeScene(https://codescene.com/)公司。显然,这个指标确实有价值。 真是白费心思,原来我没什么原创点子。 不管怎样,让我们看看使用 `scc` 对其自身代码库运行会得到什么结果: ``` $ scc --hotspots ─────────────────────────────────────────────────────────────────────────────── 热力点 · 最近 1000 次提交 · 2019-07-21 → 2026-06-26 ─────────────────────────────────────────────────────────────────────────────── 文件 语言 复杂度 提交次数 代码行变化 作者数 热力点值 ─────────────────────────────────────────────────────────────────────────────── processor/processor.go Go 156 156 1,651 13 100.0 processor/workers.go Go 244 92 3,617 15 92.2 test-all.sh Shell 56 181 3,287 15 41.7 ~ocessor/formatters_test.go Go 183 51 2,459 9 38.4 processor/workers_test.go Go 408 21 1,189 8 35.2 processor/formatters.go Go 44 135 5,848 17 24.4 main_test.go Go 261 18 995 6 19.3 processor/detector_test.go Go 133 32 1,175 6 17.5 main.go Go 40 101 1,545 17 16.6 processor/file.go Go 50 73 2,074 12 15.0 processor/detector.go Go 70 45 948 5 12.9 processor/file_test.go Go 75 33 826 5 10.2 cmd/badges/main.go Go 73 31 1,111 5 9.3 processor/history.go Go 173 9 941 4 6.4 processor/structs.go Go 25 42 247 10 4.3 config_test.go Go 199 4 850 3 3.3 ~workers_regression_test.go Go 50 13 276 6 2.7 ~rocessor/processor_test.go Go 51 12 289 4 2.5 ~ocessor/history_authors.go Go 111 5 666 3 2.3 mcp.go Go 71 7 527 4 2.0 ─────────────────────────────────────────────────────────────────────────────── 复杂度 × 变更频率,归一化 · 显示了 90 个文件中的 20 个 ─────────────────────────────────────────────────────────────────────────────── ``` 如你所见,输出正确识别了 `processor/processor.go` 和 `processor/workers.go` 是代码库中的热力点。根据我个人经验,可以确认这是正确的。 你为什么要在意?因为这个摘要正在做复杂度或变更频率单独无法做到的事情。 辛普森荷马解释如何做 > 解释如何做! 简而言之,`热力点 = 复杂度 × 提交次数`,在 0\-100 的范围内归一化。我们计算当前 HEAD 版本文件的复杂度,然后向后追溯,查看每个文件被修改了多少次。注意这仅统计 HEAD 中的文件。已被删除的高变更文件不在计算之列。 让我们将其与简单计数进行比较: ``` $ scc --by-file -i go -s complexity ─────────────────────────────────────────────────────────────────────────────── 语言 文件数 总行数 空行数 注释行数 代码行数 总复杂度 ─────────────────────────────────────────────────────────────────────────────── Go 69 40,137 3,049 2,131 34,957 4,478 ─────────────────────────────────────────────────────────────────────────────── processor/workers_test.go 2,156 374 69 1,713 408 main_test.go 992 80 26 886 261 processor/workers.go 966 146 102 718 244 processor/report_test.go 971 98 109 764 237 config_test.go 786 50 85 651 199 ``` 通过运行简单的行数统计,限制为 Go 文件并按复杂度排序,我们看到 `workers_test.go`、`main_test.go` 和 `config_test.go` 排名都很高。这些文件技术上很复杂,但没有一个是真正的核心开发工作所在。复杂度本身只告诉你哪里有包含大量条件判断的大型文件。结果发现,这些往往是测试文件。它们仍然在列表中,只是排名靠后了。当然,高变更频率的测试文件仍然会如预期那样排在前面。 反过来按变更频率(即提交次数)排名。现在 `test-all.sh` 以 181 次提交位居第一,`structs.go` 也以 42 次提交浮上来。两者都经常变化,但都不是缺陷或逻辑所在。变更频率本身告诉你什么经常变化,这通常是配置、脚本和样板代码,但还不能完全代表缺陷或逻辑。 然而,变更频率和复杂度两者的重叠是一个合理的代理指标。哪些文件既复杂又变更频繁!注意,这与 Google 尝试并失败的做法并不完全相同。这个指标不是“历史上容易出错”的指向标,而是“难以处理”的指示器,可能暗示代码需要被拆分。 那么为什么这很有用呢?好吧,没人编辑的复杂代码可能不是问题。它能工作,然后你就继续前行。你经常修改的简单文件可能也不是问题。你添加一行配置,编译器检查通过,然后你继续前行。然而,一个既复杂又变更频繁的文件通常是问题所在。它是你遇到最多合并冲突、最多测试失败、修改起来最痛苦的地方。 现在我已经对 `scc` 代码库了解这些,但想象一下,如果我不熟悉它呢?我刚刚识别出了应用程序核心引擎所在的位置。 回到 Google,他们标记了有风险的文件,但开发者并不在意,因为知道热点在哪里并不能帮助你采取任何行动。知道“这个容易出错”只是在你的 CI/CD 中增加了一个标记,给你更多工作(把它记在我的技术债信用卡上)。知道你熟悉代码库中的热点用处不大。然而,在接入和学习一个代码库时,知道热点极其有用,而这个指标正是在回答那个问题。 > Google 失败了,因为热点标记没有提供可操作的建议,但针对不熟悉的代码库提出类似想法,就变成了接入地图。 \- 我 你还可以指定计算时追溯的 git 提交深度。通过回溯较少或较多的提交(时间),我们可以发现热力点如何转移。 回溯 50 次提交与 10 次对比: ``` $ scc --hotspots --depth 50 ─────────────────────────────────────────────────────────────────────────────── 热力点 · 最近 50 次提交 · 2026-04-13 → 2026-06-26 ─────────────────────────────────────────────────────────────────────────────── 文件 语言 复杂度 提交次数 代码行变化 作者数 热力点值 ─────────────────────────────────────────────────────────────────────────────── processor/processor.go Go 156 14 415 4 100.0 main_test.go Go 261 8 295 4 95.6 processor/history.go Go 173 9 941 4 71.3 processor/workers.go Go 244 6 130 5 67.0 processor/workers_test.go Go 408 3 157 3 56.0 ... $ scc --hotspots --depth 10 ─────────────────────────────────────────────────────────────────────────────── 热力点 · 最近 10 次提交 · 2026-06-25 → 2026-06-26 ─────────────────────────────────────────────────────────────────────────────── 文件 语言 复杂度 提交次数 代码行变化 作者数 热力点值 ─────────────────────────────────────────────────────────────────────────────── processor/workers.go Go 244 2 15 1 100.0 processor/processor.go Go 156 3 20 1 95.9 config_test.go Go 199 2 5 2 81.6 processor/history.go Go 173 1 19 1 35.5 regression_test.go Go 152 1 6 1 31.1 ``` 现在需要注意的一点是,这并没有告诉你代码库有什么问题。它只告诉你应该考虑从哪里着手查看。可能有一个特别严重的 bug 就藏在那个配置文件里。它只是一个指示器! 不过,正如那句话所说,所有模型都是错的,但有些是有用的。 请注意,上述功能都不需要安装 git。虽然它确实需要仓库有 `.git` 文件夹和所需文件,但 `scc` 内置了 `github.com/go\-git/go\-git`,仍然只是一个包含你所需所有功能的单个二进制文件安装包。 当然,这些计算并非免费... 那么获得这种能力的代价是什么? 现在做事情需要时间 - 汉弗莱·阿普比爵士 > 现在做事情需要时间! \- 汉弗莱·阿普比爵士 这对 `scc` 来说以前从未如此。它的运行和产生结果一直相当快(我拒绝说“快如闪电”)。但它以前只处理“现在”,即代码库的当前状态。 处理随时间变化的事情意味着需要回溯 git 历史,默认是最近 1000 次提交(当然你可以覆盖这个设置)。结果就是它比标准 scc 进程慢。 ``` $ hyperfine 'scc' 'scc --hotspots' 基准测试 1: scc 时间(均值 ± 标准差): 11.2 ms ± 0.4 ms [用户: 15.2 ms, 系统: 7.6 ms] 范围(最小 ... 最大): 10.6 ms ... 13.5 ms 194 次运行 基准测试 2: scc --hotspots 时间(均值 ± 标准差): 4.739 s ± 0.068 s [用户: 3.341 s, 系统: 1.611 s] 范围(最小 ... 最大): 4.707 s ... 4.930 s 10 次运行 总结 scc 运行速度 比 scc --hotspots 快 421.57 ± 14.52 倍 ``` 以上是在我的 Macbook Air 2020 M1 上针对 `scc` 自身代码库计算的结果。它本身不算慢,但肯定没有在同台机器上运行标准 `scc` 处理该代码库所需的约 12ms 那么快。这算快吗?我不知道。我自己没用过 codescene。也许有人能告诉我。我试过运行 bugspots(https://github.com/igrigorik/bugspots)做对比,但由于代码库较老,可能无法运行。 ## 变更耦合度 既然我已经从 CodeScene 借鉴了热力点想法,我想我也可以借鉴变更耦合度功能。其基本思想是,如果文件经常出现在同一个提交中,无论是否存在编译器强制的依赖关系,这些文件之间就存在相互依赖。 对 `scc` 自身运行该功能会产生以下精简输出: ``` $ scc --coupling ─────────────────────────────────────────────────────────────────────────────── 变更耦合度 · 最近 1000 次提交 · 2019-07-25 → 2026-07-20 ─────────────────────────────────────────────────────────────────────────────── 文件 A 文件 B 共同提交次数 耦合度 ─────────────────────────────────────────────────────────────────────────────── languages.json processor/constants.go 198 67.8% LANGUAGES.md languages.json 167 61.2% LANGUAGES.md processor/constants.go 153 58.2% SCC-OUTPUT-REPORT.html processor/constants.go 149 37.7% ``` 输出显示,`languages.json` 的变更通常会修改 `processor/constants.go`。这确实属实,上面的其他输出也是如此,因为每次添加或修改新语言时,上述每个文件都会更改。 虽然有趣,但当应用于特定文件时,它的用处更大: ``` $ scc --coupling-for ./processor/detector.go ─────────────────────────────────────────────────────────────────────────────── 变更耦合度 · 最近 1000 次提交 · 2019-07-25 → 2026-07-20 ─────────────────────────────────────────────────────────────────────────────── 关联文件 共同提交次数 耦合度 ─────────────────────────────────────────────────────────────────────────────── processor/detector_test.go 26 49.1% processor/workers.go 15 12.1% processor/structs.go 9 11.1% processor/file_test.go 7 9.7% processor/workers_test.go 6 9.7% processor/processor_test.go 5 9.4% ``` 现在这就有趣多了,尽管在这个例子中展示了显而易见的关联。如果你修改了检测器,你可能也需要修改它的测试。这个功能真正有用的地方在于,当你处理随机文件并想知道可能的爆炸半径(而这些关联并未被你的编译器检查覆盖)时。 然而,这种耦合可能存在同样的问题,即非代码文件也可能被检测到。因此,我们可以应用热力点技巧,按复杂度加权,得到下面的结果: ``` $ scc --coupling-weighted --coupling-for ./processor/detector.go ─────────────────────────────────────────────────────────────────────────────── 变更耦合度 · 最近 1000 次提交 · 2019-07-25 → 2026-07-20 ─────────────────────────────────────────────────────────────────────────────── 关联文件 共同提交次数 分数 ─────────────────────────────────────────────────────────────────────────────── processor/detector_test.go 26 100.0 processor/workers.go ...

相似文章

Backplanes 的 Spotlight

Product Hunt

Backplanes 推出了 Spotlight,为 Claude Code 和 Codex 提供会话报告,帮助改进您的代码。

multica-ai/andrej-karpathy-skills

GitHub Trending (daily)

一个单独的 CLAUDE.md 文件,实现了四项原则,以改进 Claude Code 的编码行为,源自 Andrej Karpathy 对 LLM 编码陷阱的观察。