[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -0,0 +1,417 @@
|
||||
---
|
||||
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]]
|
||||
Reference in New Issue
Block a user