레거시 코드, 방치하면 '시한폭탄' 된다: 재작성 vs. 리팩토링, 어떤 선택이 현명할까?
2026. 6. 20.
레거시 코드, 방치하면 '시한폭탄' 된다: 재작성 vs. 리팩토링, 어떤 선택이 현명할까?
이번 주부터는 좀 더 가벼운 주제를 다뤄보자고 스스로 다짐했는데, 월요일에 JSNation 컨퍼런스 여정이 공식적으로 끝났습니다. 강연에 대해선 아직 글 하나도 쓰지 못했더라고요. 기억이 생생할 때, 바로 시작해볼까요!
JSNation 자체에 대해선 사실 복합적인 감정이 교차합니다. 저는 온라인 트랙에 선정되었고, 주최 측의 전문성은 정말 대단했지만, 직접 현장에 가는 것과는 역시 달랐어요. 제가 JSNation에서 느낀 건, 온라인 세션이 아무리 잘 준비되어도 현장의 에너지와 네트워킹을 따라갈 순 없다는 점이었죠. 화면 너머로 제 강연을 보면서 팀즈 메시지에 답하고 있자니, '내가 지금 암스테르담에서 웨스 보스와 맥주를 마시고 있을 수도 있었는데!' 하는 아쉬움이 진하게 밀려왔습니다. 😄 그래도 정말 좋은 경험이었어요. 누가 알겠어요? 언젠가 제 전문성이나, 아니면 이 정도 '유명세'라도 😅 더 커져서 암스테르담에서 직접 강연할 기회를 얻을지도요.

