8.8 KiB
8.8 KiB
代码质量检查
本文档详细说明如何使用 AI 分析代码质量问题。
📋 概述
代码质量检查是智能代码审查的核心维度之一,通过分析代码的复杂度、命名规范、注释完整性等指标,评估代码的可读性和可维护性。
🎯 检查维度
1. 代码复杂度
检查项:
- 圈复杂度(Cyclomatic Complexity): 衡量代码的独立路径数量
- 函数长度: 单个函数的代码行数
- 嵌套层级: 代码的嵌套深度
- 参数数量: 函数的参数个数
标准:
-
圈复杂度 < 10: 优秀 ✅
-
圈复杂度 10-20: 良好 ⚠️
-
圈复杂度 > 20: 需要重构 🔴
-
函数长度 < 50 行: 优秀 ✅
-
函数长度 50-100 行: 良好 ⚠️
-
函数长度 > 100 行: 需要拆分 🔴
-
嵌套层级 < 3: 优秀 ✅
-
嵌套层级 3-4: 良好 ⚠️
-
嵌套层级 > 4: 需要简化 🔴
示例代码:
// 🔴 高复杂度示例(需要重构)
func processData(input1, input2, input3, input4, input5 string) error {
if input1 != "" {
for i := 0; i < 100; i++ {
if input2 != "" {
switch input3 {
case "a":
if input4 != "" {
// 嵌套层级过深
}
case "b":
// ...
}
}
}
}
return nil
}
// ✅ 低复杂度示例(优秀)
func processData(input string) error {
if err := validateInput(input); err != nil {
return err
}
data, err := parseInput(input)
if err != nil {
return err
}
return saveData(data)
}
2. 命名规范
检查项:
- 变量命名: 是否使用清晰、描述性的名称
- 函数命名: 是否使用动词开头,描述函数功能
- 类命名: 是否使用名词,首字母大写
- 常量命名: 是否使用全大写+下划线
规则:
- ✅ 使用有意义的名称(
userAge而非x) - ✅ 遵循语言约定(Go: 驼峰命名,Python: 下划线命名)
- ❌ 避免单字母变量(除循环变量
i,j) - ❌ 避免缩写(
usr而非user)
示例:
// ❌ 不好的命名
const x = 10;
function calc(a, b) {
return a + b;
}
// ✅ 好的命名
const maxRetryCount = 10;
function calculateTotal(price, quantity) {
return price * quantity;
}
3. 注释完整性
检查项:
- 函数注释: 复杂函数是否有注释说明
- 代码逻辑: 复杂逻辑是否有解释
- TODO 标记: 是否有未完成的 TODO
规则:
- ✅ 公共 API 必须有注释
- ✅ 复杂算法必须有注释
- ✅ 非显而易见的逻辑必须有注释
- ❌ 避免注释显而易见的代码
示例:
// ❌ 不好的注释(显而易见)
// 设置用户名为 "admin"
username := "admin"
// ✅ 好的注释(解释复杂逻辑)
// 使用二次探测法解决哈希冲突
index := (hash + i * i) % tableSize
4. 代码格式
检查项:
- 缩进: 是否使用一致的缩进(2/4 空格或 Tab)
- 空行: 函数/类之间是否有适当的空行
- 行长度: 单行代码是否过长(建议 < 120 字符)
- 代码组织: 导入、常量、变量、函数的顺序
标准:
- 使用统一的代码格式化工具(gofmt、prettier)
- 函数之间空 1-2 行
- 逻辑块之间空 1 行
🔧 分析流程
开始分析代码质量
↓
1. 解析代码结构
├─ 识别函数、类、变量
└─ 提取代码块
↓
2. 计算复杂度指标
├─ 圈复杂度
├─ 函数长度
├─ 嵌套层级
└─ 参数数量
↓
3. 检查命名规范
├─ 变量命名
├─ 函数命名
└─ 类命名
↓
4. 评估注释完整性
├─ 函数注释
├─ 逻辑注释
└─ TODO 标记
↓
5. 生成质量报告
├─ 评分
├─ 问题列表
└─ 改进建议
↓
完成
📊 输出格式
JSON 格式
{
"quality_analysis": {
"overall_score": 85,
"complexity": {
"score": 90,
"metrics": {
"avg_cyclomatic_complexity": 3.5,
"max_cyclomatic_complexity": 8,
"avg_function_length": 25,
"max_function_length": 60,
"max_nesting_level": 3
},
"issues": [
{
"file": "src/auth/login.go",
"function": "authenticate",
"line": 45,
"severity": "MEDIUM",
"metric": "function_length",
"value": 60,
"threshold": 50,
"suggestion": "建议将此函数拆分为更小的函数"
}
]
},
"naming": {
"score": 95,
"issues": [
{
"file": "src/auth/user.go",
"line": 78,
"severity": "LOW",
"type": "variable",
"name": "x",
"suggestion": "建议使用更具描述性的名称,如 'retryCount'"
}
]
},
"comments": {
"score": 75,
"coverage": 60,
"missing_comments": [
{
"file": "src/auth/login.go",
"function": "validateToken",
"line": 120,
"suggestion": "建议添加函数注释说明验证逻辑"
}
]
},
"format": {
"score": 90,
"issues": [
{
"file": "src/auth/login.go",
"line": 45,
"type": "line_length",
"value": 150,
"threshold": 120,
"suggestion": "建议将长行拆分为多行"
}
]
}
}
}
Markdown 格式
## 代码质量分析: 85/100 ⭐⭐⭐⭐
### 复杂度: 90/100 ✅
- 平均圈复杂度: 3.5 ✅
- 最大圈复杂度: 8 ✅
- 平均函数长度: 25 行 ✅
- 最大函数长度: 60 行 ⚠️
- 最大嵌套层级: 3 ✅
#### ⚠️ 需要改进
1. **函数过长** - `src/auth/login.go:45`
- 函数 `authenticate` 长度为 60 行
- 建议:将此函数拆分为更小的函数
### 命名规范: 95/100 ✅
#### 💡 改进建议
1. **变量命名** - `src/auth/user.go:78`
- 变量 `x` 命名不够清晰
- 建议:使用更具描述性的名称,如 'retryCount'
### 注释完整性: 75/100 ⚠️
- 注释覆盖率: 60%
#### ❌ 缺少注释
1. **函数注释** - `src/auth/login.go:120`
- 函数 `validateToken` 缺少注释
- 建议:添加函数注释说明验证逻辑
### 代码格式: 90/100 ✅
#### 💡 改进建议
1. **行长度** - `src/auth/login.go:45`
- 行长度为 150 字符
- 建议:将长行拆分为多行
💡 最佳实践
1. 保持函数简短
// ✅ 好的实践
func handleRequest(req *Request) (*Response, error) {
if err := validateRequest(req); err != nil {
return nil, err
}
data, err := processRequest(req)
if err != nil {
return nil, err
}
return buildResponse(data), nil
}
// ❌ 不好的实践
func handleRequest(req *Request) (*Response, error) {
// 100+ 行代码
// 验证、处理、响应都在一个函数中
}
2. 使用清晰的命名
// ✅ 好的实践
const MAX_RETRY_ATTEMPTS = 3;
const API_TIMEOUT_MS = 5000;
function calculateDiscount(price, discountRate) {
return price * (1 - discountRate);
}
// ❌ 不好的实践
const max = 3;
const t = 5000;
function calc(p, d) {
return p * (1 - d);
}
3. 添加有意义的注释
# ✅ 好的注释
# 实现二分查找算法,时间复杂度 O(log n)
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
# ❌ 不好的注释
# 查找目标值
def binary_search(arr, target):
# ... 显而易见的代码 ...
🔍 常见问题
Q: 如何平衡代码质量和开发效率?
A:
- 对于核心业务逻辑,严格要求代码质量
- 对于一次性脚本,可以适当放宽标准
- 使用代码格式化工具自动处理格式问题
- 定期进行代码重构,而非过度追求完美
Q: 如何处理历史遗留的低质量代码?
A:
- 不要求立即重构所有历史代码
- 在修改相关代码时进行重构
- 优先重构最常用的核心模块
- 逐步改进,避免大规模重写
Q: 代码质量工具与 AI 审查如何配合?
A:
- 代码质量工具(lint、static analysis)处理规则性检查
- AI 审查处理语义性、上下文相关的检查
- 工具提供定量指标,AI 提供定性分析
- 结合使用,获得全面的代码质量评估
📚 相关文档
最后更新: 2026-06-12