본문 바로가기
IT

Claude Code 리팩토링 완전정리: 코드 구조 개선의 모든 것

by 샤나엘 2026. 3. 12.
반응형

Claude Code 리팩토링 완전정리: 코드 구조 개선의 모든 것

"이 파일이 500줄이 넘어서 관리가 안 돼", "콜백 지옥을 async/await로 바꾸고 싶어", "함수 이름을 전체 코드베이스에서 변경해야 해". Claude Code는 코드베이스 전체를 이해하고, 관련 파일을 모두 찾아 동시에 수정하며, 테스트로 동작을 검증합니다. 이 글에서는 Claude Code로 리팩토링하는 실전 기법을 완전 정리합니다.

Claude Code 리팩토링 완전정리


1. Claude Code가 리팩토링에 강한 이유

전체 코드베이스를 이해하는 에이전트

일반 에디터는 열린 파일 하나만 봅니다. Claude Code는 프로젝트 전체를 봅니다.

[일반 에디터]
  열린 파일 1개만 수정
  → 다른 파일의 참조는 수동으로 찾아야 함
  → 놓치면 런타임 에러

[Claude Code]
  프로젝트 전체 파일 검색 (Grep/Glob)
  → 모든 참조를 자동으로 찾음
  → 관련 파일을 동시에 수정
  → 테스트로 검증

리팩토링 에이전트 루프

1. 컨텍스트 수집
   └── 파일 구조, 의존성, import 관계 파악
        ↓
2. 영향 범위 분석
   └── Grep으로 모든 참조 검색
        ↓
3. 다중 파일 수정
   └── 관련 파일 동시 변경
        ↓
4. 테스트 실행
   └── 동작 변경 없음을 검증
        ↓
5. 반복 또는 완료

리팩토링에서의 핵심 강점

강점 설명
전체 참조 검색 Grep으로 함수/클래스의 모든 사용처 자동 발견
다중 파일 동시 수정 import, 호출부, 테스트를 한 번에 변경
동작 보존 구조만 바꾸고 기능은 그대로 유지
자동 테스트 변경 후 테스트 실행으로 회귀 방지
Hook 연동 수정 후 자동 포맷팅/린팅
Git 안전망 워크트리로 격리, 체크포인트로 되돌리기

Claude Code가 리팩토링에 강한 이유


2. Plan 모드로 리팩토링 전략 세우기

코드를 바꾸기 전에 분석부터

대규모 리팩토링은 Plan 모드에서 전략을 세운 후 실행하는 것이 안전합니다.

# Plan 모드로 시작
claude --permission-mode plan

리팩토링 계획 프롬프트

인증 시스템을 OAuth2로 리팩토링하려고 합니다.
다음을 분석해줘:
1. 현재 인증 관련 파일 목록
2. 변경이 필요한 파일과 범위
3. 데이터베이스 마이그레이션 필요 여부
4. 하위 호환성 유지 방안
5. 단계별 실행 계획
6. 리스크 평가

Claude가 만드는 리팩토링 계획

영향 분석:
  src/auth/login.ts       → 전면 수정 (OAuth2 플로우)
  src/auth/register.ts    → 전면 수정
  src/middleware/auth.ts   → 토큰 검증 로직 변경
  src/api/users.ts        → 인증 확인 방식 변경
  prisma/schema.prisma    → OAuthAccount 모델 추가
  tests/auth.test.ts      → 테스트 전면 수정

실행 계획:
  Phase 1: DB 스키마 변경 + 마이그레이션
  Phase 2: OAuth2 프로바이더 설정
  Phase 3: 로그인/회원가입 로직 교체
  Phase 4: 미들웨어 업데이트
  Phase 5: API 엔드포인트 수정
  Phase 6: 테스트 업데이트 + 검증

리스크:
  - 기존 세션 무효화 → 마이그레이션 스크립트 필요
  - 소셜 로그인 실패 시 폴백 필요

계획을 검토하고 Shift+Tab으로 일반 모드로 전환하여 구현합니다.

Plan 모드로 리팩토링 전략 세우기


3. 핵심 리팩토링 패턴

패턴 1: 이름 변경 (Rename)

전체 코드베이스에서 함수/변수 이름을 일괄 변경합니다.