(물론 올해 안에 암스테르담을 다시 방문할 계획이 있긴 하지만, 너무 앞서가지 말자고요. 😉)
다시 본론으로 돌아와서, 제 강연 제목은 "재작성(Rewrite) vs. 리팩토링(Refactor)? 레거시 앱을 현대적인 프레임워크로 안전하게 옮기는 방법" 이었습니다. 제가 이 주제에 대해 이야기할 적임자라고 생각해요. 왜냐고요? 경력 내내 프런트엔드 앱을 수없이 마이그레이션해왔거든요. 오래된 Angular를 최신 Angular로, ASP.NET MVC 5를 Vue로, 클래스 컴포넌트 기반 React를 최신 React로 바꾸는 등 정말 다양한 환경을 겪어봤습니다.
이유는 간단합니다. 어떤 회사든 마이그레이션이 절실한 상황에서, 이미 마이그레이션 경험이 있는 지원자의 이력서를 보면 보통은 정말 기뻐하며 채용하거든요. 심지어 시장 가격보다 조금 더 높은 연봉을 제시하는 경우도 흔하고요! 😄 그렇게 저는 프런트엔드 마이그레이션 전문가가 되었고, 이 분야에 대해 할 이야기가 꽤 많습니다.
그런데, 대체 왜 마이그레이션을 해야 하죠?
전략을 논하기 전에, 좀 더 근본적인 질문에 답해야 합니다. 애초에 왜 마이그레이션을 해야 할까요?
이 질문은 이해관계자들, 특히 비기술적인 제품 책임자들에게서 수없이 들었습니다. "애플리케이션이 잘 작동하는데, 왜 건드리죠? 개발자들은 그냥 유행을 쫓고 이력서에 번쩍이는 기술을 추가하고 싶어 하는 거 아닌가요?"
제 대답은 보통 매우 간단하고 솔직합니다.
저를 잘 아실 겁니다. 저는 특정 프레임워크의 팬보이가 아닙니다. 제게 프레임워크는 그저 도구일 뿐이죠. 망치 같은 거요. 하지만 무언가를 만들 때, 부품이 빠진 녹슨 망치보다는 견고하고 신뢰할 수 있는 망치를 쓰고 싶을 겁니다. 😉🔨⛏️🪓🔧🪛
하지만 마이그레이션은 단순히 개발자 경험에 대한 이야기만은 아닙니다. 현실적으로, 이건 제품의 생존과 직결된 문제예요. 특히 기술이 그 어느 때보다 빠르게 진화하고 AI가 모든 것을 더욱 가속화하는 요즘 같은 시대에는요.
보안을 예로 들어볼까요? 특정 라이브러리가 더 이상 사용되지 않고 아무도 유지보수하지 않으면, 보안 패치는 끊깁니다. 그러면 취약점 보고서가 빨갛게 물들기 시작하죠. 역사상 그 어떤 제품 책임자도 "좋아요, 몇 가지 추가 기능을 위해 보안을 희생합시다!"라고 말한 적은 없을 겁니다. 적어도 저는 그렇게 바랍니다 😅
그리고 현대적인 개발 도구도 빼놓을 수 없죠. Vite 빌드만으로도 엄청난 차이를 만들어낼 수 있습니다. 최신 애플리케이션은 단순히 더 빠르고, 빠른 애플리케이션은 더 좋은 애플리케이션이니까요. 제가 실무에서 레거시 시스템을 접할 때마다 느끼는 건, 단순히 개발자의 '새로운 기술 쓰고 싶다'는 욕망을 넘어, 결국엔 제품의 생존 문제라는 겁니다. 특히 보안 취약점 보고서가 빨갛게 물들기 시작하면, 그 어떤 비즈니스 요구사항도 보안을 앞설 수 없다는 걸 경험으로 알게 되죠.
이 외에도 많은 이유가 있지만, 가장 중요한 건 이것 하나입니다:
마이그레이션을 미루면 미룰수록, 더 어렵고 비싸집니다.
좋아요, 좋아요. 마이그레이션하고 싶어요. 그런데 어떻게 하죠?
흥미롭게도, LLM(거대 언어 모델)의 등장이 마이그레이션 전략을 근본적으로 바꾸지는 않았습니다. AI가 주류가 되기 전과 기본적으로 동일하죠. 때로는 작업 속도가 빨라지기도 하고, 아닐 때도 있지만, 근본적인 접근 방식은 변함이 없습니다.
아마 시니어 엔지니어의 수만큼 마이그레이션 전략이 존재할 테지만, 실제로는 크게 두 가지 범주로 나뉩니다.
재작성 (빅뱅 전략, Rewrite / Big Bang Strategy)
전체 애플리케이션을 처음부터 다시 작성하거나, 프런트엔드에서 흔히 발생하는 것처럼, 오래된 스택을 프레임워크의 최신 버전으로 직접 업그레이드하는 방식입니다.
리팩토링 (스트랭글러 패턴, Refactor / Strangler Pattern)
기존 애플리케이션의 기능을 계속 제공하면서, 부분적으로 애플리케이션을 조금씩 재작성해 나가는 방식입니다.
그렇다면, 어떤 접근 방식이 더 좋을까요?
솔직히 말해, 이 부분에서 '성전(holy war)'을 벌일 필요는 없습니다. 대부분의 경우, 프로젝트의 현실이 당신 대신 결정을 내려줄 겁니다.
애플리케이션이 상대적으로 작고, 팀이 숙련되었으며, 문서화가 잘 되어 있고, 몇 주 또는 몇 달 동안 기능 개발을 중단할 여유가 있다면, 재작성(Rewrite)이 완벽하게 합리적인 선택이 될 수 있습니다.
반면에, 주니어 개발자가 많거나 해당 기술에 익숙하지 않은 사람들이 많은 거대한 프로젝트를 진행하고 있고, 문서화가 거의 없다면 – 점진적인 리팩토링(Incremental Refactor)이 아마도 유일한 현실적인 선택지일 겁니다.
물론 고려해야 할 다른 많은 요소들이 있습니다. 다음은 간략한 요약입니다:
| 요소 | 재작성 (빅뱅) | 리팩토링 (스트랭글러) |
|---|---|---|
| 애플리케이션 크기 | 작거나 중간 | 큼 |
| 기능 개발 | 중단 가능 | 계속해야 함 |
| 문서화 | 좋음 | 부족함 |
| 팀 경험 | 높음 | 혼합됨 |
| 위험 감수 수준 | 높음 | 낮음 |
| 첫 번째 결과 도출 시간 | 짧음 | 긺 |
| 마이그레이션 중 복잡성 | 낮음 | 높음 |
| 무한 마이그레이션 위험 | 낮음 | 높음 |
빅뱅 – 생각보다 무섭지 않아요
두 가지 접근 방식을 간략하게 설명해 드리겠습니다. 빅뱅부터 시작하죠.
솔직히 저는 이 전략을 좋아합니다. 물론 책이나 글에서는 위험하고, 때로는 안티 패턴으로 묘사되기도 합니다. 그리고 그들의 말이 맞습니다 – 만약 아무도 건드릴 엄두조차 못 내는 20년 된 자바 모놀리스를 이야기한다면요.
하지만 많은 프런트엔드 애플리케이션은 비교적 젊고 크기도 상대적으로 작습니다. 이런 상황에서는 빅뱅 접근 방식이 단순히 더 빠르고 저렴할 수 있습니다.
요즘 완전 재작성은 비교적 드뭅니다. 하지만 대규모 업그레이드는 꽤 흔하죠. 예를 들어, Angular 7에서 Signals를 사용하는 최신 Angular로, 또는 클래스 컴포넌트 기반의 오래된 React에서 훅을 사용하는 최신 React로 전환하는 경우 같은 것들입니다.
이러한 프로젝트들도 여전히 많은 작업과 오래된 코드를 깊이 파고드는 과정을 요구하지만, 스트랭글러 마이그레이션보다 훨씬 빠르게 결승선에 도달할 수 있습니다.
계획 단계, 마이그레이션 스크립트, 코드 모드 또는 제가 사용했던 특정 도구에 대해서는 자세히 설명하지 않겠습니다. 그런 세부 사항은 프로젝트마다 다르며 일반적인 글에서는 큰 의미가 없습니다.
그러나 거의 모든 마이그레이션에서 놀랍도록 일관되게 나타나는 특정 사항들이 있습니다. 😉
실전 사례: Angular 7에서 최신 Angular로의 빅뱅 마이그레이션
여기 흥미로운 예시가 있습니다. 때로는 팀이 어떻게 애플리케이션을 수년간 업그레이드 없이 방치할 수 있었을까 궁금해질 때가 있죠. 실제로는 놀랍도록 쉬운 일입니다. 특히 제품이 유지보수 모드에 있고 수년간 크게 변경되지 않아 아무도 적극적으로 작업하지 않는 경우에요.
이 경우가 딱 그랬습니다.
그러다 어느 날, 이해관계자들이 애플리케이션을 대폭 확장하고 새로운 기능을 여러 개 추가하기로 결정했습니다. 저는 주로 보안상의 이유로 최신 Angular 버전으로 업그레이드하도록 그들을 설득했습니다. 시스템이 중요한 데이터를 저장하고 있었거든요.
간단히 말해, 네 명의 개발자가 4개월 만에 최신 버전으로 업그레이드했습니다. 그리고 예상했던 것보다 훨씬 더 어려웠습니다.
무엇보다도 문제의 범위를 과소평가하기 쉽습니다. 겉으로 보기에는 간단해 보이죠: "그냥 Angular만 업그레이드하면 돼."
하지만 프레임워크 자체는 실제 문제가 되는 경우가 드뭅니다. 주변 생태계가 문제죠.
예를 들어, 저희의 주요 컴포넌트 라이브러리는 버전 12와 13 사이 어딘가에서 주요 구문 변경을 도입했습니다. 얼마나 많은 곳을 업데이트해야 했을지 상상해보세요! 물론 AI가 도움이 될 수 있지만, 야심 찬 UI 엔지니어가 CSS 클래스 이름을 바꾸고 컴포넌트 구조를 변경하기로 결정했다면, AI도 당신을 구할 수 없습니다. 결국 수동으로 수정해야 할 거예요. 제 경험상, 초기 단계에서 컴포넌트 라이브러리를 한 번에 대규모로 바꾸는 게 오히려 장기적으로는 관리 비용을 줄이는 지름길이 될 때가 많았습니다. 물론 마이그레이션 도중 '이걸 왜 이렇게 만들었지?' 하는 한탄이 수없이 터져 나오지만요.
일부 서드파티 라이브러리는 오래전에 버려졌습니다. 그리고 여기서 기억해 둘 만한 것이 있습니다:
수년간 업데이트되지 않았고, 저자가 존재 자체를 잊어버린 것 같으며, 심지어 Node 18에서는 컴파일조차 되지 않는 라이브러리가 있다면, 그건 "작동하는 코드"가 아닙니다. 그건 "시한폭탄"입니다.
네, 저희는 수많은 E2E 테스트를 가지고 있었습니다. 그중 많은 부분이 컴포넌트 라이브러리 변경 때문에 터져버렸죠. 😄 그러니 자동화된 테스트조차 항상 당신을 구원해주지는 않습니다.
또 다른 중요한 교훈: 핫픽스를 위한 견고한 브랜칭 전략을 항상 마련해 두세요. 뭔가 잘못될 거라고 가정하세요. 왜냐하면 결국, 아마도 뭔가 잘못될 테니까요.

