Post

레거시 UI 빌드 개선기 1: 50분짜리 기다림을 문제로 보기까지

레거시 UI를 어떻게 문제를 정의했고, AI가 360만줄 코드를 분석 가능한 상태로 만드는 과정

신입 때 처음 이 프로젝트를 접했을 때부터 빌드 시간은 분명한 불편이었습니다.

여러 팀이 공유해 사용하는 레거시 UI 프로젝트였습니다. 시간이 지나도 상황은 크게 달라지지 않았고, 어느 순간부터는 모두가 그 불편에 맞춰 일하고 있었습니다. 로컬 개발을 하려면 사용하지 않는 서비스 라우터를 주석 처리해야 했고, 개발기 검수는 빌드가 끝날 때까지 기다려야 했습니다.

저는 이 상황을 “프론트엔드 빌드가 느리다”보다 조금 다르게 봤습니다. 개발 흐름 전체를 막는 병목에 가까웠습니다.

모두가 알고 있었지만, 해결되지 않던 문제

사내에서 공통으로 사용하는 레거시 UI는 빌드 한 번에 평균 40~50분 정도가 걸렸습니다.

어느 날 갑자기 생긴 문제가 아니었습니다. 오래전부터 모두가 알고 있었지만, 당장 해결하기 어렵다는 이유로 자연스럽게 감수하는 일이 되어 개발자가 로컬에서 특정 기능을 확인하려면 자신이 사용하지 않는 서비스들을 최대한 주석 처리해야 했습니다. 그래야 개발 서버를 띄우고 작업할 수 있었습니다.

스크린샷 2026-04-29 오후 4.28.12.png

처음에는 임시방편처럼 보였지만, 시간이 지나면서 이 방식은 하나의 개발 방식처럼 굳어져 있었습니다.

  • 로컬에서 개발을 시작시간 지연
  • 사용하지 않는 라우터를 주석 처리하는 작업이 반복
  • 주석 처리한 코드가 실수로 커밋될 위험 감수
  • QA팀은 개발기 검수시간 지연

빌드 시간이 길어지면서 개발, 검수, 배포 워크플로우가 느려지고 있었습니다.

스크린샷 2026-04-27 오후 4.47.43.png

개발 흐름의 병목

이 상황을 “프론트엔드 빌드가 느리다” 한 줄로 정리하기는 어려웠습니다.

실제 기능 개발은 여러 역할을 거쳐 진행됩니다. 기획자가 새 기능을 기획하면 디자인팀이 화면과 상태를 정의하고, 마크업팀은 그 디자인을 받아 UI를 구성합니다. 이후 개발자는 기획을 검토하고 백엔드 개발이 필요한지 확인합니다. API나 데이터 처리 작업이 먼저 필요한 경우에는 백엔드 작업 결과가 나온 뒤, 프론트엔드에서 마크업을 확인하며 기능을 연결합니다.

기능 개발이 끝나도 개발기 빌드에 40~50분이 걸리니 QA팀은 바로 검수를 시작하지 못했습니다. 개발자는 빌드가 끝났는지 확인한 뒤에야 검수를 요청했고, QA 피드백이 돌아오는 시간도 자연스럽게 뒤로 밀렸습니다. 빌드 시간은 개발자 한 명의 대기 시간으로 끝나지 않았습니다. QA 요청, 검수, 운영 반영, 운영 검수까지 이어지는 피드백 루프 전체를 늦추는 병목이었습니다.

image.png

제가 이 작업을 통해 보여주고 싶었던 것은 “프론트엔드 잘 안다”가 아니었습니다. 제 주 업무는 백엔드에 더 가깝습니다. 다만 이 문제는 특정 프론트엔드 기술 하나의 문제가 아니라 협업 흐름의 문제였고, 그래서 빌드 도구를 바꾸기 전에 조직의 대기 시간을 줄이는 일로 봐야 했습니다.

AI 활용의 전제

