Skip to main content

대규모 리팩터링이 무서운 이유는 단순합니다. 변경량이 커질수록 "어디서 망가졌는지"를 찾기 어려워지고, 리뷰·테스트·롤백 비용이 기하급수로 늘어납니다. 그래서 정답은 늘 같았습니다. 동작을 유지하는 작은 변환을 연속으로 쌓아 올리는 것, 그리고 매 단계에서 프로그램이 '작동하는 상태'로 남도록 만드는 것입니다.1

Codex는 이런 방식을 특히 잘 지원합니다. 한 번에 끝내려는 거대한 계획을 대신해, 작은 배치(batch)를 설계하고 그 배치를 끝까지 밀어붙이는 데 강합니다. 핵심은 "큰 리팩터링도 작은 배치로 나누면 안정적으로 끝까지 간다"는 원칙을 Codex의 작업 단위(세션, 승인, 자동 실행, 재개)에 정확히 맞추는 것입니다.

작은 배치가 대규모 리팩터링을 '완주'로 바꾸는 이유

리팩터링을 점진적으로 하면 위험이 줄고(테스트 범위가 좁아짐), 코드베이스가 안정된 채로 개선이 누적됩니다.2 또한 한 번의 커밋이 설명할 수 있는 목표를 가지면 리뷰가 쉬워지고, 실패했을 때 되돌릴 범위도 작아집니다.3

여기서 Codex의 역할은 두 가지입니다.

첫째, 작업을 쪼개는 설계자입니다. 코드를 읽고(의존성/호출 그래프/데이터 흐름) "어디서부터 잘라야 안전한지"를 제안합니다.

둘째, 각 배치를 끝내는 실행자입니다. 배치마다 필요한 코드 변경, 테스트 생성(또는 보강), 포맷/린트, 반복 실행을 일정한 리듬으로 수행합니다. '작은 단계'라는 원칙은 사람에게는 귀찮지만, 자동화에겐 가장 자연스러운 단위입니다.4

0단계: 범위 정의 — 무엇을 바꾸고, 무엇을 절대 안 바꿀 것인가

큰 작업을 시작하기 전에 범위를 텍스트로 고정하세요. 이 문서 한 장이 뒤로 갈수록 팀을 살립니다.

리팩터링은 "외부 동작을 바꾸지 않는 설계 개선"이 원칙이고, 기능 개발과 섞이면 리뷰 관점이 충돌해 비용이 커집니다.3 따라서 목표를 다음처럼 분리합니다.

  • 동작 보존(Behavior-preserving) 목표: 예) 클래스 책임 분리, 파일 이동, 의존성 역전, 네이밍 개선

  • 동작 변경 목표: 예) API 계약 변경, DB 스키마 변경, 권한 정책 변경

Codex에게는 목표를 섞지 않는 것이 특히 중요합니다. 세션마다 "이번 배치는 동작 보존인지/변경인지"를 선언하면, Codex가 테스트·승인·커밋 전략을 자동으로 맞춥니다.

1단계: 체크포인트 설계 — 매 커밋마다 '초록불'을 켜두기

대규모 리팩터링의 체크포인트는 거창하지 않아도 됩니다. 중요한 건 각 단계에서 컴파일되고, 테스트가 돌고, 되돌릴 수 있어야 한다는 점입니다.5

체크포인트를 설계할 때는 다음 순서를 추천합니다.

  1. 현재 동작을 고정하는 테스트(특히 레거시)

테스트가 부족한 코드라면 먼저 '특성화 테스트(characterization test)'로 현재 동작을 캡처합니다.6 이 테스트가 촘촘할수록 배치 크기를 키울 수 있고, 부족할수록 배치를 더 작게 잡아야 합니다.7

  1. 커밋을 작게, 그리고 단일 의도로

리팩터링 커밋은 리팩터링만, 기능 변경 커밋은 기능 변경만 담습니다.13 커밋 메시지에 '그리고(and)'가 들어가기 시작하면 대개 과적입니다.3

  1. 자동 실행 체크포인트