getUserData 함수를 fetchUserProfile로
전체 코드베이스에서 변경해줘.
import, 호출부, 테스트 모두 포함.

Claude가 자동으로:

  1. Grep으로 모든 참조 검색
  2. 함수 정의, import, 호출부 동시 수정
  3. 테스트 파일도 업데이트
  4. 테스트 실행으로 확인

패턴 2: 함수 추출 (Extract)

큰 함수에서 반복되는 로직을 분리합니다.

checkout.ts에서 카드 유효성 검증 로직을
validatePaymentCard 함수로 추출해줘.
즉시결제와 구독결제 두 곳에서 사용해.

패턴 3: 파일 분리 (Split)

거대한 파일을 기능별로 분리합니다.

src/user.ts가 500줄이 넘어.
다음과 같이 분리해줘:
- src/user/model.ts (데이터 구조)
- src/user/service.ts (비즈니스 로직)
- src/user/validators.ts (유효성 검증)
모든 import를 업데이트해.

패턴 4: 통합 (Consolidate)

분산된 유틸리티를 하나로 합칩니다.

src/utils/string.ts, src/utils/array.ts,
src/utils/object.ts를 src/utils.ts로 통합해줘.
타입별로 정리하고 import를 업데이트해.

패턴 5: 레거시 마이그레이션

오래된 패턴을 최신 패턴으로 전환합니다.

모든 var 선언을 const/let으로 변환하고,
require()를 ES6 import로 교체해줘.

패턴 6: 성능 최적화

getUserWithPosts에서 N+1 쿼리 문제가 있어.
각 사용자마다 별도 쿼리 대신
JOIN으로 한 번에 가져오도록 리팩토링해줘.

핵심 리팩토링 패턴


4. 테스트 기반 리팩토링

테스트가 안전망이다

리팩토링의 핵심 원칙: 구조는 바꾸되, 동작은 바꾸지 않는다. 테스트가 이를 보장합니다.

테스트 우선 리팩토링 워크플로우

1단계: 현재 테스트 커버리지 확인
  > "인증 모듈의 테스트 커버리지를 확인해줘"

2단계: 부족한 테스트 추가
  > "빠진 엣지 케이스 테스트를 추가해줘"

3단계: 모든 테스트 통과 확인
  > npm test → 전부 통과

4단계: 리팩토링 실행
  > "이제 async/await로 리팩토링해줘"

5단계: 테스트 재실행
  > npm test → 전부 통과 확인

검증을 프롬프트에 포함

UserService.ts에서 비밀번호 검증 로직을
별도 함수로 추출해줘.

변경 후:
1. npm test -- UserService.test.ts 실행
2. 모든 테스트 통과 확인
3. 실패하면 수정 후 재실행
4. 전체 테스트 스위트도 실행

Hook으로 자동 테스트 실행

파일을 수정할 때마다 자동으로 관련 테스트를 실행하도록 설정할 수 있습니다.

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "npm test -- --bail"
      }]
    }]
  }
}

테스트가 실패하면 Claude가 즉시 인지하고 수정합니다.

테스트 기반 리팩토링


5. 대규모 리팩토링 전략

/batch로 코드베이스 일괄 변경

/batch 커맨드는 수십~수백 개 파일을 병렬로 수정합니다.

claude
/batch

# 작업 설명:
"모든 Redux connect()를 Redux Hooks로 마이그레이션.
mapStateToProps → useSelector
mapDispatchToProps → useDispatch
로 교체해줘."

/batch의 동작:

  1. 리서치: 변경 대상 파일 검색
  2. 계획: 마이그레이션 전략 수립
  3. 분할: 5~30개 에이전트로 파일 배분
  4. 병렬 실행: 각 에이전트가 워크트리에서 독립 작업
  5. 결과: 파일 그룹별 PR 생성

/batch에 적합한 작업

적합 부적합
함수명 일괄 변경 (100+ 파일) 복잡한 판단이 필요한 리팩토링
라이브러리 마이그레이션 파일 간 의존성이 복잡한 변경
린트 규칙 일괄 적용 빈번한 피드백이 필요한 작업
import 경로 일괄 변경  
타입 어노테이션 일괄 추가  

Git 워크트리로 안전한 병렬 리팩토링

# 터미널 1: 인증 리팩토링
claude --worktree auth-refactor

