Angular 1에서 React로 — Strangler 패턴으로 1년간 점진적 마이그레이션한 이야기

11 min read
ReactAngularMigrationStrangler Pattern리팩토링
Angular 1에서 React로 — Strangler 패턴으로 1년간 점진적 마이그레이션한 이야기

왜 마이그레이션이 필요했나

원래 개발자가 떠나고, 남은 팀은 Angular 1 코드베이스에 대한 자신감이 낮았다. 버그를 고치면 다른 곳이 깨지고, 새 기능을 넣으려면 기존 구조를 이해하는 데 시간이 더 걸리는 상황이었다. 거기에 Angular 1은 **공식 지원 종료(EOL)**가 예고된 상태였다.

핵심: 마이그레이션은 "새 기술이 좋아서"가 아니라, 기존 코드에 대한 신뢰가 바닥이라 시작됐다.

비유하면 이렇다. 낡은 건물에서 영업 중인 식당을 리모델링해야 하는데, 문을 닫을 수는 없다. 그래서 한쪽 벽부터 하나씩 바꿔나가는 방식을 택한 거다. 이것이 바로 Strangler 패턴이다.

[💡 잠깐! 이 용어는?] Strangler 패턴(Strangler Fig Pattern): 레거시 시스템을 새 시스템으로 교체할 때, 한 번에 전부 바꾸지 않고 점진적으로 감싸면서 교체하는 방법. 교살 무화과나무가 숙주 나무를 서서히 감싸는 모습에서 이름을 따왔다.


Strangler 패턴의 실전 적용

Angular와 React를 동시에 돌린다

Jack Franklin의 팀은 ngReact 라이브러리를 사용해서 Angular 앱 안에 React 컴포넌트를 렌더링하는 방식을 택했다. 마이그레이션 방향은 바텀업(bottom-up) — 가장 말단의 작은 컴포넌트부터 React로 바꾸고, 점점 상위 컴포넌트로 올라가는 식이다.

마이그레이션 진행 방향
Angular 앱 (전체 프레임)
  └── Angular 페이지
        ├── Angular 컴포넌트
        │     └── React 컴포넌트 (ngReact) ← 여기서 시작
        ├── React 컴포넌트
        └── Angular 컴포넌트
              └── React 컴포넌트

[💡 잠깐! 이 용어는?] ngReact: Angular 1 디렉티브 안에서 React 컴포넌트를 렌더링할 수 있게 해주는 브릿지 라이브러리. Angular의 $scope가 변경되면 React 컴포넌트에 props로 전달된다.

어떤 것부터 바꿀까?

모든 컴포넌트를 동시에 바꿀 수 없으니 우선순위가 필요했다. 팀은 세 가지 기준으로 점수를 매겼다.

기준설명높을수록
버그율(Bug Rate)해당 모듈에서 버그가 얼마나 자주 발생하는가먼저 마이그레이션
코드 품질테스트 커버리지, 일관성, 가독성낮을수록 먼저
변경 빈도(Churn Rate)최근 커밋에서 얼마나 자주 수정되는가높을수록 먼저

버그가 잦고, 코드 품질이 낮고, 자주 변경되는 모듈이 마이그레이션의 ROI가 가장 높은 대상이다. 반대로 안정적이고 거의 건드리지 않는 코드는 나중으로 미룬다.


테스트 전략

레거시 마이그레이션에서 테스트는 안전망이다. 테스트 없이 마이그레이션하면 "고친 건지 부순 건지" 구분이 안 된다.

테스트 종류도구역할
단위 테스트Jest + EnzymeReact 컴포넌트 개별 검증
E2E 테스트Protractor사용자 시나리오 전체 흐름 검증
크로스 브라우저Sauce LabsIE, Safari 등 다양한 환경 검증

핵심은 E2E 테스트를 먼저 작성하는 것이었다. Angular 버전으로 E2E 테스트를 만들어두면, React로 교체한 뒤 같은 테스트를 통과하는지 확인하는 것만으로 기능 동등성을 보장할 수 있다. 비유하면 리모델링 전에 건물 도면을 그려놓는 것과 같다. 벽을 뜯은 뒤에도 도면대로 되어 있는지 대조할 수 있다.


7가지 교훈

1년간의 마이그레이션에서 Jack Franklin이 공유한 핵심 교훈을 정리한다.

1. 매일 배포한다

마이그레이션 코드를 오래 쌓아두면 통합 충돌이 커진다. 매일 작은 단위로 배포하면 문제가 생겨도 범위가 좁아서 원인을 빨리 찾을 수 있다.

2. 작업에 변화를 준다

1년 내내 마이그레이션만 하면 팀이 지친다. 새 기능 개발, 버그 수정, 마이그레이션 작업을 번갈아 배치해서 단조로움을 피했다.

3. 진행 상황을 시각화한다

마이그레이션은 끝이 안 보이는 느낌을 주기 쉽다. Angular 컴포넌트 수 대비 React 컴포넌트 수를 대시보드로 시각화해서 팀의 사기를 유지했다.

진행률 시각화 예시
Angular 컴포넌트: ████████░░░░░░░░  47개 (42%)
React 컴포넌트:   ████████████████  65개 (58%)

4. 기술 부채를 비즈니스 언어로 번역한다