Codex에게는 "커밋 전 반드시 수행할 자동 점검"을 명확히 주면 좋습니다. 예를 들면 포맷 → 린트 → 유닛 테스트 →(필요 시) 통합 테스트 순으로 고정합니다.

2단계: 배치 쪼개기 — '수정'이 아니라 '이동'부터 시작하기

큰 리팩터링을 작은 배치로 쪼개는 가장 실용적인 방법은, 처음엔 의미를 바꾸지 않는 "구조만 바꾸는" 작업을 앞에 배치하는 것입니다.

예를 들어 "클래스가 너무 크다"는 문제를 다룰 때, 한 번에 재설계하지 말고 메서드들을 맥락별로 묶고 → 독립 클래스로 추출하고 → 의존성을 정리하는 식으로 아주 작은 단계로 진행합니다.5 이런 접근은 "변경을 쉽게 만든 다음, 쉬운 변경을 하라"는 원칙과도 맞닿아 있습니다.5

배치를 쪼갤 때 자주 쓰는 단위는 다음과 같습니다.

  • 파일/폴더 이동(동작 0 변경)

  • 이름 변경(동작 0 변경)

  • 작은 함수 추출(동작 0 변경)

  • 어댑터 추가(구 인터페이스 유지)

  • 호출부 점진적 전환(일부만 새 경로 사용)

  • 구 경로 제거(마지막 정리)

Codex에게 배치를 요청할 때는 "최종 목적"이 아니라 "이번 배치의 종료 조건"을 줘야 합니다.

예) "서비스 레이어를 분리해줘" 대신

예) "BillingService에서 결제수단별 분기 로직만 PaymentStrategy로 뽑고, 기존 public API 시그니처는 그대로 유지. 테스트는 기존 + 새 유닛 테스트 2개 추가. 커밋 2개로 나눠."

3단계: 파일 이동·인터페이스 유지 — '옮기는 동안에도' 사용자에게는 그대로

파일 이동이나 모듈 분리는 대개 "코드는 바뀌는데 동작은 안 바뀌어야" 합니다. 이때 핵심은 인터페이스를 '고정점'으로 두고, 내부 구현만 이동하는 것입니다.

실전 패턴은 간단합니다.

첫째, 구 인터페이스를 남겨두고 내부로 위임합니다.

예를 들어 old_module/foo.py의 함수가 new_module/foo.py로 이동해야 한다면, 먼저 새 파일을 만들고, 옛 경로는 얇은 래퍼로 남겨 둡니다. 호출자는 천천히 옮깁니다.

둘째, 호출부 전환은 기계적으로, 검증은 자동으로 합니다.

Codex는 이런 기계적 변경(임포트 경로 수정, 심볼 이름 변경, 반복 호출부 수정)을 빠르게 처리합니다. 대신 여러분은 "어디까지 바꾸고 멈출지(배치 경계)"와 "무엇으로 안전을 보장할지(테스트/체크포인트)"를 통제해야 합니다.

셋째, 폐기(삭제)는 항상 마지막 배치로 미룹니다.

이 원칙을 지키면, 중간에 문제가 생겨도 래퍼를 통해 빠르게 되돌릴 수 있습니다.

4단계: 마이그레이션(스키마·트래픽·시스템) — 공존 기간을 설계하기

리팩터링이 '코드 내부 구조'의 변화라면, 마이그레이션은 '운영 중인 시스템'의 변화입니다. 운영 중 변화의 공통 원칙은 구 시스템과 신 시스템이 한동안 공존하도록 만들고, 천천히 전환하며, 언제든 되돌릴 수 있게 하는 것입니다.89

점진적 스키마 마이그레이션(무중단)

