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