"Angular가 낡았다"는 설명은 경영진에게 와닿지 않는다. 대신 이렇게 말한다:

기술 언어비즈니스 언어
Angular 1이 EOL이다보안 패치가 중단되어 리스크가 생긴다
코드 품질이 낮다새 기능 출시 속도가 2배 느려진다
테스트가 없다버그 수정에 드는 비용이 매달 증가한다

[💡 잠깐! 이 용어는?] 기술 부채(Technical Debt): 빠른 출시를 위해 미뤄둔 코드 개선 작업. 금융 부채처럼 시간이 지날수록 이자(유지보수 비용)가 불어난다.

5. 완벽한 마이그레이션 계획은 없다

처음 세운 계획은 3개월 만에 수정됐다. 예상보다 복잡한 모듈이 있었고, 비즈니스 우선순위가 바뀌었다. 계획은 방향을 잡는 도구이지, 철칙이 아니다.

6. 양쪽 프레임워크의 경계를 명확히 한다

Angular와 React가 공존하는 동안, 데이터가 어디서 관리되고 어디서 렌더링되는지 경계가 모호해지기 쉽다. ngReact 브릿지를 통과하는 데이터 흐름을 문서화하고, 팀 전체가 동일한 규칙을 따르도록 했다.

7. "나중에 고치자"는 실현되지 않는다

마이그레이션 중에 발견한 문제를 "나중에" 목록에 넣으면, 그 목록은 끝없이 길어진다. 작은 개선이라도 해당 모듈을 마이그레이션할 때 같이 처리하는 게 현실적이다.


실전 적용 체크리스트

Strangler 패턴 마이그레이션을 시작하기 전에 확인할 포인트를 정리한다.

  • E2E 테스트가 핵심 흐름을 커버하는가? — 마이그레이션 전에 안전망을 먼저 깐다.
  • 우선순위 기준이 명확한가? — 버그율, 코드 품질, 변경 빈도로 정량화한다.
  • 매일 배포할 수 있는 환경인가? — CI/CD 파이프라인이 준비되어야 한다.
  • 경영진에게 비즈니스 임팩트로 설명했는가? — "기술 부채"가 아니라 "출시 속도"로 말한다.
  • 팀이 번아웃되지 않을 일정인가? — 마이그레이션과 새 기능 작업을 번갈아 배치한다.

정리

  • 대규모 레거시 마이그레이션은 **빅뱅이 아니라 점진적 교체(Strangler 패턴)**가 현실적이다.
  • ngReact 같은 브릿지 라이브러리로 두 프레임워크를 공존시키면서, 바텀업으로 하나씩 교체한다.
  • 우선순위는 감이 아니라 버그율, 코드 품질, 변경 빈도로 정한다.
  • 기술 부채를 경영진에게 설명할 때는 **비즈니스 임팩트(속도, 비용, 리스크)**로 번역한다.
  • 마이그레이션은 마라톤이다. 팀의 사기를 유지하는 것도 기술적 결정만큼 중요하다.

참고:

관심 있을 만한 포스트

React 상태 올리기 — 대부분의 경우 하지 않는 게 낫다

React에서 습관적으로 lift state up을 하는 안티패턴을 살펴보고, 상태를 쓰는 곳 가까이 두는 편이 왜 더 나은지 정리한다.

React상태 관리

React Compiler의 한계 — 뭘 최적화하고 뭘 못 하는가

React Compiler가 자동 메모이제이션으로 해결하는 것과 해결하지 못하는 것. 컴파일러 기반 UI 프레임워크의 능력 경계를 정리했다.

ReactReact Compiler

Coaction v1.0 — Web Worker로 멀티스레딩 상태 관리하기

JavaScript 단일 스레드 한계를 극복하는 상태 관리 라이브러리 Coaction의 동작 방식, Zustand와의 차이, Standard/Shared 두 가지 모드 사용법을 정리한다.

CoactionWeb Worker

LCP 28초짜리 React 앱을 1초로 깎아낸 기록 — 4단계 성능 수술 프레임워크

번들 분석부터 에셋 최적화까지, React 앱의 LCP를 단계적으로 개선하는 실전 프레임워크를 다룬다.

React성능 최적화

달리는 기차의 엔진을 교체하라 — 네이버 스마트스토어 Oracle→MySQL 이중 쓰기 전환기

10년 이상 운영한 Oracle을 서비스 중단 없이 MySQL로 전환한 네이버 스마트스토어 회원 파트의 이중 쓰기(dual write) 전략과 기술적 해결 과정.

MySQLOracle

Next.js 블로그 만들기 — 카드 그리드와 포스트 상세 페이지

Velog 스타일 카드 UI와 MDX 렌더링 상세 페이지 구현. 반응형 그리드, SEO 메타데이터, 정적 사이트 생성까지.

Next.jsReact

SVG 아이콘 — 코드 배포 없이 프로덕트 팀이 직접 관리하는 법

CSS mask-image와 S3를 조합해 개발자 개입 없이 아이콘을 교체하는 패턴을 소개한다.

SVGCSS

VS Code 1.116 — 에이전트 디버깅, 포그라운드 터미널, 내장 Copilot

2026년 4월 VS Code 1.116이 에이전트 경험, 터미널, Chat UX, 내장 브라우저를 개선한 핵심 변경사항을 정리한다.

VS Code1.116