스키마 변경은 보통 여러 단계로 나눕니다. 예를 들어 컬럼을 바꾸려면

  • 새 컬럼 추가

  • 백필(backfill)

  • 애플리케이션을 새 컬럼 사용으로 전환(필요 시 듀얼 라이트)

  • 일치 검증

  • 구 컬럼 제거

처럼 다단계로 진행합니다.8 이 방식은 "한밤중에 한 번에 교체" 같은 빅뱅을 피하게 해줍니다.9

Codex와의 궁합 포인트는 다음입니다.

  • 백필 스크립트 작성, 검증 쿼리 작성, 마이그레이션 단계별 체크리스트를 Codex에게 맡기기

  • 각 단계마다 롤백 조건(예: 불일치율, 에러율, 지연 시간)을 텍스트로 고정해 두기

트래픽/기능 점진 전환(카나리·프록시·스트랭글러)

점진 마이그레이션은 기능 단위(수직) 또는 사용자/조직 단위(수평)로 쪼개서 전환합니다.9 공통점은 "새 경로로 조금만 보내서 확인하고, 점점 늘린다"입니다.89

Codex는 여기서 전환 장치(Feature Flag, 라우팅, 어댑터)를 만드는 일을 잘합니다. 여러분은 어떤 단위를 기준으로 쪼갤지(예: 조직, 리전, 플랜, 퍼센트)만 결정하면 됩니다.

5단계: 성능 관점 점검 — 리팩터링은 종종 '느려지면서' 성공한다

구조를 바꾸는 동안, 성능은 흔히 잠깐 나빠집니다. 문제는 그 나빠짐이 "일시적인 부하"인지 "영구적인 회귀"인지 구분이 안 되면 끝까지 가기 어렵다는 점입니다.

따라서 배치마다 성능 체크포인트를 최소로라도 둡니다.

  • 기준선(변경 전) 벤치마크 1개

  • 변경 후 같은 벤치마크 1개

  • 임계치(예: p95 지연 10% 이상 악화 시 중단)

Codex에게는 "테스트는 통과했는데 성능이 떨어졌는지 확인"하는 자동 실행을 맡기세요. 특히 파일 이동/추상화 도입 같은 변화는 눈에 띄지 않게 핫패스를 느리게 만들 수 있습니다.

6단계: 보안 관점 점검 — 리팩터링은 취약점을 '옮겨 심을' 수 있다

리팩터링이 항상 보안을 개선하는 것은 아닙니다. 정보 은닉, 캡슐화, 접근 경로가 바뀌면서 보안 메트릭이 좋아질 수도, 나빠질 수도 있습니다.10

그래서 배치마다 다음을 최소 점검 항목으로 두는 것이 좋습니다.

  • 비밀정보(키/토큰/연결 문자열)가 코드·로그·테스트 픽스처에 새로 등장하지 않았는지

  • 인증/인가 경로가 우회 가능해지지 않았는지

  • 입력 검증이 빠지거나 중복으로 적용되어 로직이 꼬이지 않았는지

  • 의존성 업데이트로 알려진 취약점이 유입되지 않았는지

일반적인 보안 권장사항으로는 정적 분석과 코드 리뷰, 접근 제어 검증, 암호화, 의존성 점검, 안전한 설정/시크릿 관리, 로깅/모니터링, 침투 테스트 등이 반복적으로 강조됩니다.11

Codex는 여기서 "체크리스트 실행자"로 쓰기 좋습니다. 예를 들어 PR 설명에 포함할 보안 영향 요약, 변경된 인증/인가 경로 목록, 새로 추가된 외부 호출 목록을 자동으로 뽑게 할 수 있습니다.

Codex로 진행하는 '작은 배치 리팩터링' 루프

