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

363 lines
7.4 KiB
Markdown

---
id: quality-tech-debt
title: Tech Debt — 측정 / 우선순위 / 갚기
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [quality, tech-debt, refactoring, vibe-coding]
tech_stack: { language: "Process", applicable_to: ["Engineering"] }
applied_in: []
aliases: [tech debt, technical debt, refactoring budget, code quality, debt register]
---
# Tech Debt
> 모든 코드는 debt. **의도적 vs 우발적** 구분 + 측정 + 정기 상환. "20% time" / "Friday refactor" / "debt sprint" 같은 budget.
## 📖 핵심 개념
- 의도적 debt: 알고 빠른 해결. (deadline)
- 우발적 debt: 무지 / 변경된 요구.
- Bit rot: 시간 경과로 stale.
- Compound interest: 안 갚으면 더 비싸짐.
## 💻 코드 패턴
### Debt 종류
```
Code: 복잡, 중복, naming
Architecture: monolith → microservice 마이그
Documentation: stale, missing
Test: coverage 낮음, brittle
Dependency: 옛 version, EOL library
Infrastructure: legacy server, manual deploy
Knowledge: 1명만 아는 system, bus factor
Process: manual deploy, no monitoring
```
### Debt register
```yaml
# debt-register.yml (git 안 living doc)
- id: TECH-001
title: Migrate from Express to Hono
category: dependency
severity: medium
estimated-effort: 5d
blocking: [v2-rewrite]
owner: backend-team
created: 2025-08-01
- id: TECH-002
title: Add types to legacy /admin module
category: code
severity: low
estimated-effort: 2d
owner: alice
created: 2025-12-01
```
→ 매 sprint 검토 + 우선순위.
### TODO comment 정리
```ts
// ❌ 정보 없음
// TODO: fix this
// ✅ 명시
// TODO(alice, 2026-06-01): Replace with new auth system #ISSUE-123
// Current: legacy basic auth, no MFA
// Needed: OAuth + 2FA before EOL of legacy backend
```
```bash
# CI lint
grep -rn 'TODO\|FIXME\|XXX' src/ | wc -l
# 또는 leasot tool
npx leasot src/
```
→ TODO 추적 + 만료 검사.
### Deprecation
```ts
/**
* @deprecated Use `newApi.fetch()` instead. Remove after 2026-06-01.
*/
function oldApi() { ... }
```
```ts
// runtime
function oldApi() {
console.warn('oldApi deprecated, use newApi');
return newApi();
}
```
```bash
# CI fail if deprecated 사용 (after sunset)
// .eslintrc — no-deprecated rule
```
### 측정 — code metrics
```bash
# Complexity
npx complexity-report-html src/
# Duplication
npx jscpd src/
# Test coverage
yarn test --coverage
# Bundle size (위 [[Perf_Bundle_Analysis]])
yarn size
# Type coverage
npx type-coverage --strict
```
### Architecture metrics
```bash
# Dependency cruiser
depcruise src --output-type err
# Madge — circular deps
madge --circular src/
# Cycles, depth, fan-in/out
```
### CodeScene / SonarQube / Codacy
```
- Hot spots: 자주 변경 + 복잡 = high risk.
- "Knowledge silo": 한 명만 변경.
- Trends: getting better / worse?
```
→ 자동 / dashboard.
### Refactoring 우선순위
```
High impact + High risk:
→ 적극 refactor
High impact + Low risk:
→ 작은 PR continuous
Low impact + High risk:
→ Leave alone (or document)
Low impact + Low risk:
→ Ignore
```
### Boy Scout Rule
```
"Always leave the code cleaner than you found it."
매 PR 가 작은 cleanup:
- Variable rename
- 작은 extract function
- Test 추가
- TODO 처리
```
→ 큰 refactor 없이 점진 향상.
### Refactor budget
```
20% rule: 매 sprint 의 20% = debt / refactor.
또는: 매 5 PR 중 1 PR = pure refactor.
또는: 분기마다 1 week debt sprint.
→ 안 잡으면 영원 미룸.
```
### Tech debt sprint
```
매 분기 1주일 = 모든 dev 가 debt 갚기.
Top 10 debt items 선택 → solve.
→ 단순 / focus.
```
### "Make it work, make it right, make it fast"
```
Phase 1: Working code (fast iteration)
Phase 2: Refactor for quality
Phase 3: Optimize bottlenecks
→ 1 phase 만 하면 debt. Phase 2 가 핵심.
```
### Debt 가 아닌 것
```
- 다른 디자인 선호 (의견)
- "예전 방식"
- 새 lib 안 사용
- Style 차이 (lint 가 처리)
→ Debt = 명확 cost (slow, bug, friction).
```
### Communicate debt to stakeholders
```
PM / Manager 에게:
- Cost: "이 debt 가 매 feature 의 30% 시간 추가"
- Risk: "EOL 의존 — 보안 patch 안 옴"
- ROI: "1 week refactor = 매 sprint 2 day 절감"
→ 비즈니스 언어.
```
### Debt vs new feature trade
```
"Refactor or new feature?"
매 sprint:
- 60-70% new feature
- 20-30% debt
- 5-10% buffer / unknowns
→ 100% feature = debt 폭발.
```
### Common debts to address
```
1. 옛 dependencies (EOL → security risk)
2. No tests (regression risk)
3. Manual deploy / runbook
4. Single point of failure (bus factor 1)
5. Performance hotspot
6. UI / a11y 옛 standard
7. DB schema (FK 없음, index 없음)
```
### Quick wins
```
- Add prettier / eslint
- Add CI test gate
- TypeScript adoption (점진)
- Test for high-traffic endpoints
- Bundle analyzer
- Dependency update batch (Dependabot)
→ 작은 effort + 큰 gain.
```
### Big projects
```
- Monolith → microservice (몇 분기)
- DB migration (Postgres major)
- Framework upgrade (React 17 → 19)
- 옛 codebase 재작성
- Cloud migration
→ Roadmap + milestone.
```
### Strangler fig pattern
```
Big rewrite 대신:
1. 새 system + old system 동시 운영
2. 점진적으로 traffic 이동
3. 옛 system 점차 사라짐
→ Risk ↓.
```
### Recognize sunk cost
```
"이미 X 시간 투자했으니 계속" = sunk cost fallacy.
Decision = future cost only.
```
### Avoid premature abstraction
```
Rule of three: 3번 반복 = abstract.
1-2번 = 그대로.
→ Wrong abstraction = debt.
```
### Yagni (You Aren't Gonna Need It)
```
"미래에 필요할 것 같아" = often not needed.
Build for current requirement.
Refactor when needed.
```
### Document the why
```
Debt 갚을 때:
"왜 이렇게 했었는지" 옛 author 에게 물어봄.
이유 있을 수도.
→ 무지 X — 의도 이해 후 변경.
```
### Test before refactor
```
1. 현재 behavior 가 무엇인지 test
2. Refactor
3. Test 통과 = 같은 behavior
→ Test 없는 코드 = 옛 안 알 수 없음. 작은 변경 위험.
```
### Mikado method
```
큰 변경 = 작은 가능 step:
1. 목표 변경 시도 → fail.
2. Prerequisites 식별.
3. 각 prereq → 작은 step → repeat.
4. Tree 구조.
→ 큰 refactor 의 단계 명확.
```
### Refactor anti-patterns
```
- 한 PR 가 1000+ line 변경
- 모든 거 한 번에
- 작동하는 거 망가뜨림
- Test 없는 refactor
- 본질 안 보고 Style 만
- 다른 더 큰 issue 무시
```
## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| Debt 많음 + 새 feature 우선 | 20% time + boy scout |
| 큰 architectural debt | 분기마다 milestone |
| Library EOL | 즉시 plan |
| 코드 hot spot | 작은 PR 자주 |
| Bus factor 1 | Pair / docs / share |
| Test 없는 critical | Test first |
## ❌ 안티패턴
- **Big rewrite (모든 거 다시)**: 보통 실패.
- **Debt 무측정**: 안 보임.
- **모든 거 debt 라고 lab**: 의미 없음 — focus.
- **새 feature 가 항상 우선**: debt 폭발.
- **Dev 가 boss 에게 communicate X**: budget 못 받음.
- **Refactor 하면서 feature 추가**: 둘 다 망침.
- **Test 없는 refactor**: behavior 변경 모름.
## 🤖 LLM 활용 힌트
- Debt register + 정기 review.
- 20% time 또는 분기 sprint.
- Boy scout rule 매 PR.
- Strangler fig 대규모.
## 🔗 관련 문서
- [[Quality_Refactoring]]
- [[Productivity_Code_Review]]
- [[Productivity_Documentation]]