"매 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_passhttp://new-service;}location/api/v2/orders{proxy_passhttp://new-service;}location/{proxy_passhttp://legacy-monolith;}# 매주 endpoint 추가 → legacy 점점 축소
Pattern 2: Branch by Abstraction
# 1. 추출classPaymentGateway(Protocol):defcharge(self,amount:int)->str:...classLegacyPayment(PaymentGateway):...# 기존classNewPayment(PaymentGateway):...# 신규# 2. Feature flag 로 전환defget_payment()->PaymentGateway:returnNewPayment()ifflag.enabled("new_payment")elseLegacyPayment()
Pattern 3: Parallel run with shadow traffic
defprocess_order(order):legacy_result=legacy.process(order)try:new_result=new.process(order)ifnew_result!=legacy_result:log_diff(order,legacy_result,new_result)exceptExceptionase:log_error(e)returnlegacy_result# 아직 legacy 가 truth
Pattern 4: Anti-corruption Layer
# Legacy 의 이상한 model 을 새 domain 으로 변환classLegacyCustomerAdapter:defto_domain(self,row:dict)->Customer:# legacy: cust_nm, cust_dt_birth, cust_flg_actreturnCustomer(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: 새 컬럼 추가, 양쪽 쓰기
ALTERTABLEusersADDCOLUMNemail_v2VARCHAR(255);-- App: write to both email AND email_v2
-- Phase 2 backfill: 기존 데이터 복사
UPDATEusersSETemail_v2=LOWER(TRIM(email))WHEREemail_v2ISNULL;-- Phase 3 contract: 신규 read, 구 제거
-- App: read from email_v2 only
ALTERTABLEusersDROPCOLUMNemail;ALTERTABLEusersRENAMECOLUMNemail_v2TOemail;
Pattern 6: Characterization tests before refactor
# Legacy 동작을 "있는 그대로" 고정 — golden masterdeftest_legacy_behavior():forinput_caseinload_production_samples():actual=legacy.process(input_case)assertactual==load_golden(input_case.id)# Refactor 후에도 통과해야 함
Pattern 7: Event interception (Strangler 변형)
# Legacy 가 발행하는 event 를 새 서비스가 구독@on_event("OrderCreated")defnew_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.