# 터미널 2: 결제 리팩토링
claude --worktree payment-refactor

# 터미널 3: 알림 리팩토링
claude --worktree notification-refactor

# 각 세션은 독립 브랜치에서 격리 작업
# 완료 후 개별 머지

서브에이전트로 병렬 분석

세 개 서비스를 병렬로 분석해줘:
1. 결제 서비스의 개선점
2. 알림 서비스의 개선점
3. 리포트 서비스의 개선점
각각 서브에이전트로 분석하고 결과를 보고해줘.

대규모 리팩토링 전략


6. Hook으로 자동화

수정 후 자동 포맷팅

Claude가 파일을 수정할 때마다 Prettier가 자동으로 실행됩니다.

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
      }]
    }]
  }
}

수정 후 자동 린팅

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "jq -r '.tool_input.file_path' | xargs npx eslint --fix"
      }]
    }]
  }
}

포맷팅 + 린팅 + 테스트 통합

리팩토링에 최적화된 Hook 설정:

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "FILE=$(jq -r '.tool_input.file_path') && npx prettier --write \"$FILE\" && npx eslint --fix \"$FILE\""
      }]
    }]
  }
}

이렇게 하면 Claude가 코드를 수정할 때마다:

  1. Prettier로 포맷팅
  2. ESLint로 린트 수정
  3. 결과가 자동 반영

Hook으로 자동화


7. CLAUDE.md로 리팩토링 규칙 적용

프로젝트 리팩토링 표준 정의

CLAUDE.md에 리팩토링 규칙을 정의하면 모든 세션에서 일관된 기준이 적용됩니다.

# CLAUDE.md - 리팩토링 규칙

## 코드 스타일
- ES 모듈 (import/export) 사용, CommonJS 금지
- async/await 사용, Promise.then() 금지
- const 기본, let 필요시만, var 절대 금지

## 리팩토링 기준
- 함수 최대 길이: 50줄
- 파일 최대 길이: 400줄
- 순환 복잡도 최대: 10
- 2곳 이상에서 사용되면 함수로 추출
- 파일당 하나의 주요 export

## 네이밍 규칙
- 함수: camelCase (getUserData)
- 상수: UPPER_SNAKE_CASE (MAX_RETRIES)
- 클래스: PascalCase (PaymentProcessor)

## 테스트 요구사항
- 리팩토링 후 반드시 테스트 실행
- 테스트 커버리지 유지 또는 향상
- 새 함수에는 테스트 추가

경로별 규칙 (.claude/rules/)

# .claude/rules/api-refactoring.md
---
paths:
  - "src/api/**/*.ts"
---

# API 리팩토링 규칙
- 모든 입력은 Zod로 검증
- 일관된 에러 응답 형식 사용
- 외부 호출에 타임아웃 추가
- DB는 커넥션 풀링 사용

CLAUDE.md로 리팩토링 규칙 적용


8. 실전 리팩토링 예제

예제 1: 콜백 → async/await

src/auth/ 디렉토리의 모든 Promise.then() 체인을
async/await로 변환해줘.
에러 핸들링 동작은 동일하게 유지해.

변환 전:

function getUser(id) {
  return db.query('SELECT * FROM users WHERE id = ?', [id])
    .then(rows => rows[0])
    .catch(err => { throw new Error('User not found'); });
}

변환 후:

async function getUser(id) {
  try {
    const rows = await db.query('SELECT * FROM users WHERE id = ?', [id]);
    return rows[0];
  } catch (err) {
    throw new Error('User not found');
  }
}

예제 2: 모놀리스 → 마이크로서비스

결제 처리 코드를 독립 서비스로 분리해줘:
1. 새 디렉토리 구조 생성
2. 결제 로직을 메인 앱에서 추출
3. 메시지 큐 통신 설정
4. 메인 앱에서 결제 서비스 호출로 변경
5. 테스트 추가 후 검증

예제 3: 클래스 → 함수형 컴포넌트

Header.tsx를 클래스 컴포넌트에서
함수형 컴포넌트 + Hooks로 마이그레이션해줘.
- componentDidMount → useEffect
- this.state → useState
- 같은 props 인터페이스 유지
- 테스트 업데이트

예제 4: N+1 쿼리 최적화

