如何衡量前端代码质量
问题
你怎么衡量一个前端项目的代码质量?有哪些指标?
回答思路
1. 代码质量的维度
2. 可量化的指标
| 指标 | 工具 | 推荐阈值 | 说明 |
|---|---|---|---|
| 测试覆盖率 | Vitest / Jest | ≥ 70%(核心逻辑 ≥ 90%) | 衡量测试充分度 |
| 类型覆盖率 | TypeScript | strict mode 100% | 衡量类型安全 |
| Lint 通过率 | ESLint | 0 error | 代码规范遵守程度 |
| 包体积 | bundle-analyzer | 首屏 JS < 200KB | 性能相关 |
| 圈复杂度 | ESLint rule | 函数 < 10 | 代码复杂度 |
| 重复代码率 | jscpd | < 5% | 代码复用程度 |
| 依赖安全 | npm audit | 0 high/critical | 依赖安全 |
| Core Web Vitals | Lighthouse | LCP < 2.5s, CLS < 0.1 | 用户体验 |
3. 高质量代码 vs 低质量代码
❌ 低质量代码
// 1. 命名不清晰
const d = new Date();
const fn = (a: any, b: any) => a + b;
// 2. 过长函数(做了太多事情)
function handleSubmit(formData) {
// 50 行校验逻辑...
// 30 行数据转换...
// 20 行 API 调用...
// 10 行错误处理...
// 总共 110 行
}
// 3. 硬编码
if (user.role === 1) { /* admin */ }
if (status === 'XFHJ2K') { /* ??? */ }
// 4. 没有错误处理
const data = JSON.parse(input);
const value = obj.a.b.c.d;
✅ 高质量代码
// 1. 命名清晰,自解释
const createdAt = new Date();
const calculateTotal = (price: number, quantity: number): number => price * quantity;
// 2. 职责单一,函数简短
function handleSubmit(formData: FormData): void {
const validationResult = validateForm(formData);
if (!validationResult.isValid) {
showErrors(validationResult.errors);
return;
}
const payload = transformFormData(formData);
submitToServer(payload);
}
// 3. 使用常量和枚举
const enum UserRole {
Admin = 1,
Editor = 2,
Viewer = 3,
}
if (user.role === UserRole.Admin) { /* ... */ }
// 4. 完善的错误处理
const data = safeJsonParse<UserData>(input, defaultValue);
const value = obj?.a?.b?.c?.d ?? fallbackValue;
4. 建立质量度量体系
集成到 CI 流水线
.github/workflows/quality.yml
name: Code Quality
on: [pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Lint 检查
- run: pnpm lint
# 类型检查
- run: pnpm tsc --noEmit
# 单元测试 + 覆盖率
- run: pnpm test --coverage
# 覆盖率门禁
- uses: codecov/codecov-action@v3
with:
fail_ci_if_error: true
# 包体积检查
- run: pnpm build
- uses: andresz1/size-limit-action@v1
5. 代码质量改进策略
| 阶段 | 策略 | 工具 |
|---|---|---|
| 编码时 | ESLint 实时提示 + TypeScript 类型检查 | IDE 插件 |
| 提交前 | lint-staged + husky 拦截 | pre-commit hooks |
| CR 时 | 人工 Review + AI 辅助 | GitHub PR + CodeRabbit |
| CI 时 | 自动化测试 + 覆盖率门禁 + 体积检查 | GitHub Actions |
| 上线后 | 错误监控 + 性能监控 | Sentry + Web Vitals |
常见面试问题
Q1: 代码质量和开发速度如何平衡?
答案:
短期看是矛盾的,长期看高质量代码反而更快:
- 短期:写测试、做 CR 会花更多时间
- 长期:高质量代码减少 Bug、减少维护成本、新功能开发更快
平衡策略:
- 自动化规范检查:让机器处理格式、简单 Bug,减少人工负担
- 按重要度分层:核心逻辑严格要求,边缘功能适当放宽
- 技术债定期偿还:不追求完美,但持续改进
- 团队共识:对"什么是可接受的质量"达成共识
Q2: 圈复杂度是什么?怎么降低?
答案:
圈复杂度(Cyclomatic Complexity)衡量代码中独立执行路径的数量。每多一个 if、for、case,复杂度 +1。
降低圈复杂度
// ❌ 复杂度高(多层嵌套 if)
function getDiscount(user: User): number {
if (user.isVip) {
if (user.level >= 3) {
if (user.years > 5) return 0.5;
return 0.7;
}
return 0.85;
}
return 1;
}
// ✅ 使用早返回 + 策略表降低复杂度
const discountRules: Array<{ match: (u: User) => boolean; discount: number }> = [
{ match: (u) => u.isVip && u.level >= 3 && u.years > 5, discount: 0.5 },
{ match: (u) => u.isVip && u.level >= 3, discount: 0.7 },
{ match: (u) => u.isVip, discount: 0.85 },
];
function getDiscount(user: User): number {
return discountRules.find((rule) => rule.match(user))?.discount ?? 1;
}
Q3: 你如何推动团队提升代码质量?
答案:
- 工具先行:配置 ESLint + Prettier + TypeScript strict,让工具自动保障基础质量
- 建立 CR 文化:制定 CR 规范,每个 PR 必须 Review
- 写好测试:Leader 带头写测试,核心逻辑必须有测试覆盖
- Code Quality Dashboard:可视化展示各项指标,定期 Review
- Knowledge Sharing:分享好的代码模式和反面案例
Q4: 测试覆盖率高就代表质量好吗?
答案:
不一定。测试覆盖率是必要条件,但不是充分条件:
- 100% 覆盖率 ≠ 没有 Bug:可能覆盖了行但没覆盖分支
- 有效的测试更重要:测试应该验证行为而非实现细节
- 关键路径优先:核心业务逻辑 90%+,工具函数 80%+,UI 组件关注行为
好测试 vs 坏测试
// ❌ 坏测试:测试实现细节
test('should call setState', () => {
const setState = vi.fn();
// 测试内部实现...
});
// ✅ 好测试:测试行为
test('should show error when input is invalid', () => {
render(<LoginForm />);
fireEvent.click(screen.getByRole('button', { name: 'Submit' }));
expect(screen.getByText('Email is required')).toBeInTheDocument();
});