Files
2nd/00_Raw/Legacy Codebase Refactoring.md
T

9.3 KiB

Legacy Codebase Refactoring

📌 Brief Summary

Legacy Codebase Refactoring(레거시 코드베이스 리팩터링)은 시간이 지남에 따라 노후화된 애플리케이션의 코드를 동작 변화 없이 점진적으로 개선하여 구조를 현대화하는 작업입니다 [1]. 단순히 코드를 수정하는 것에 그치지 않고 시스템의 유지보수성을 높이며 기술 부채를 관리하는 핵심 과정입니다 [1]. React 생태계에서는 주로 클래스형 컴포넌트를 함수형 컴포넌트(Hooks)로 전환하거나, 노후화된 상태 관리 라이브러리를 최신 도구로 마이그레이션하며, 코드베이스에 테스트 및 정적 분석 도구를 통합하는 방식으로 진행됩니다 [1-3].

📖 Core Content

  • 점진적 마이그레이션 전략 (Incremental Migration): 레거시 시스템을 한 번에 모두 재작성하는 것은 위험성이 큽니다 [1]. 따라서 "재작성하지 말고 리팩터링하라(refactor, do not rewrite)"는 철학을 바탕으로, 기존의 기능 개발을 계속하면서 상태 관리 스토어나 아키텍처를 하나씩 점진적으로 이동하는 전략이 권장됩니다 [1].
  • 테스트 주도 접근 및 동작 보장: 리팩터링을 시작하기 전에 반드시 단위 테스트나 UI 테스트 스위트를 작성해야 합니다 [4, 5]. 테스트 코드는 기존 코드의 역할을 이해하게 도와주며, 리팩터링 과정에서 발생할 수 있는 기능 파손(regression)을 즉시 파악할 수 있도록 합니다 [4, 6].
  • React 특화 리팩터링 체크리스트:
    • 컴포넌트 및 로직 전환: 클래스 기반 컴포넌트를 함수형 컴포넌트와 훅(Hooks)으로 교체하고, TypeScript를 점진적으로 도입합니다 [2, 7].
    • 상태 관리 현대화: 불필요한 useEffect를 제거하고, 복잡한 전역 스토어를 대체하기 위해 서버 상태는 Tanstack Query로, 클라이언트 전역 상태는 Context나 Zustand로 역할을 분리합니다 [2].
    • 사용자 정의 훅 단위의 추출: 복잡한 컴포넌트 내부에 혼재된 로직을 사용자 정의 훅(Custom Hooks)으로 분리해 모듈화와 테스트 용이성을 극대화합니다 [1, 8].
    • 최적화 도구 정리: React 19와 같은 최신 버전을 활용할 경우, 코드를 어지럽히는 불필요한 useMemouseCallback 등을 제거할 수 있습니다 [9].
  • 비즈니스 로직 분석 및 코드 품질 표준화: 리팩터링 전 비즈니스 로직과 전역 UI 스토어의 역할을 완전히 이해하고, 전역 레벨에서 로컬 레벨로 분석을 좁혀 나가야 합니다 [8, 10]. 더불어 CSS 스타일 방식을 한 가지로 통일하고 [11, 12], ESLint(eslint-plugin-react 등)를 적용하여 코드 컨벤션을 강제함으로써 코드 스멜을 방지해야 합니다 [3].

⚖️ Trade-offs & Caveats

  • 전체 재작성(Rewrite) vs 점진적 마이그레이션: 코드베이스가 매우 작을 경우 완전히 처음부터 새로 작성하는 것이 빠르고 쉬울 수 있습니다 [5]. 그러나 복잡한 애플리케이션에서는 전체 재작성이 막대한 자원과 위험을 수반하므로, 기능 배포를 멈추지 않는 점진적 마이그레이션을 선택해야만 하는 제약이 따릅니다 [1].
  • TypeScript 도입에 따른 인지적 오버헤드: 리팩터링 시 TypeScript 도입은 장기적으로 오류를 줄여주지만, 경험이 부족한 팀원에게는 새로운 복잡성 레이어로 작용할 수 있습니다. 따라서 상황에 맞춰 단일 파일씩 점진적으로 변환하는 타협(Trade-off)이 필요합니다 [7].
  • 사전 테스트 작성의 비용: 기존 코드의 회귀(Regression)를 막기 위해 테스트 코드 작성이 강력히 권장되지만, 얽혀있는 기존 레거시 코드에 단위 테스트를 추가하는 작업은 초기 리팩터링 시간을 크게 지연시킬 수 있습니다 [4-6].
  • 계층형 아키텍처의 리팩터링 한계: 기존 레거시가 기능 기반이 아닌 기술적 유형(컴포넌트, 훅 등) 단위의 폴더로 나뉜 계층형 아키텍처(Layered Architecture)를 따를 경우, 단일 기능을 리팩터링할 때 관련된 여러 파일이 흩어져 있어 추적 및 수정이 극도로 번거로울 수 있습니다 [13].

🔗 Knowledge Connections

