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

7.4 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
quality-tech-debt Tech Debt — 측정 / 우선순위 / 갚기 Coding draft B conceptual 2026-05-09 2026-05-09
quality
tech-debt
refactoring
vibe-coding
language applicable_to
Process
Engineering
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

# 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 정리

// ❌ 정보 없음
// 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
# CI lint
grep -rn 'TODO\|FIXME\|XXX' src/ | wc -l
# 또는 leasot tool
npx leasot src/

→ TODO 추적 + 만료 검사.

Deprecation

/**
 * @deprecated Use `newApi.fetch()` instead. Remove after 2026-06-01.
 */
function oldApi() { ... }
// runtime
function oldApi() {
  console.warn('oldApi deprecated, use newApi');
  return newApi();
}
# CI fail if deprecated 사용 (after sunset)
// .eslintrc — no-deprecated rule

측정 — code metrics

# 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

# 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 대규모.

🔗 관련 문서