9148c358d0
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
5.4 KiB
5.4 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-legacy-modernization | Legacy Modernization | 10_Wiki/Topics | verified | self |
|
none | A | 0.9 | applied |
|
2026-05-10 | pending |
|
Legacy Modernization
매 한 줄
"매 big-bang 은 죽는다". Strangler fig 로 incremental 하게 둘러싸고 잘라낸다, parallel run 으로 검증.
매 핵심
매 5 pattern
- Strangler Fig (Fowler): 신규 시스템이 점진적으로 legacy 를 둘러싸고 대체. 가장 안전
- Branch by Abstraction: 인터페이스 추출 → 두 구현 공존 → 신구 전환 → 구 제거
- Parallel Run: 신구 동시 실행, 결과 비교, 신뢰 쌓이면 cutover
- Rewrite vs Refactor: 비즈니스 로직 명확하면 refactor, 아키 자체가 문제면 rewrite
- Anti-corruption Layer (DDD): legacy 모델이 신규에 새지 않도록 adapter
매 응용
- Monolith → microservice 분해
- On-prem → cloud
- Legacy DB schema 점진적 마이그레이션
- COBOL → Java/Go
- SOAP → REST/gRPC
💻 패턴
Pattern 1: Strangler Fig with reverse proxy
# nginx routes traffic: new endpoints → new svc, rest → legacy
location /api/v2/users { proxy_pass http://new-service; }
location /api/v2/orders { proxy_pass http://new-service; }
location / { proxy_pass http://legacy-monolith; }
# 매주 endpoint 추가 → legacy 점점 축소
Pattern 2: Branch by Abstraction
# 1. 추출
class PaymentGateway(Protocol):
def charge(self, amount: int) -> str: ...
class LegacyPayment(PaymentGateway): ... # 기존
class NewPayment(PaymentGateway): ... # 신규
# 2. Feature flag 로 전환
def get_payment() -> PaymentGateway:
return NewPayment() if flag.enabled("new_payment") else LegacyPayment()
Pattern 3: Parallel run with shadow traffic
def process_order(order):
legacy_result = legacy.process(order)
try:
new_result = new.process(order)
if new_result != legacy_result:
log_diff(order, legacy_result, new_result)
except Exception as e:
log_error(e)
return legacy_result # 아직 legacy 가 truth
Pattern 4: Anti-corruption Layer
# Legacy 의 이상한 model 을 새 domain 으로 변환
class LegacyCustomerAdapter:
def to_domain(self, row: dict) -> Customer:
# legacy: cust_nm, cust_dt_birth, cust_flg_act
return Customer(
name=row["cust_nm"],
birthday=parse_legacy_date(row["cust_dt_birth"]),
active=row["cust_flg_act"] == "Y",
)
Pattern 5: Database expand-contract
-- Phase 1 expand: 새 컬럼 추가, 양쪽 쓰기
ALTER TABLE users ADD COLUMN email_v2 VARCHAR(255);
-- App: write to both email AND email_v2
-- Phase 2 backfill: 기존 데이터 복사
UPDATE users SET email_v2 = LOWER(TRIM(email)) WHERE email_v2 IS NULL;
-- Phase 3 contract: 신규 read, 구 제거
-- App: read from email_v2 only
ALTER TABLE users DROP COLUMN email;
ALTER TABLE users RENAME COLUMN email_v2 TO email;
Pattern 6: Characterization tests before refactor
# Legacy 동작을 "있는 그대로" 고정 — golden master
def test_legacy_behavior():
for input_case in load_production_samples():
actual = legacy.process(input_case)
assert actual == load_golden(input_case.id)
# Refactor 후에도 통과해야 함
Pattern 7: Event interception (Strangler 변형)
# Legacy 가 발행하는 event 를 새 서비스가 구독
@on_event("OrderCreated")
def new_handler(event):
new_service.create_order(event.payload)
# Legacy 는 그대로, 새 시스템이 옆에서 동기화
매 결정 기준
| 상황 | Approach |
|---|---|
| 비즈니스 로직 명확, 코드 더러움 | Refactor (in place) |
| 아키 자체가 잘못 | Rewrite + Strangler Fig |
| Risk 매우 높음 | Parallel run + shadow |
| DB schema 변경 | Expand-contract |
| Legacy 모델이 새 시스템 오염 | Anti-corruption Layer |
| Big bang 유혹 | 거의 항상 X |
기본값: Strangler Fig + Branch by Abstraction + Characterization tests.
🔗 Graph
- 부모: Software_Architecture, Refactoring_Best_Practices
- 변형: Strangler_Fig, Branch_by_Abstraction
- 응용: Microservices
- Adjacent: Domain_Driven_Design, Feature Flags
🤖 LLM 활용
언제: legacy 코드 의도 파악, characterization test 생성, COBOL → Java 변환 후 검증. 언제 X: 결정론적 schema migration (sqitch/flyway), 비즈니스 룰 단독 추출 (사람 검증 필수).
❌ 안티패턴
- Big bang rewrite ("2년만 주세요") → 프로젝트 사망
- Test 없이 refactor → 회귀 무한
- Strangler 시작했는데 끝까지 안 감 → 이중 유지보수 영원
- DB schema 한번에 변경 → 롤백 불가
- 비즈니스 사용자 무시 → 신규 기능 deliver 정지
🧪 검증 / 중복
- Verified (Fowler StranglerFigApplication, Feathers WELC, Evans DDD ACL). 신뢰도 A.
Legacy-Systems.md가 본 문서 redirect.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — canonical, 5 pattern + 7 code recipe |