AI로 레거시 코드 리팩토링하기 — 실전 프롬프트 패턴
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 모킹)"
성과**
우리의 리팩토링 결과:
- 기간: 10년 코드 → 2개월 (예상 6개월)
- 코드량: jQuery 5000줄 → React 2000줄 (60% 감소)
- 성능: 페이지 로딩 시간 5초 → 1.2초
- 유지보수성: 코드 복잡도 50% 감소
마무리
AI로 레거시 코드를 리팩토링할 때의 핵심은 청크 단위 처리와 명확한 요구사항이다. 전체를 한 번에 주려고 하면 실패한다. 하지만 잘 정의된 단계별 프롬프트로 진행하면, AI는 정말 효율적인 리팩토링을 도와준다.
특히 타입 정의와 테스트를 AI에 맡기면, 개발자는 아키텍처와 비즈니스 로직에 집중할 수 있다.