AI로 레거시 코드 리팩토링하기 — 실전 프롬프트 패턴

게시일: 2025년 7월 11일 · 15분 읽기

10년 된 코드와의 전쟁

우리 회사엔 10년 된 jQuery 코드가 있었다. 기능은 하지만, 유지보수가 어렵고 성능도 떨어진다. React로 마이그레이션하려고 했지만, 규모가 너무 컸다. 전체 리팩토링에만 6개월이 걸릴 것 같았다.

Claude를 활용해서 2개월로 줄였다. 비결은 좋은 프롬프트다.

청크 단위로 분석하기

전체 코드를 한 번에 주면 AI가 이해하지 못한다. 청크로 나눠서 처리한다:

<?xml version="1.0"?>
// 나쁜 예: 전체 코드
"$('#header').click(function() { ... })
$('#sidebar').toggle()
...
// 1000줄"

// 좋은 예: 기능별로 분리
"유저 인증 관련 코드만 React로 변환해줘

현재 코드:
<script>
  $('#login-form').on('submit', function() {
    const username = $('#username').val()
    const password = $('#password').val()
    $.post('/api/login', {
      username: username,
      password: password
    }, function(data) {
      localStorage.setItem('token', data.token)
      window.location.href = '/dashboard'
    })
  })
</script>

요구사항:
- React Hooks 사용
- TypeScript
- Error handling 추가
- Loading state 포함"

컨텍스트 설정

AI가 팀의 규칙을 따르도록:

<?xml version="1.0"?>
"우리 팀의 코딩 스타일:
- TypeScript strict 모드
- React Hooks (클래스 컴포넌트 X)
- tailwindCSS로 스타일링
- API 호출은 /lib/api.ts의 함수 사용
- 에러 처리는 항상 try-catch
- 로딩 상태는 isLoading boolean 사용
- 테스트는 vitest로 작성

폴더 구조:
src/
  components/     # React 컴포넌트
  pages/          # 페이지 컴포넌트
  lib/
    api.ts        # API 호출 함수들
    hooks.ts      # 커스텀 훅
  types/
    index.ts      # TypeScript 타입

이제 다음 코드를 React로 변환해줘:"

마이그레이션 전략

큰 프로젝트의 경우 단계별 진행:

<?xml version="1.0"?>
1단계: 컴포넌트 구조 설계
"jQuery 코드를 분석해서 React 컴포넌트 구조를 제안해줘.
현재 HTML 구조:
<div id="app">
  <header id="main-header">
    <nav id="navbar">...</nav>
  </header>
  <main>
    <sidebar id="left-sidebar">...</sidebar>
    <content id="main-content">...</content>
  </main>
</div>

컴포넌트 구조 제안 + 데이터 흐름도"

2단계: 타입 정의
"위 구조에 필요한 TypeScript 타입을 정의해줘.
- 각 컴포넌트의 props
- 전역 상태 타입
- API 응답 타입"

3단계: 개별 컴포넌트 변환
"Header 컴포넌트를 React로 변환해줘.
(이미 정의된 타입과 구조 사용)"

4단계: 상태 관리
"이 컴포넌트들의 상태 관리를 위해 필요한 hooks를 만들어줘"

5단계: 통합
"모든 컴포넌트를 통합하는 App.tsx를 작성해줘"

구체적인 예제

<?xml version="1.0"?>
// jQuery 원본
$(document).ready(function() {
  $('#products-list').on('click', '.product-item', function() {
    const productId = $(this).data('id')
    const name = $(this).find('.product-name').text()
    const price = $(this).find('.product-price').text()

    $('#product-detail').html(
      `<h2>${name}</h2><p>$${price}</p>`
    )

    $.get(`/api/products/${productId}`, function(data) {
      $('#product-desc').html(data.description)
      $('#add-to-cart').data('product-id', productId)
    })
  })

  $('#add-to-cart').on('click', function() {
    const productId = $(this).data('product-id')
    $.post('/api/cart', { product_id: productId }, function() {
      alert('Added to cart!')
    })
  })
})

// 좋은 프롬프트
"이 jQuery 코드를 React로 변환해줘.

요구사항:
1. ProductList와 ProductDetail 두 개 컴포넌트로 분리
2. 상태는 useProductStore (Zustand) 사용
3. API 호출은 /lib/api/products.ts의 함수 사용
4. TypeScript 타입 포함
5. 에러 처리 추가
6. Loading 상태 표시
7. tailwindCSS로 스타일링

참고: Product 타입은 이미 있음
type Product = {
  id: number
  name: string
  price: number
  description: string
}"

QA와 검증

변환 후 검증 프롬프트:

<?xml version="1.0"?>
"이 React 컴포넌트를 검토해줘.

체크리스트:
- TypeScript 타입이 정확한가?
- 메모리 누수 위험은 없는가? (useEffect cleanup)
- 에러 핸들링이 충분한가?
- 접근성 (a11y)은 고려했는가?
- 성능 문제는 없는가? (불필요한 re-render)
- 테스트하기 쉬운 구조인가?

문제가 있으면 수정 코드를 제시해줘."

테스트 자동 생성

React 컴포넌트는 테스트도 필요하다:

<?xml version="1.0"?>
"이 ProductDetail 컴포넌트에 대한 vitest 테스트를 작성해줘.

테스트 항목:
1. 컴포넌트 마운트 시 API 호출
2. 데이터 로딩 중 로딩 표시
3. API 에러 시 에러 메시지 표시
4. 'Add to Cart' 버튼 클릭 시 cart API 호출
5. API 응답 데이터 정확히 표시

사용 라이브러리:
- vitest
- @testing-library/react
- msw (API 모킹)"

성과**

우리의 리팩토링 결과:

마무리

AI로 레거시 코드를 리팩토링할 때의 핵심은 청크 단위 처리와 명확한 요구사항이다. 전체를 한 번에 주려고 하면 실패한다. 하지만 잘 정의된 단계별 프롬프트로 진행하면, AI는 정말 효율적인 리팩토링을 도와준다.

특히 타입 정의와 테스트를 AI에 맡기면, 개발자는 아키텍처와 비즈니스 로직에 집중할 수 있다.

iL
ian.lab

실무 개발자입니다. 현장에서 겪은 문제와 해결 과정을 기록합니다. 오류 제보는 연락처로 보내주세요.