Files
2nd/10_Wiki/Topics/Coding/Quality_Code_Metrics.md
T
2026-05-09 21:08:02 +09:00

418 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: quality-code-metrics
title: Code Metrics — Complexity / Coverage / Hot spots
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [quality, metrics, vibe-coding]
tech_stack: { language: "Various", applicable_to: ["Engineering"] }
applied_in: []
aliases: [code metrics, cyclomatic complexity, test coverage, code churn, hot spot, SonarQube]
---
# Code Metrics
> "측정 안 한 거 = 개선 X". **Complexity, coverage, churn, hot spots**. Metrics = signal X target. Goodhart's law 주의.
## 📖 핵심 개념
- Complexity: cyclomatic, cognitive.
- Coverage: line / branch / function.
- Churn: 자주 변경 file.
- Hot spot: complexity × churn = risk.
## 💻 코드 패턴
### Cyclomatic complexity
```
함수 안 decision point + 1.
if / for / while / case / && / || / ternary 마다 +1.
10 미만: OK
10-20: review 필요
20+: split
```
```ts
// CC = 1
function add(a: number, b: number) { return a + b; }
// CC = 4 (3 if + 1 base)
function classify(n: number) {
if (n < 0) return 'negative';
if (n === 0) return 'zero';
if (n < 10) return 'small';
return 'large';
}
```
### Cognitive complexity (modern)
```
Nesting 도 카운트.
Sequential 보다 nested 가 비싸.
CC = 같음 but cognitive 다름:
function flat() {
if (a) ...;
if (b) ...;
if (c) ...;
// cognitive ≈ 3
}
function nested() {
if (a) {
if (b) {
if (c) ...;
}
}
// cognitive ≈ 6 (nesting penalty)
}
```
→ SonarQube 측정.
### 측정 도구
```bash
# JS / TS
npx complexity-report-html src/
# 또는 ESLint
{
"rules": {
"complexity": ["warn", 10],
"max-depth": ["warn", 4],
"max-lines-per-function": ["warn", 50]
}
}
```
```bash
# Code Climate (managed)
# SonarQube / SonarCloud
# CodeScene
```
### Test coverage
```bash
yarn test --coverage
# 결과
# Lines: 87.3%
# Branches: 76.5%
# Functions: 92.1%
# Statements: 87.0%
```
```js
// jest.config.js
coverageThreshold: {
global: { lines: 80, branches: 70, functions: 80 },
'./src/payment/': { lines: 95, branches: 90 }, // critical
}
```
→ Critical 만 high. 모든 곳 100% 무의미.
### Coverage 함정
```
100% line = bug 없음 X.
- Test 가 assertion 약함
- Edge case 못 잡음
- Logic 정확성 검증 X
→ Coverage = signal. Mutation testing 가 진짜.
```
### Code churn
```bash
# 자주 변경 file (last 6 months)
git log --since="6 months ago" --pretty=format: --name-only | sort | uniq -c | sort -rn | head -20
# 또는 CodeScene / Codacy
```
→ 자주 변경 = bug 가능.
### Hot spot (complexity × churn)
```
High complexity + High churn = HIGH RISK.
→ Refactor priority.
Low complexity + Low churn = stable.
High complexity + Low churn = legacy (안 변경하면 OK).
Low complexity + High churn = OK 자주 변경.
```
### Churn 자주 변경 file 의 의미
```
1. Bug magnet — 같은 곳 자주 fix.
2. 디자인 잘못 — 자주 reorganize.
3. 활발 — 단순 active feature.
→ 추가 분석 필요.
```
### Bus factor
```bash
# Each file 의 contributor 수
git log --pretty=format:"%an" -- file.ts | sort -u | wc -l
# 1 = bus factor 1 (위험)
```
→ 1 명만 = pair / share.
### File / function size
```
Function > 50 lines: split
File > 500 lines: split / module
Class > 1000 lines: God class — split
```
→ 정확 cutoff 보다 trend.
### Type coverage (TS)
```bash
npx type-coverage --strict --at-least 95
# 95% 미만 = fail
```
`any` 사용 % 측정.
### Dependency metrics
```bash
# Cycles
madge --circular src/
# Depth
npx dependency-cruiser src/ --output-type metrics
# Fan-in / fan-out
```
### Build time
```
Slow build = 자주 안 build = bug 자주.
목표:
- Local dev: instant (HMR)
- CI test: < 10 min
- Production build: < 5 min
측정 + alarm if 늘어남.
```
### CI 안 metric
```yaml
- name: Test coverage
run: yarn test --coverage --coverageReporters=text-summary
- name: Complexity
run: npx eslint --rule 'complexity: [error, 15]' src/
- name: Type coverage
run: npx type-coverage --at-least 95
- name: Bundle size
run: yarn size
- name: Lint
run: yarn lint --max-warnings 0
```
### Dashboard (long-term trend)
```
Grafana / Datadog / SonarQube:
- 매 commit / day metrics
- Trend graph
- Per-team / per-module
→ "지난 분기 보다 좋아짐?"
```
### Goodhart's law
```
"When a measure becomes a target, it ceases to be a good measure."
목표 = 100% coverage:
→ 사람 가 의미 없는 test 추가.
→ Coverage 100% but quality X.
→ Metric = signal. Target 가 아닌 signal.
```
### Healthy ranges
```
Cyclomatic: < 10 (most), 15 max.
Cognitive: < 15.
Function lines: < 50.
File lines: < 500.
Coverage: 70-90% (critical 95%).
Type coverage: 95%+ (TS strict).
Cycles: 0.
```
→ 정확 number 보다 trend.
### Code review metric
```
- PR cycle time (open → merge)
- PR size (median lines)
- Time to first review
- Number of review iterations
목표:
- Cycle time: < 1 day
- Median size: < 200 lines
- First review: < 4 hours
- Iterations: 1-2
```
→ 개선 = 빠른 ship + 적은 bug.
### DORA metrics
```
1. Deploy frequency
2. Lead time (commit → prod)
3. MTTR (mean time to recover)
4. Change failure rate
Elite:
- Deploy: multiple per day
- Lead time: < 1 hour
- MTTR: < 1 hour
- Failure: < 15%
```
→ Industry benchmark.
### Technical excellence checklist (자체)
```
- [ ] 80%+ test coverage
- [ ] Type strict
- [ ] Lint clean
- [ ] CI < 10 min
- [ ] PR cycle < 1 day
- [ ] Documentation 80%+
- [ ] On-call < 3 page / week
- [ ] Deploy frequency 1/day+
```
### 자체 metrics (domain-specific)
```
- API endpoint test count
- Schema validation coverage
- Error rate per endpoint
- Latency p99 per endpoint
- Cache hit rate
- DB query count
```
### Metric review meeting
```
Monthly / quarterly:
- 어떤 metric 가 worsened?
- 어떤 module 가 risky?
- 어떤 action?
→ Action items.
```
### Per-team vs whole-codebase
```
Per-team metrics: ownership, accountability.
Whole-codebase: 전체 health.
→ 둘 다.
```
### Anti-metric (bad measures)
```
- LOC (lines of code) — 더 많이 = 더 좋음 X
- PR count — 큰 PR vs 많은 작은 PR
- Hours worked — quality X quantity
- Code review comments — 많이 = 좋음? maybe noise
→ 의미 없는 measure.
```
### Senior 의 metric
```
Junior:
- Output (LOC, PRs)
Senior:
- Quality (review feedback)
- Mentoring (others' growth)
- System health
- Tech debt 줄임
- Cross-team impact
```
→ Senior 가 LOC 측정 = 잘못된 incentive.
### Manager dashboard
```
- Team velocity
- Cycle time
- Defect rate
- On-call load
- Burnout signals (work hours, vacation usage)
- Engagement survey
→ Indicators of team health.
```
### Tools
```
SonarQube / SonarCloud — full code quality
CodeScene — hot spot, knowledge map
Codacy — automated review
Code Climate — quality grade
Codecov — coverage trend
LinearB / Jellyfish — DORA + dev productivity
```
### "측정만 하지 말고 act"
```
Metrics 보기 → action items → 다음 달 비교.
매 quarter:
- Top 3 metrics 가 worsened?
- 액션 plan
- Accountability
```
## 🤔 의사결정 기준
| 측정 | 자주 |
|---|---|
| Complexity | PR (CI lint) |
| Coverage | PR + dashboard |
| Churn | Monthly |
| Hot spot | Quarterly |
| DORA | Monthly (team) |
| Bus factor | Quarterly |
## ❌ 안티패턴
- **Coverage target = 100%**: useless test.
- **Metric 가 target**: gaming.
- **Single metric judge**: 한 면만.
- **No context**: number 만 — meaning 없음.
- **개인 별 LOC**: bad incentive.
- **측정 + no action**: dashboard 의미 없음.
- **모든 코드 같은 standard**: critical 가 다름.
## 🤖 LLM 활용 힌트
- Complexity + coverage + churn = baseline.
- Hot spot = complexity × churn.
- DORA metrics 가 큰 picture.
- Goodhart — 신호 X target.
## 🔗 관련 문서
- [[Quality_Tech_Debt]]
- [[Quality_Refactoring]]
- [[Testing_Mutation_Testing]]