다행히 마이그레이션은 성공적이었습니다.
빌드 시간은 극적으로 개선되었습니다. 번들 크기는 상당히 줄어들었습니다. 새로운 레이아웃은 이전 것보다 훨씬 보기 좋아서, 기술에 가장 저항적이던 이해관계자들조차 감탄했습니다.
그리고 아마도 가장 중요하게는, 애플리케이션이 미래 업그레이드를 위한 준비를 마쳤다는 것입니다. 처음에는 우리를 미워했던 QA 팀조차, 7년에 한 번 하는 것보다 정기적으로 업그레이드하는 것이 훨씬 낫다고 결국 인정했습니다 🤣.
점진적 마이그레이션 – 두 마리 토끼를 다 잡는 방법
하지만 때로는 애플리케이션이 빅뱅 접근 방식을 취하기에는 너무 크거나, 기능을 계속 제공해야 하는 상황일 수 있습니다. 이 경우, 점진적 마이그레이션이 유일한 현실적인 선택지가 됩니다.
이러한 단계별 리팩토링은 보통 **스트랭글러 패턴(Strangler Pattern)**을 사용하여 구현됩니다. 물론 다른 접근 방식도 있지만, 저는 개인적으로 이 방식이 우아하고 비교적 간단하며, 세계에서 가장 큰 기술 회사들 중 일부에서 검증되었기 때문에 좋아합니다.
그렇다면 스트랭글러 패턴은 정확히 무엇일까요?
아래 제가 직접 draw.io로 만든 아름다운 다이어그램을 살펴보시죠. 😄

