
🎯 学 gstack 的代码质量组合评分系统:不是跑一个 linter 就评价代码质量,而是将类型检查器(22%)、Linter(18%)、测试运行器(28%)、死代码检测器(13%)、Shell Lint(9%)和 GBrain 代码智能(10%)融合为单一健康评分——6 个工具如同 6 个专科医生联合会诊,综合判断代码库的健康状况。 ⏱️ 预计时间:30 分钟
[!quote]- 📖 原Skill精要 技能名称:health 核心功能:代码质量仪表盘。包装项目现有工具(类型检查器、Linter、测试运行器、死代码检测器、Shell Linter),计算加权综合 0-10 评分,追踪时间趋势。六个工具如同六个专科医生联合会诊,综合判断代码库健康。 所属体系:gstack 虚拟工程团队 协作关系:可作为 [[L6-25-发布上线管理|ship]] 前的质量关口
§1 课程概览
health 是 gstack 的代码质量综合评分系统——它不替代任何单一工具,而是将 6 个工具(Typecheck 22%、Lint 18%、Tests 28%、Dead Code 13%、Shell 9%、GBrain 10%)的独立诊断融合为一加权健康评分(0-100)。Tests 权重最高(28%)因为只有测试能验证"逻辑正确性"。GBrain 作为 gstack 自有的代码智能引擎,从圈复杂度、耦合度、安全气味等 6 个维度捕捉其他工具无法检测的架构级问题。六步工作流(Detect → Run → Score → Present → Persist → Trends)将体检从一次性快照变为持续追踪。与 /qa(测试功能质量)和 /review(PR 变更质量)构成三个维度的质量评分矩阵,在 /ship 中形成综合合入门禁。
[!tip] 白话小课堂 想象你去医院体检,抽血、心电图、B 超每一项都有一个报告。health 就是把这些专科报告汇总成一张"综合健康分"的体检总表——告诉你这个代码库整体有多健康,而不是"ESLint 报了 47 个 warning"这种碎片信息。就像你不会拿着血常规报告问医生"我是健康的吗",你也不应该拿着 ESLint 输出问"这个代码库质量好吗"。
§2 Health 是什么——代码的"体检报告"
传统的代码质量工具给出的是碎片化的"专科诊断":ESLint 告诉你 47 个 warning(然后呢?),TypeScript 报 12 个类型错误(严重吗?),测试覆盖率 67%(是好是坏?)。单一工具的回答只覆盖了代码质量的某一个维度,无法回答"整个代码库有多健康"这个问题。
health 的解决方案是加权融合。它将六个专科医生的独立诊断按确定性权重合成一张"综合体检表":
类型安全(Typecheck):22%
代码风格(Lint):18%
测试健康(Tests):28%
死代码(Dead Code):13%
Shell 质量(Shell):9%
GBrain 代码智能(GBrain):10%
= 加权综合健康评分 / 100
一个数字回答一个根本问题:这个代码库整体有多健康?更重要的是,这个数字随时间变化——你可以看趋势,而不是只看一张快照。
💡 白话小课堂:这就是把"你的胆固醇偏高""你的心率不齐""你的肺活量偏低"汇总成"你的健康评分 73/100,需要关注心血管系统"。
§3 六大类别权重详解
Typecheck(类型检查)—— 22%
运行项目配置的类型检查器(tsc / mypy / sorbet / go vet)。0 错误 = 满分 22,每个错误扣 1 分。为什么是 22%?因为类型错误是编译器验证的"事实"而非"意见"——它是 6 项中确定性最高的信号。一个类型错误不是"风格不好",是"这段代码在运行时一定会以某种方式失败"。
Lint(代码风格/静态分析)—— 18%
运行项目配置的 linter(eslint / rubocop / ruff / golangci-lint)。0 警告 = 满分 18,每个 warning 扣 0.5 分,每个 error 扣 1 分。为什么低于 Typecheck?因为 lint 规则包含主观偏好(如"单引号还是双引号""每行最多多少字符"),信号略弱——但 lint 仍然能捕捉到"大概率导致 bug 的模式"(如 == vs ===、未使用的变量)。
Tests(测试健康)—— 28%
最高权重——测试是代码质量的最后防线。三个子维度:
- Test Pass Rate (12%):通过率 x 12——测试通过是最基本的健康信号
- Test Coverage (10%):行覆盖率 x 10(上限 10)——但高覆盖率不等于高质量测试
- Test Presence (6%):有测试文件 → 6,无 → 0——有测试总比没有好
为什么最高?因为类型检查、lint、死代码检测都能告诉你代码"写得怎么样",但只有测试能告诉你代码"逻辑对不对"。一个通过了所有类型检查的函数仍然可能把"加"写成"减"——只有测试能捕获这种逻辑错误。
Dead Code(死代码检测)—— 13%
运行项目支持的死代码检测器(JS/TS: ts-prune / knip,Ruby: debride / coverband,Python: vulture)。无死代码 = 满分 13,每个未使用导出扣 1 分。死代码是技术债务的体量指标——它不会引起 bug,但它让代码库更难理解、更慢编译、更让新人困惑。
Shell(Shell 脚本质量)—— 9%
对项目中所有 .sh 文件运行 shellcheck。0 问题 = 满分 9,每个 warning 扣 0.5 分。权重最低——但 Shell 脚本中的错误可以是灾难性的:一个未加引号的变量在 CI 中可能变成 rm -rf /。
GBrain(代码智能分析)—— 10%
gstack 自己的代码分析引擎,用 AI 和静态分析结合的方式评估代码的深层质量。这是最"软"的指标——但它捕捉了所有其他工具漏掉的架构级问题(详情见 §4)。
🔑 核心秘诀:为什么 Tests 权重最高(28%)?因为类型检查、lint、死代码检测都能告诉你的代码"写得怎么样",但只有测试能告诉你的代码"逻辑对不对"。你可以写一段通过了所有类型检查、lint 零警告、没有死代码的代码——但仍然算错了总价。
§4 GBrain 子评分——六个维度的代码智能
GBrain 不是外部工具——是 gstack 自己的代码分析引擎。它用 AI 和静态分析结合的方式评估代码的深层质量。架构问题不会出现在类型错误或 lint 警告中——但架构问题是最昂贵的修复,所以必须被度量。
维度 1: Cyclomatic Complexity(圈复杂度)—— 2 分
每个函数的决策路径数量。高圈复杂度 = 函数做太多、难测试、bug 温床。> 10 开始扣分,> 20 严重扣分。一个圈复杂度 30 的函数有 30 条不同的执行路径——谁能保证 30 条都正确?
维度 2: Coupling & Dependency(耦合与依赖)—— 2 分
模块之间的依赖数量和方向。循环依赖 = 严重扣分(最差的结构问题——A 依赖 B,B 依赖 A,两者都无法独立理解和测试)。过多的外部模块依赖 → 扣分。扁平依赖图 → 高分。
维度 3: Code Consistency(代码一致性)—— 2 分
命名模式一致吗?错误处理风格一致吗?文件组织逻辑一致吗?一致性高的代码 → AI 和人类都更容易理解和修改。不一致的代码→每个文件都需要重新学习它的"方言"。
维度 4: Security Smells(安全气味)—— 2 分
硬编码的密钥、令牌、密码;危险的函数调用(eval, exec, shell=True);缺失的输入验证;不安全的默认配置。这些不会被类型检查发现,但可能是安全漏洞。
维度 5: Documentation Density(文档密度)—— 1 分
公共 API 的文档覆盖率。注释的质量(不是数量)——解释"为什么"而非"做了什么"。关键设计:过时的注释扣分比没有注释更多——错误的文档比没有文档更危险(没有文档你只是不知道,错误文档会误导你)。
维度 6: Error Handling Hygiene(错误处理卫生)—— 1 分
异常被正确传播而不是被静默吞掉。空 catch 块 = 扣分。返回错误而不是抛出(Go/Rust 风格检查)。一个空的 catch (e) {} 是最危险的代码之一——它让系统在错误状态下继续运行,但没人知道出了什么问题。
⚠️ 避坑指南:GBrain 中有一个容易被忽视的细节——"过时的注释扣分"比"没有注释"扣更多的分。这是有意设计的:过时注释的本质是"对代码库的撒谎"。没有注释你只是不知道函数的意图,过时注释让你相信一个错误的意图——你会基于错误的假设做出修改。
§5 六步工作流——从检测到持久化
Step 1: Detect Stack(检测技术栈)
读取 package.json / Gemfile / pyproject.toml / go.mod → 确定语言和主要框架 → 识别可用工具。TypeScript → tsc + eslint + ts-prune;Ruby → sorbet + rubocop + debride;Python → mypy + ruff + vulture;Go → go vet + golangci-lint + staticcheck。如果多语言共存 → 对每个语言分别评分后取加权平均。
这一层的设计要点是"零配置"——health 不需要你告诉它你用了什么工具,它自己从项目文件中推断。这降低了使用的摩擦:不需要写 health 配置文件。
Step 2: Run Tools(运行所有工具)
并行运行所有检测到的工具,捕获每个工具的输出(stdout + stderr)。工具运行失败 → 该类别得分 0(不阻塞整体评分——一个坏掉的工具不应该让整个体检失败)。限时运行——每个工具最多 2 分钟(防止某个工具挂死阻塞整个流程)。
Step 3: Score(评分)
根据权重公式计算每个类别的得分 → 汇总为总健康评分(0-100)→ 生成评分明细表。评分公式的核心设计是"每个错误独立扣分"——这样你不会因为一个类别有 200 个 lint warning 就被打 0 分(扣分有上限保护)。
Step 4: Present(展示结果)
表格形式展示评分明细:
Code Health: 73/100 (FAIR)
Category | Score | Max | Status
-------------|-------|-----|--------
Typecheck | 20/22 | 91%| ✓ GOOD
Lint | 14/18 | 78%| △ FAIR
Tests | 19/28 | 68%| △ FAIR
Dead Code | 11/13 | 85%| ✓ GOOD
Shell | 9/9 | 100%| ★ EXCELLENT
GBrain | 6/10 | 60%| ✗ POOR
同时展示关键发现列表——导致扣分最多的具体问题。不是扔一个数字就不管了,而是告诉团队"你的 73 分是被这 3 个问题拖下去的"。
Step 5: Persist(持久化)
写入 gstack-review-log,与 /review 和 /qa 的评分一起存储,为趋势分析积累数据。每次 health 运行不是孤立事件——它是时间序列的一个数据点。
Step 6: Trends(趋势分析)
读取历史 health 评分,展示趋势线,标记恶化趋势。趋势让 health 从"一次性快照"变成"持续监控"——你能看到代码健康在变好还是变差,而不是只知道"现在是多少分"。
§6 健康评分等级——不止一个数字
评分带与工程含义
Score Range | Grade | 含义
90-100 | ★ EXCELLENT | 生产就绪,无显著技术债务
80-89 | ✓ GOOD | 高质量,少量可改进项
70-79 | △ FAIR | 可接受,累积了一些技术债务
60-69 | △ NEEDS WORK | 有明确的技术债务需要偿还
50-59 | ✗ POOR | 显著的质量问题,建议优先处理
0-49 | ✗ CRITICAL | 系统性质量问题,不应继续添加新功能
与 /ship 集成的阈值
- Health >= 80 → 合入无阻碍
- 70 <= Health < 80 → 建议修复后再合(警告但不阻止)
- 60 <= Health < 70 → 强烈建议修复
- Health < 60 → 阻止合入——先提高代码健康度
权衡哲学
health 评分是建议性而非强制性的。紧急 hotfix → 可以忽略低健康评分(救火优先)。但在正常开发流程中,低评分 = 红灯——评分的目的是让债务可见,不可见的债务会无限累积。
§7 趋势追踪——健康是动态的
为什么追踪趋势?
代码健康不是静态属性——每次 PR 都在改变它。一次性评分告诉你"现在是什么状态",趋势告诉你"我们在往哪个方向走"。
趋势指标
[3 weeks ago] 68 NEEDS WORK
[2 weeks ago] 72 FAIR ↑ +4
[1 week ago] 75 FAIR ↑ +3
[now] 73 FAIR ↓ -2
趋势解读
- 持续上升 → 团队在偿还技术债务——好事
- 持续下降 → 技术债务在累积——需要关注
- 持平 → 维持现状——对低分来说不够好(70 分持平不是"稳定",是"停滞")
- 大幅波动 → 质量不稳定——需要建立门禁
趋势写入 CLAUDE.md
health 可以在项目 CLAUDE.md 中维护一个 ## Health Trends 章节,每次运行后更新,让所有 Agent 都能看到代码健康的历史趋势,在 plan mode 中影响代码重构的优先级决策。
GBrain 趋势的特殊价值
GBrain 捕捉的架构问题往往是最慢改善的指标。如果 GBrain 持续下降 → 警告信号——架构在腐烂。如果所有其他指标上升但 GBrain 下降 → 在修症状(lint、类型)但不管病因(架构复杂度)。这就是"表面干净,内里腐烂"的信号。
§8 与其他质量系统的关系
三大质量评分体系
gstack 有三个从不同维度度量代码质量的系统:
| 系统 | 测量什么 | 数据来源 | 典型评分 |
|---|---|---|---|
| /health | 代码结构质量 | 静态分析工具 | 73/100 |
| /qa | 测试功能质量 | 测试运行结果 | 82/100 |
| /review | PR 变更质量 | 审查发现统计 | 8.5/10 |
三者如何互补?
- /health 告诉你代码库的整体状况(广度优先——全局快照)
- /qa 告诉你当前功能是否正常工作(行为验证——运行时正确性)
- /review 告诉你本次变更引入了什么问题(变更焦点——增量质量)
三种组合的诊断意义:
- health 高 + qa 低 → 代码写得好但逻辑有 bug(结构优良但行为错误——优先修 bug)
- health 低 + qa 高 → 功能正常但代码质量在退化(测试通过但代码在腐烂——开始重构)
- health 低 + qa 低 + review 低 → 严重的工程问题(三个维度都报警——需要全面干预)
在 /ship 中的综合门禁
/ship 读取三个评分:三个都高 → 快速合入;任一低 → 警告并展示问题列表;两个或以上低 → 阻止合入。
§9 结构拆解
health Skill 结构模板
核心特征
- 管理对象: 代码库的整体静态质量(结构 + 风格 + 测试 + 安全)
- 核心原则: 加权融合——6 个工具的独立诊断按确定性权重合成单一健康评分
- 关键设计: Tests 最高权重(28%)因为只有它能验证逻辑正确性;GBrain 捕捉其他工具漏掉的架构级问题
通用结构
-
技术栈检测层: 读取 package.json/Gemfile/pyproject.toml → 识别可用工具 → 多语言加权平均 输入: 项目根目录的文件系统 输出: 工具清单 + 语言权重分配
-
工具运行层: 并行运行 Typecheck(22%) + Lint(18%) + Tests(28%) + Dead Code(13%) + Shell(9%) + GBrain(10%) 每个工具限时 2 分钟,捕获 stdout/stderr 工具失败不阻塞整体(该类别得 0 分)
-
评分汇聚层: 各工具独立评分 → 加权求和 → 总健康分(0-100) → 等级判定 公式: Σ(category_score × weight) / Σ(weight) × 100 等级: EXCELLENT/GOOD/FAIR/NEEDS WORK/POOR/CRITICAL
-
展示持久层: 评分明细表 + 关键发现列表 → 写入 review-log → 趋势追踪 在 CLAUDE.md 中维护 Health Trends 章节
-
GBrain 子引擎: 圈复杂度(2) + 耦合依赖(2) + 代码一致性(2) + 安全气味(2) + 文档密度(1) + 错误处理卫生(1) 总计 10 分,捕捉其他工具无法检测的架构级问题
-
门禁集成: /ship 综合门禁(health + qa + review 三维度评分矩阵) Health >= 80: 无阻碍 / 70-79: 警告 / 60-69: 强烈建议 / < 60: 阻止
§10 电商 Skill 案例:电商平台的代码健康持续监控
🛒 实战案例:某电商后台管理系统是一个3年前启动的老项目(Node.js+TypeScript,12万行代码,4个微服务),最近3个月线上故障频率上升(从月均1次到月均4次),新功能开发速度下降(从2周/功能到5周/功能)。CTO怀疑代码健康度在持续恶化但无数据支撑。用
/health建立持续监控体系。
- 首次全项目体检(Week 1):4个服务得分——api-gateway 78/100(FAIR,Lint警告217个,GBrain圈复杂度平均14)、payment-service 85/100(GOOD,最健康的服务,类型检查满分,Dead Code仅3处)、inventory-service 62/100(NEEDS WORK,Dead Code 11处,圈复杂度平均22,3个函数圈复杂度>30)、web-frontend 70/100(FAIR,Shell脚本未检查,测试覆盖率仅47%)。总项目Health Score 73.75/100。
- 趋势追踪(Week 1-8):建立每周自动运行
/health+数据持久化机制。8周趋势——api-gateway 78→76→74→73→72→72→71→71(↓-7,持续下滑)、payment-service 85→84→85→86→86→85→85→86(≈稳定)、inventory-service 62→63→61→60→60→59→58→57(↓-5,持续恶化,Dead Code从11处增至19处)、web-frontend 70→71→73→74→75→76→77→78(↑+8,稳步提升)。- 诊断发现:api-gateway持续下滑的原因——新功能开发时为赶进度跳过了类型注解更新和lint修复,技术债务以每周+3处的速度累积。inventory-service恶化更严重——Dead Code从11处增到19处(团队在废弃功能上只注释不删除),圈复杂度从平均22升到27(在旧逻辑上叠加新逻辑而非重构)。web-frontend上升的原因——前端团队引入了自动化测试生成工具,测试覆盖率从47%提升到68%。
- 决策与行动:CTO基于数据做决策——(1)api-gateway:在
/ship门禁中提高health阈值到当前值72,阻止进一步恶化(≤72的PR不能合入);(2)inventory-service:分配1个sprint(2周)做“深度重构”——专门清理Dead Code+拆分高圈复杂度函数,目标从57提升到65+;(3)web-frontend:保持当前节奏,不做干预。- 重构后效果(Week 12):inventory-service重构2周后重新体检——Dead Code 19→3(-84%),圈复杂度平均27→15(-44%),health从57→70(+13分)。api-gateway止跌回升到74(门禁阻止了3个低质量PR合入)。web-frontend继续上升到80。总项目Health Score从73.75提升到78.5。
🔑 启示:代码健康体检的价值不在“一次性的得分”——而在持续追踪产生的趋势曲线。inventory-service从62降到57的过程如果只看单次得分(“57分需要改善”)不足以推动重构,但当CTO看到“它连续8周每周降1分”的趋势时,就知道不干预的话2个月后会跌破50——趋势比绝对值更有说服力。
[!info] 参考来源 代码质量仪表盘的设计理念参考了 SonarQube Quality Gates 的质量门禁模式和 Google Engineering Practices 的代码健康指南。
§11 掌握检验
Q1:health 评分中,Tests 权重最高(28%)的根本原因是什么?
- A) 测试覆盖率是最容易量化的指标
- B) 测试是唯一能验证"代码行为正确性"的工具——类型检查和 Lint 只能验证"写得规整"
- C) 大多数项目都有大量测试
- D) 测试运行速度最快
Q2:GBrain 中,"过时的注释"为什么比"没有注释"扣更多分?
- A) 过时的注释更难发现
- B) 错误的注释比没有注释更危险——没有注释你只是不知道,错误注释会误导你
- C) 过时注释表明团队成员不沟通
- D) 这只是 GBrain 随机分配的权重
Q3:三大量化评分体系(/health、/qa、/review)中,"health 高 + qa 低"的场景意味着什么?请进行工程诊断并给出优先级排序的修复建议。
Q4:"GBrain 持续下降但其他所有指标都在上升"被描述为"在修症状但不管病因"。请用具体的项目场景解释这个隐喻——团队在做什么导致其他指标上升,却忽略了什么导致 GBrain 下降?
Q5:health 的趋势追踪不是一次性的——它需要跨时间积累。假设你是新接手项目的 Tech Lead,发现项目 CLAUDE.md 中 ## Health Trends 记录了最近 8 周的 history。数据健康评分持续从 82(GOOD)降到 68(NEEDS WORK)。你周一会做的第一、第二、第三件事分别是什么?请基于评分带的工程含义给出行动计划。
Q6:在电商案例中,inventory-service 重构后 health 从 62 升到 70。但如果团队只清理了 Dead Code(从 13 处降到 3 处)但圈复杂度从 15 升到了 18(为了减少代码行数而过度拆分函数),GBrain 评分可能下降。这个场景暴露了 health 评分的什么局限?单看总分的上升(62 → 70)会隐藏什么危险信号?
§12 答案
点击查看答案
Q1:B —— 类型检查和 Lint 可以告诉你代码"书写质量",但只有测试能告诉你代码"逻辑是否正确"。一个通过了所有类型检查的函数仍然可能把"加"写成"减"——只有测试能验证行为。
Q2:B —— 过时注释的本质是"对代码库的撒谎"。没有注释你只是不知道函数的意图(你会谨慎对待),过时注释让你相信一个错误的意图(你会基于错误假设做修改)。这就是为什么 GBrain 对有 year-old 注释且与代码不一致的情况扣分更重。
Q3:health 高说明代码结构好(类型全、lint 干净、无死代码),qa 低说明测试通过率低——好的代码结构但坏的逻辑错误。工程诊断:代码写得规范但存在运行时行为 bug(可能是边界条件处理错误、算法逻辑错误、或 API 返回值假设错误)。修复优先级:①先修复 qa 发现的行为错误(因为用户正在被这些 bug 影响——这是燃眉之急);②然后继续保持 health 评分(结构好意味着修 bug 时不容易引入新问题——结构好的代码更容易定位和修复逻辑错误)。
Q4:团队在持续做"表面的代码清洁":修 Lint 警告(Lint 评分 ↑)、加类型注解(Typecheck 评分 ↑)、删除死代码(Dead Code 评分 ↑)——这些都是"看得见的干净"。但同时,为了实现新功能急速扩展,模块间依赖越来越深(Coupling 上升 → GBrain 下降),函数为了减少代码行数被过度拆分到无法理解(圈复杂度隐藏但认知复杂度上升),为了修 bug 引入了一些不安全的默认配置(Security Smells 上升)。这些深层架构问题需要重构才能解决,但团队选择了"更容易的"表面修复——这就是"治标不治本"。
Q5:第一步——立即制止继续下降:下次 /ship 中将健康门禁阈值临时提高到当前值 68,阻止所有可能进一步降低评分的合入(止血)。第二步——分析 8 周的评分明细趋势,识别是哪个维度在驱动下降(是 Tests 覆盖率持续降低?还是 GBrain 架构质量恶化?还是 Dead Code 暴增?)。第三步——根据诊断结果制定偿还计划:如果 Tests 在降 → 未来 2 周不做新功能只补测试;如果 GBrain 在降 → 规划一次聚焦架构重构的 sprint;如果是全维度均匀下降 → 可能是团队在赶进度时集体"跳过质量",需要流程层面的干预(如在 CI 中强制 health 检查)而非纯技术修复。
Q6:health 总分的局限:它是一个加权平均,可能掩盖子维度的恶化。库存模块的 Dead Code 清理(从 13 处到 3 处 = +10 分)可能掩盖了圈复杂度的上升(从 15 到 18 = GBrain -1 分)。单看总分 → "太好了,升了 8 分!"但细看 GBrain → "架构复杂度在恶化"。危险信号:如果团队不断通过清理 Dead Code 来"刷分",而忽视了架构复杂度的增长,长期来看 health 会到达一个"Dead Code 已经清不动的天花板"——届时 GBrain 的低分会成为唯一的瓶颈,而那时的架构债务已经积重难返。解决方案:health 展示总分的同时,必须展示 GBrain 的趋势线——如果 GBrain 下降,即使总分上升也要标注警告。
(4/5 通过)
延伸阅读
- 下一步:[[L6-25-发布上线管理|发布上线管理]] —— health 评分是 /ship 合入门禁的核心输入之一
- [[L6-23-性能基准测试|性能基准测试]] —— 代码结构的健康不等于运行时性能的健康
- [[L6-20-自动化测试修复|自动化测试+自动修复]] —— Tests 占了 28% 权重,/qa 帮你维护这个最高权重项
- [[L6-36-项目复盘大师|项目复盘大师]] —— retro 从 health 的历史数据中提取趋势洞察

评论区
共 0 条评论