getUserWithPosts에서 N+1 쿼리를 수정해줘.

현재: 사용자 1회 조회 + 각 사용자마다 게시물 조회
수정: Prisma include로 한 번에 조회

성능 테스트도 추가해줘.

예제 5: JS → TypeScript 점진적 마이그레이션

src/services/UserService.js를 TypeScript로 마이그레이션해줘:
1. UserService.ts 생성
2. 타입 정의 추가
3. import 업데이트
4. 테스트 실행으로 동작 확인

 

실전 리팩토링 예제

 


9. 프롬프트 작성 베스트 프랙티스

좋은 리팩토링 프롬프트

✅ 구체적이고 측정 가능한 요청:

"validateEmail, validatePhone, validateZipCode에서
반복되는 검증 로직을 validateField(value, pattern)
함수로 추출해줘. 모든 호출부를 업데이트하고
테스트를 실행해."

나쁜 리팩토링 프롬프트

❌ 모호하고 방향이 불분명:

"코드를 좋게 만들어줘"
"인증 시스템을 개선해"
"데이터베이스 코드를 정리해"

리팩토링 프롬프트 템플릿

[대상] {컴포넌트}를 리팩토링
[이유] {문제점} 때문에
[범위] 영향 파일: {파일 목록}
[현재] {현재 상태 설명}
[목표] {목표 상태 설명}
[제약] {유지해야 할 동작}
[검증] {테스트 명령어}

/review로 리팩토링 기회 발견

claude
/review

# Claude가 분석:
# - "이 함수가 200줄, 분리 필요"
# - "validateEmail이 3곳에서 중복"
# - "PaymentProcessor와 BillingProcessor에 중복 로직"

프롬프트 작성 베스트 프랙티스


10. 자주 묻는 질문 (FAQ)

Q: 리팩토링 중 동작이 바뀌지 않는다는 걸 어떻게 보장하나요?
A: Claude Code가 변경 후 자동으로 테스트를 실행합니다. "테스트를 실행하고 실패하면 수정해줘"를 프롬프트에 포함하세요. Hook으로 자동 테스트 실행도 설정할 수 있습니다.

Q: 파일 수백 개를 동시에 변경할 수 있나요?
A: /batch 커맨드를 사용하면 5~30개의 병렬 에이전트가 각각 워크트리에서 독립적으로 작업합니다. 함수명 일괄 변경, 라이브러리 마이그레이션 등에 적합합니다.

Q: 리팩토링 도중 되돌리고 싶으면 어떻게 하나요?
A: Esc Esc를 눌러 마지막 체크포인트로 되돌릴 수 있습니다. Git 워크트리를 사용하면 메인 브랜치에 영향 없이 안전하게 실험할 수 있습니다.

Q: Plan 모드와 일반 모드를 언제 쓰나요?
A: 영향 범위가 크거나 전략이 필요한 리팩토링은 Plan 모드에서 분석 후, 일반 모드에서 구현합니다. 단순 이름 변경 같은 작업은 바로 일반 모드에서 진행해도 됩니다.

Q: CLAUDE.md에 리팩토링 규칙을 넣으면 자동으로 적용되나요?
A: 네. Claude Code는 세션 시작 시 CLAUDE.md를 자동 로딩합니다. 정의된 코드 스타일, 네이밍 규칙, 파일 크기 제한 등을 리팩토링 시 자동으로 따릅니다.

Q: 레거시 프로젝트의 점진적 마이그레이션도 가능한가요?
A: 네. JavaScript→TypeScript, 클래스→함수형, 콜백→async/await 등의 점진적 마이그레이션이 가능합니다. Plan 모드로 우선순위를 정하고 파일 단위로 점진적으로 진행합니다.

Q: 서브에이전트를 리팩토링에 어떻게 활용하나요?
A: 여러 모듈을 병렬로 분석할 때 유용합니다. 각 서브에이전트가 독립 컨텍스트에서 분석하므로 메인 컨텍스트가 깔끔하게 유지됩니다.


 

면책 조항: 이 글은 정보 제공 목적으로 작성되었습니다. Claude Code의 기능과 요금은 Anthropic의 정책에 따라 변경될 수 있으며, 최신 정보는 공식 문서를 확인해 주세요.

반응형

댓글