Codex 팁

레거시 코드 리팩토링을 Codex에게 안전하게 맡기는 절차: 테스트 먼저, 작게 쪼개기

레거시 코드를 Codex로 리팩토링할 때 필요한 테스트 우선 원칙과 작은 작업 단위, 검증 루프를 단계별로 정리합니다.

4분 읽기조코헌트 운영팀
목차

1. 리팩토링의 목표를 ‘변경’이 아니라 ‘보존’으로 정의하기

레거시 코드 리팩토링의 첫 목표는 코드를 예쁘게 만드는 일이 아닙니다. 이미 동작하는 기능을 유지하면서 구조만 바꾸는 것입니다. 이 기준을 Codex와 공유하지 않으면, 모델은 낡아 보이는 부분을 넓게 고치다가 동작 변경까지 섞을 수 있습니다.

먼저 고정할 동작

리팩토링을 시작하기 전에 “무엇이 지금처럼 동작해야 하는가”를 적어보세요. 예를 들면 로그인 실패 시 보여주는 메시지, 결제 완료 후 이동 경로, 특정 입력값의 예외 처리처럼 사용자가 실제로 경험하는 결과입니다. 내부 함수명이나 폴더 위치는 바뀌어도 되지만, 외부에서 관찰되는 결과는 유지한다는 식으로 경계를 정합니다.

성공 조건을 문장으로 쓰기

“서비스 코드를 개선해줘”보다 “OrderService의 할인 계산 로직을 분리하되, 기존 테스트 결과와 API 응답 형식은 유지해줘”가 안전합니다. 변경 범위, 유지할 계약, 실행할 검증 명령을 함께 적으면 작업 후 판단도 쉬워집니다.

2. 테스트가 없으면 관찰 테스트부터 만든다

대표 입력과 정상·경계·실패 케이스를 기록해 리팩토링 전후 동작을 비교하는 테스트 안전망 도식

테스트가 전혀 없는 파일을 곧바로 리팩토링하는 것은 지도 없이 건물 벽을 허무는 일과 비슷합니다. 완벽한 테스트 설계를 기다릴 필요는 없지만, 현재 동작을 기록하는 최소한의 안전망은 먼저 만들어야 합니다.

입력과 출력을 고정하기

함수나 API에 대표 입력을 넣고 반환값, 상태 코드, 저장 결과를 확인하는 테스트를 추가하세요. 내부 구현을 검증하기보다 “현재 이 입력은 이 결과를 낸다”를 기록하는 데 집중합니다. 정상 케이스 하나와 경계·실패 케이스 몇 개만 있어도 Codex가 바꿔도 되는 영역과 건드리면 안 되는 영역을 구분하는 데 도움이 됩니다.

테스트가 어려우면 실행 기록부터 남기기

외부 결제나 파일 시스템처럼 테스트가 복잡한 부분은 호출 전후의 값, 로그, 화면 결과를 체크리스트로 남겨도 됩니다. 이후 Codex에게 “리팩토링 전후에 이 관찰 결과가 같아야 한다”고 전달하세요. 테스트가 부족한 상태에서 큰 구조 변경을 요청하지 않는 것이 핵심입니다.

3. Codex에게는 한 번에 한 경계만 맡긴다

목표·범위·제약·검증으로 Codex 작업을 작은 책임 단위로 나누는 워크플로우 도식

작업 단위는 파일 개수가 아니라 책임의 경계로 나누는 편이 좋습니다. 먼저 함수 하나를 순수 함수로 분리하고, 다음 요청에서 이름을 정리하고, 그다음 중복 호출을 합치는 식입니다. 각 단계가 독립적으로 실행되고 되돌릴 수 있어야 합니다.

안전한 요청의 기본 구조

다음 네 가지를 프롬프트에 넣어보세요.

  • 목표: 어떤 책임을 분리하거나 단순화할지
  • 범위: 읽고 수정해도 되는 파일과 금지된 영역
  • 제약: 공개 API, 데이터 구조, 에러 메시지를 유지할지
  • 검증: 실행할 테스트·타입 체크·린트 명령

예시는 다음처럼 쓸 수 있습니다.

src/billing 안에서 할인 계산 로직만 별도 함수로 분리해줘. 공개 API와 반환 타입은 유지하고, 데이터베이스 스키마와 의존성은 변경하지 마. 먼저 관련 파일을 조사한 뒤 수정하고, 변경 이유와 실행한 검증 결과를 요약해줘.

프로젝트의 규칙이 있다면 AGENTS.md 작성법을 참고해 반복되는 제약을 문서화해두는 것도 좋습니다.

4. 매 단계마다 diff와 테스트를 함께 확인한다

diff 확인부터 테스트와 실제 흐름 확인까지 반복하는 리팩토링 검증 루프

Codex의 작업이 끝났다는 말보다 실제 변경량과 테스트 결과가 중요합니다. 작은 커밋 단위로 확인하면 문제가 생겼을 때 원인을 좁히기 쉽습니다.

diff에서 볼 것

요청하지 않은 파일이 바뀌지 않았는지, 함수 이름만 바뀌고 동작이 달라지지 않았는지, 예외 처리와 로깅이 사라지지 않았는지를 먼저 확인하세요. 특히 자동 포맷터가 만든 대규모 공백 변경은 실제 로직 검토를 어렵게 하므로 별도 변경으로 분리하는 편이 낫습니다.

검증 순서를 고정하기

가능하면 해당 모듈의 테스트부터 실행하고, 다음으로 타입 체크와 린트를 돌립니다. 마지막에는 실제 사용 흐름을 한 번 수동 확인하세요. 실패했다면 “고쳐줘”라고 넓게 재요청하기보다 실패 메시지, 기대 결과, 변경하면 안 되는 조건을 함께 전달해야 합니다. Codex로 코드 리뷰 받기처럼 diff 중심으로 검토하는 습관도 이 단계에 잘 맞습니다.

5. 이 신호가 보이면 작업을 멈추고 쪼갠다

다음 상황에서는 리팩토링을 계속 확장하지 말고 현재 변경을 정리하세요.

  • 테스트 실패 원인을 설명하지 못한 채 수정이 반복될 때
  • 한 요청에서 여러 도메인과 설정 파일이 동시에 바뀔 때
  • Codex가 요구사항에 없는 라이브러리 교체나 스키마 변경을 제안할 때
  • 테스트는 통과하지만 실제 사용자 흐름을 확인하지 않았을 때

이때는 변경을 되돌릴지 판단한 뒤, 마지막으로 동작이 확인된 지점에서 새 작업을 시작합니다. Codex 샌드박스와 승인 모드 이해하기도 자동 실행 범위를 정할 때 참고할 수 있습니다.

마지막으로 각 작업 전후에 아래 네 가지만 기록해보세요.

  • 바꾸려는 책임은 하나인가?
  • 유지해야 할 동작을 문장으로 썼는가?
  • 실패를 재현할 테스트나 관찰 기록이 있는가?
  • diff와 검증 결과를 직접 확인했는가?

레거시 리팩토링은 한 번의 대청소보다 작은 안전한 이동에 가깝습니다. Codex의 속도는 활용하되, 범위와 검증의 결정권은 계속 사람이 쥐고 있을 때 오래된 코드도 조금씩 다룰 수 있는 상태로 바뀝니다.

이 글 공유하기

같은 주제를 다룬 다른 글도 살펴보세요.