보시다시피, 레거시 애플리케이션으로 시작합니다. 그 옆에 새로운 애플리케이션을 구축합니다. 그리고 그 앞에 리버스 프록시를 두어, 어떤 경로가 어떤 애플리케이션으로 갈지 결정하게 합니다.
그다음부터는 화면별, 경로별로 마이그레이션합니다. 시간이 지남에 따라 레거시 애플리케이션은 점점 작아지고, 결국에는 새로운 애플리케이션만 남게 되기를 바라며, 마지막에는 오래된 앱과 리버스 프록시를 모두 제거할 수 있습니다.
이 시나리오에서는 두 애플리케이션이 인증과 백엔드를 공유해야 하지만, 프런트엔드 코드는 공유하지 않아야 합니다.
그리고 두 애플리케이션이 반드시 통신해야 한다면, 이른바 "임시" 어댑터 같은 것보다는 사용자 정의 DOM 이벤트와 같은 간단한 것을 사용하는 것을 강력히 추천합니다.
왜냐하면 소프트웨어 엔지니어링에서 "임시(temporary)"가 무엇을 의미하는지 우리 모두 알고 있기 때문이죠. 영원히(Forever). 😅 그리고 깨닫기도 전에, 그 어댑터들은 새로운 레거시 조각이 되어버릴 겁니다.
실전 사례: 스트랭글러 패턴으로 백본(Backbone)에서 뷰(Vue)로 마이그레이션하기
이것은 백본으로 작성된 오래된 애플리케이션이었고 – 솔직히 말해 정말 잘 작성된 코드였습니다. 하지만 그래도 백본이었죠. 😄
애플리케이션이 엄청나게 큰 것은 아니어서 이론적으로는 빅뱅 마이그레이션도 가능했습니다. 하지만 저희는 스타트업이었고, 어느 날 이런 유명한 말을 듣게 되었습니다: "여러분, 아직 존재하지 않는 기능을 방금 팔았습니다. 3개월 안에 납품해야 합니다. 즐겁게 개발하세요!"
저의 즉각적인 반응은 이랬습니다: "하하하. 정말 재미있네요. 그걸 백본으로 만들 리가 없죠." 다행히 저희 이해관계자들은 똑똑했고 스트랭글러 마이그레이션에 동의했습니다.
제 팀은 저와… TypeScript라는 단어를 태어나서 처음 들어봤다고 맹세하는 두 명의 주니어 자바 개발자로 구성되어 있었습니다.
다행히 그들은 야심찼고 빠르게 배웠습니다. 뭐, 사실 선택의 여지가 별로 없었죠. 😄 그리고 이것이 이 전략의 또 다른 장점입니다: 주니어 개발자들은 그 과정에서 배울 수 있습니다. 저는 새로운 Vue 애플리케이션을 옆에 만들었습니다. 회사에 많은 사람들이 이미 Vue를 알고 있었기 때문에 선택은 명확했습니다.
먼저, 개념 증명(PoC)으로 로그인 화면을 마이그레이션했습니다. 그런 다음 고객이 이미 비용을 지불한 번쩍이는 새 기능으로 넘어갔습니다. 😉
이후 1년 동안 우리는 애플리케이션을 화면별로 마이그레이션했습니다.