프로젝트는 규모가 커 Claude Code에게 전체 프로젝트를 그대로 읽게 하는 방식은 효율적이지 않았습니다. 토큰 한계 때문에 전체 구조를 한 번에 이해시키기 어려웠고, 단순히 “빌드 빠르게 해줘”라고 요청한다고 해결될 문제도 아니었습니다.

  • JS 파일: 약 11,383개
  • JS 코드 라인: 약 3,667,273줄
  • 서비스 모듈: 약 97개
  • 사내 내부 Git 패키지: 18개
  • Webpack: 2.2.1
  • Babel: 6.x
  • React: 15.x

그래서 먼저 해야 할 일은 코드를 고치는 것이 아니라, AI가 이 거대한 코드베이스를 분석 가능한 형태로 받아들이게 정리해야 했습니다.

분석 가능한 코드베이스

전체 파일을 무작정 읽히는 대신, 분석에 필요한 자료를 따로 만들었습니다. 이 자료들을 .ai-context/ 디렉토리에 모아두고, CLAUDE.md에는 분석 순서와 각 자료의 용도를 적었습니다.

1
2
3
4
.ai-context/
├── deps.json                          # dependency-cruiser: 모듈 간 의존 관계 그래프
├── codebase-compressed-compress.xml   # Repomix: 파일별 API 표면 (함수 시그니처, export)
└── churn-top100                       # Git 로그: 최근 12개월 수정 빈도 상위 파일

1. 의존성 그래프

dependency-cruiser를 사용해 어떤 파일이 어떤 파일을 import하는지 JSON으로 추출했습니다. 이를 통해 특정 파일을 바꿨을 때 어디까지 영향이 퍼질 수 있는지 확인할 수 있었습니다.

2. 압축된 코드베이스

Repomix를 사용해 전체 코드를 압축된 형태로 만들었습니다. 구현 전체를 전부 읽기보다, 파일의 역할과 API 표면을 먼저 파악할 수 있도록 했습니다.

3. 변경 빈도 분석

Git 로그를 기반으로 최근 12개월 동안 자주 수정된 파일을 뽑았습니다. 많이 바뀐 파일은 그만큼 중요하거나, 버그가 발생할 가능성이 높거나, 여러 기능과 연결되어 있을 가능성이 높다고 판단했습니다.

이 세 가지 자료를 바탕으로 AI에게 다음과 같은 순서로 분석하게 했습니다.

스크린샷 2026-04-27 오후 5.06.09.png

계획과 검증

AI에게 프롬프트 한번으로 빌드 개선이 아닌 분석 가능한 코드베이스를 통하여 마크다운 파일로 점진적 개선 방식으로 계획을 세우고 사람이 검증하는 과정으로 진행하였습니다.

실제 프로젝트에 적용하려면 그보다 훨씬 구체적인 질문들이 따라옵니다.

  • React 15와 호환되는가?
  • 문제가 생겼을 때 롤백할 수 있는가?
  • QA가 기존 UI와 비교 검수할 수 있는가?
  • Jekins 환경에서도 동일한 결과가 나올 수 있는가?
  • 개선되었다는 지표는 어떻게 보여질것인가?
  • 레거시와 개선된 repo를 어떻게 동기화할것인가?

AI가 대신 책임질 수 없는 질문들입니다. 그래서 저는 이 작업을 단순한 코드 수정이 아니라, 계획과 검증이 필요한 개선 프로젝트로 다루었습니다.

단계적 개선 전략

처음부터 Webpack 2를 Webpack 5로 바꾸고 Babel을 SWC로 교체하는 방식은 위험하다고 판단했습니다. 프로젝트 규모가 크고 오래된 문법과 내부 패키지가 많았기 때문에, 한 번에 바꾸면 문제가 생겼을 때 원인을 찾기 어려웠습니다.

그래서 개선 단계를 나누었습니다.

  • 1단계 (즉시 개선): 기존 Webpack 2를 유지하면서 안전하게 줄일 여지가 있는 부분부터 정리했습니다. 빌드 스크립트를 손보고, babel 캐시를 켜고, dev 빌드에서는 minification을 제거했습니다.
  • 2단계 (도구 교체): minification 도구를 esbuild 기반으로 교체했습니다.
  • 3단계 (근본 전환): Webpack 5와 SWC로 전환했습니다.

image.png

This post is licensed under CC BY 4.0 by the author.