[아키텍처/기반 기술]

  • Feature-Sliced Design
    • 연결 이유: 레거시 코드베이스의 스파게티 코드를 해결하고, 의존성을 단방향으로 제한하여 확장 가능한 프로젝트 구조로 재편하는 현대적 아키텍처 방법론입니다 [14-16].
    • 이 개념을 통해 더 깊게 이해할 수 있는 부분: 리팩터링 중 컴포넌트 간 결합도를 줄이고 코드를 기능 및 비즈니스 도메인 단위로 명확하게 분리하는 방법을 학습할 수 있습니다 [15].
  • Custom Hooks
    • 연결 이유: React 리팩터링의 핵심 단위(Primary unit)로, 비즈니스 로직을 UI와 분리하는 도구입니다 [1, 17].
    • 이 개념을 통해 더 깊게 이해할 수 있는 부분: useFetchuseForm처럼 거대한 컴포넌트 속 반복되는 로직을 어떻게 단위 테스트 가능한 모듈로 추출할 수 있는지 이해할 수 있습니다 [17].

[구현/활용 도구]

  • TypeScript
    • 연결 이유: 노후화된 JavaScript 코드베이스를 현대화할 때 정적 타입 검사를 통해 런타임 오류를 방지하기 위해 필수적으로 권장되는 도구입니다 [2, 7].
    • 이 개념을 통해 더 깊게 이해할 수 있는 부분: 리팩터링 과정에서 발생할 수 있는 예기치 못한 데이터 구조 변화나 Props 전달 오류를 어떻게 컴파일 타임에 차단할 수 있는지 파악할 수 있습니다.
  • ESLint
    • 연결 이유: 리팩터링 시 팀의 일관성을 유지하고, 코드 스멜 및 안티 패턴을 자동으로 식별하기 위한 정적 분석 및 컨벤션 도구입니다 [3, 18].
    • 이 개념을 통해 더 깊게 이해할 수 있는 부분: eslint-plugin-react-hooks 등 플러그인을 활용해 아키텍처 규칙과 React 권장 사항을 개발 과정에서 어떻게 자동 강제할 수 있는지 확인할 수 있습니다 [3, 18].

Deeper Research Questions

  • 레거시 클래스형 컴포넌트의 생명주기 메서드(예: componentDidUpdate, componentDidMount)를 useEffect를 포함한 훅(Hooks) 기반으로 리팩터링할 때 가장 안전하게 부작용(Side-effect)을 제어하는 방법은 무엇인가?
  • 테스트 코드가 전무하고 컴포넌트 결합도가 높은 대규모 레거시 React 앱에서, 가장 먼저 도입해야 하는 효율적인 최소 단위 테스트 전략(예: UI 스냅샷 테스트 vs 기능 단위 테스트)은 무엇인가?
  • Context API로 무겁게 관리되어 리렌더링 이슈가 발생하는 전역 상태를 Zustand나 TanStack Query로 점진적으로 마이그레이션할 때, 전환 과정 중 상태의 동기화를 어떻게 유지할 수 있는가?
  • 하나의 컴포넌트 파일에 API 통신, 상태 변경, DOM 렌더링 로직이 혼재된 상태에서 단일 책임 원칙(SRP)을 준수하도록 로직을 쪼갤 때, 올바른 추상화 기준은 어떻게 세우는가?
  • 전체 앱을 중단하지 않고 React 버전을 올리거나 폴더 구조(Feature-Sliced Design 등)를 도입하기 위해, 기존 코드와 새로운 코드 아키텍처를 한 프로젝트 내에서 병존시키는 전략은 무엇인가?

Practical Application Contexts

  • Implementation: 기존에 방치된 useStateuseEffect를 활용한 데이터 페칭 로직을 Tanstack Query로 분리 및 이관하고, 인라인 스타일링이나 중구난방인 CSS를 특정 패턴 하나로 통일하는 실제적인 코드 정리 작업.
  • System Design: Redux에 의존하던 방대한 보일러플레이트를 제거하고, 애플리케이션의 상태를 '서버 상태(데이터 통신)'와 '클라이언트 상태(UI 토글 등)'로 설계적으로 분리함.
  • Operation / Maintenance: 기능 추가 프로세스를 멈추지 않고, 하나의 Store나 하나의 컴포넌트 단위로 분할하여 점진적으로 새 브랜치를 병합해가는 Git 기반의 무중단 리팩터링 파이프라인.
  • Learning Path: 레거시 React의 단점 분석 -> UI 및 단위 테스트 전략 수립 -> Custom Hooks 작성 및 SOLID 원칙 학습 -> 상태 관리 현대화 -> 폴더/아키텍처 설계 순으로 점진적인 심화 학습.
  • My Project Relevance: 오래전에 개발되어 유지보수성이 극도로 떨어지는 기존 프로젝트를 이어받아 기능 추가를 하거나 버그를 픽스해야 할 때, 코드를 안전하게 해체하고 모듈화하는 지침으로 활용.

Adjacent Topics

  • SOLID Principles
    • 확장 방향: 리팩터링 과정에서 각 컴포넌트와 모듈이 '단일 책임(SRP)'이나 '인터페이스 분리(ISP)' 원칙을 통해 어떻게 의존성을 낮추고 유연하게 구성될 수 있는지에 대한 심화 이해.
  • State Management
    • 확장 방향: 리팩터링 시 Redux, Context API, Zustand, TanStack Query 등 각각의 상태 관리 라이브러리가 가진 성능 특징(리렌더링 문제 해결 등)을 비교 분석하여 최적의 기술 스택을 선정하는 과정 탐구.

Last updated: 2026-04-30