결국 백본은 완전히 사라졌습니다. 그리고 전체 과정 동안 단 한 번의 다운타임도 없었습니다. 고객들은 마이그레이션이 진행되고 있다는 사실조차 눈치채지 못했습니다.
이 전략은 특히 팀에 주니어 개발자들이 많을 때 빛을 발합니다. 기존 코드의 복잡성에 매몰되지 않고, 새로운 스택으로 작은 성공을 계속 맛보며 빠르게 성장할 기회를 주기 때문이죠. 제가 직접 겪었던 백본에서 뷰로의 전환에서도 주니어 개발자들이 놀랍게 성장하는 걸 보면서 이 패턴의 가치를 다시 한번 실감했습니다.
이전 예시와 마찬가지로, 번들 크기는 현저히 작아졌고, 빌드 시간은 극적으로 개선되었습니다.
하지만 스트랭글러 접근 방식이 마냥 장밋빛만 있는 것은 아닙니다.
우선, 시간 요소가 있습니다. 마이그레이션 과정은 매우 오래 걸립니다. 저희의 경우, 비교적 작은 애플리케이션이었음에도 불구하고 전체 1년이 걸렸습니다.
또한 **끝없는 마이그레이션(never-ending migration)**의 위험도 있습니다. 무슨 말인지 아실 겁니다. 마감 기한이 쌓이고, 기능은 계속 추가됩니다. 그리고 한동안 지나면, 제품 책임자에게 마이그레이션 작업을 위해 몇 개의 스토리 포인트를 할당해달라고 거의 애원하고 있는 자신을 발견하게 됩니다.
그리고 불행히도 레거시 코드를 건드리는 것을 피할 방법은 없습니다. 전혀 없어요. 그리고 개발자들은 이걸 정말 싫어한다는 걸 믿으세요. 저는 이런 말들을 들어봤습니다: "실비아, 왜 모든 걸 그렇게 복잡하게 만들어요? 이제 우리는 두 가지 기술 스택을 알아야 한다고요!"
그러니 어떤 전략을 선택하든, 아마도 팀의 희생양이 될 겁니다. 적어도 마이그레이션이 진행되는 동안에는요.
하지만 일단 마이그레이션이 끝나고, 번들 크기가 절반으로 줄어들고, 취약점 보고서가 더 이상 빨갛게 빛나지 않으며, 고객들의 불만이 사라지면, 당신은 갑자기 회사의 영웅이 될 겁니다. 😄
몇 가지 마지막 말
레거시 애플리케이션을 마이그레이션하는 것은 낡은 집을 사는 것과 비슷합니다. 집이 무너져가는 것이 당신의 잘못은 아니지만, 다시 제 모습을 찾도록 만드는 것은 당신의 책임입니다. 몇 주 휴가를 내고 모든 것을 한꺼번에 수리할 수도 있고, 아니면 이사 들어와서 한 번에 한 방씩 고쳐나갈 수도 있습니다.
정말 나쁜 유일한 전략은 아무것도 하지 않는 것입니다. 조만간 어쨌든 마이그레이션을 해야 할 겁니다. 단지 그때는 프로덕션 사고 때문에 하게 될 거라는 차이가 있을 뿐이죠. 😉
자, 당신의 레거시 애플리케이션을 리노베이션하는 접근 방식은 무엇인가요?
면책 조항 (Disclaimer)
위에 설명된 이야기 중 실제로 일어난 일은 없습니다. 아니, 어쩌면 일어났을지도요? 😉
전문가이자 NDA에 구속된 사람으로서, 저는 어떤 회사나 프로젝트도 식별되지 않도록 여러 마이그레이션 이야기를 의도적으로 섞어서 만들었습니다. 사실 그렇게 어렵지 않았습니다. 왜냐하면 시간이 지나면 모든 마이그레이션이 놀랍도록 비슷하게 보이기 시작하거든요. 😄
제 글이 마음에 드신다면, LinkedIn에서도 저를 팔로우해주세요.
원문: https://dev.to/sylwia-lask/who-here-has-worked-with-legacy-the-longer-you-wait-the-worse-it-gets-58bk 수집일: 2026-06-20 00:24:58