아래 루프를 한 배치의 기본 단위로 삼으면, 큰 작업도 끝까지 갈 확률이 급격히 올라갑니다.

  1. 계획: 이번 배치의 범위(바꿀 것/안 바꿀 것), 종료 조건, 롤백 경로를 한 문단으로 적는다.

  2. 안전망: 부족한 테스트를 특성화 테스트로 보강한다.6

  3. 변환: 한 가지 변화만 한다(추출, 이동, 이름 변경 등).4

  4. 검증: 테스트/린트/필요 시 벤치마크를 자동 실행한다.5

  5. 커밋: 리팩터링 커밋은 리팩터링만 담는다.13

  6. 기록: 다음 배치에 남은 일을 짧게 남긴다(세션 재개가 쉬워진다).

Codex 프롬프트 예시(리팩터링/마이그레이션)

아래 예시는 "적게 말하고 정확히" 지시하는 스타일을 기준으로 작성했습니다.

1) 배치 계획 만들기(리팩터링)

레포를 스캔해서 ReconciliationIntro(또는 유사하게 비대해진 클래스)를 책임 단위로 쪼개는 리팩터링 계획을 제안해줘. 조건: (1) 각 단계에서 컴파일/테스트 통과, (2) 커밋은 단계당 1개 목표, (3) 외부 동작 변경 금지, (4) 먼저 '이동/추출' 위주로 설계.

이 요청은 "작은 단계로 이동"과 "항상 테스트가 돌아야 한다"는 원칙을 Codex에게 강하게 각인합니다.54

2) 파일 이동 + 호환성 래퍼(인터페이스 유지)

src/legacy/auth.py의 공개 함수들을 src/security/auth/로 이동하자. 이번 배치 목표는 '동작 0 변경'이야. 옛 경로에는 deprecated 래퍼를 남기고, 새 경로로 위임하게 해줘. 임포트 경로 수정은 하지 말고, 테스트만 추가/수정해서 통과시켜. 커밋 1개로 끝내.

3) 스키마 점진 마이그레이션 플랜(무중단)

users.email을 users.primary_email로 바꾸고 싶다. 무중단으로 진행해야 해. 단계별 SQL(추가/백필/검증/전환/제거), 애플리케이션 변경(듀얼 라이트 포함 가능), 롤백 전략을 문서로 정리해줘.

점진적 스키마 마이그레이션은 다단계 전환과 검증, 빠른 롤백을 전제로 합니다.8

4) 성능·보안 영향 요약 생성(PR 보조)

이번 배치 변경(diff 기준)을 보고, 성능에 영향 줄 수 있는 핫패스 후보 5개와 그 이유를 적어줘. 그리고 보안 관점에서 점검해야 할 항목(인증/인가, 입력 검증, 시크릿, 의존성)별로 변경된 파일/함수를 매핑해줘.

리팩터링이 보안에 미치는 영향은 단순하지 않으므로, '영향 요약 + 체크리스트' 형태로 반복 점검하는 편이 안전합니다.1011

마무리: 큰 리팩터링을 끝내는 사람의 습관

대규모 리팩터링·마이그레이션은 실력보다 완주를 가능하게 하는 구조가 더 중요합니다. 점진적으로 바꾸고, 항상 동작하는 상태를 유지하고, 커밋을 작게 쪼개고, 테스트·성능·보안을 매 단계에서 확인하면 됩니다.2541 Codex는 이 루틴을 "지치지 않고" 반복 실행해 주는 도우미입니다.

다음 챕터에서는 이 루틴을 더 강하게 만들어 주는 무기, 즉 테스트를 '생성하고 유지하는' 방법으로 넘어갑니다.

참고

1How to refactor

2Refactor Incrementally: Why Small Changes Matter

3Refactor and make changes in different commits - Jake Goulding

4Refactoring Without Fear: Small Steps That Work

5Refactoring: This class is too large

6How to Refactor Complex Codebases – A Practical Guide for Devs

8Incremental Schema Migrations | ArchMan

9Why all application migrations should be incremental

10Refactoring Codes to Improve Software Security Requirements

11What are some important security measures during application refactoring?

책 목록

OpenAI Codex 활용법: IDE·CLI·클라우드에서 코딩 에이전트로 일하기

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기