PromptRecipe 로고PromptRecipe
메뉴

프롬프트 작성법

AI로 코드 리팩토링과 가독성 개선 프롬프트 작성하는 법

AI 코딩 도구에 코드 리팩토링을 요청할 때 구조, 가독성, 안정성을 함께 높이는 실전 프롬프트 작성법과 예시를 소개합니다.

소개

코드가 동작한다고 해서 항상 좋은 코드는 아닙니다. 기능 추가와 빠른 수정이 반복되면 조건문은 길어지고, 이름은 모호해지며, 하나의 함수가 여러 책임을 떠안게 됩니다. 이때 AI 코딩 도구는 단순한 자동 완성기를 넘어 코드의 구조를 관찰하고 개선안을 제안하는 협업자가 될 수 있습니다. 다만 “이 코드를 리팩토링해 줘”라는 짧은 요청만으로는 원하는 결과를 얻기 어렵습니다. AI는 무엇을 유지해야 하는지 무엇을 우선 개선해야 하는지 어디까지 바꿔도 되는지를 프롬프트에서 알아야 합니다.

이 가이드는 ChatGPT, Claude, Cursor, GitHub Copilot 등 어떤 AI 코딩 도구에도 적용할 수 있는 리팩토링 프롬프트 설계 원칙을 다룹니다. 목표는 코드를 무조건 짧게 만드는 것이 아니라 미래의 내가 그리고 팀원이 더 빠르고 안전하게 읽고 수정할 수 있게 만드는 것입니다. 좋은 리팩토링은 동작을 바꾸지 않고 이해 비용을 낮추는 작업입니다.

핵심 개념

리팩토링과 재작성은 다릅니다

리팩토링은 외부에서 관찰되는 기능을 유지한 채 내부 구조를 개선하는 활동입니다. 반면 재작성은 구현 방식, 라이브러리, 아키텍처 또는 기능 자체를 크게 바꿀 수 있습니다. AI에게 요청할 때 이 차이를 명확히 하지 않으면 보기에는 현대적이지만 기존 예외 처리나 경계 조건을 잃은 코드가 나올 수 있습니다.

따라서 프롬프트에는 “동작과 공개 API를 유지하라”, “의존성 추가를 금지하라”, “테스트가 있다면 통과해야 한다”처럼 변경 범위를 제한하는 문장을 넣는 것이 좋습니다. 리팩토링 요청에는 반드시 ‘유지해야 할 계약’을 먼저 적으세요. 계약에는 함수의 입력과 반환값, 오류 형식, 성능 기준, 외부 호출 순서, 기존 타입 정의 등이 포함될 수 있습니다.

가독성은 취향보다 의사결정 속도에 가깝습니다

가독성이 좋은 코드는 예쁜 코드라는 뜻에만 머물지 않습니다. 변수와 함수 이름만 보고도 의도가 보이고, 한 블록에서 처리하는 책임이 명확하며 예외 흐름을 쉽게 추적할 수 있어야 합니다. 특히 실무에서는 코드 작성자보다 수정자가 더 많은 시간을 쓰므로, “왜 이렇게 구현했는가”를 드러내는 구조가 중요합니다.

AI에 가독성 개선을 요청할 때는 막연히 “깔끔하게”라고 말하기보다 구체적인 평가 기준을 제시하세요. 예를 들어 중첩 조건문 축소, 의미 있는 이름 부여, 중복 로직 추출, 매직 넘버 상수화, 조기 반환 적용, 오류 메시지 개선, 함수 길이 축소처럼 관찰 가능한 기준을 사용합니다. ‘깔끔하게’ 대신 검증 가능한 개선 기준을 나열하는 것이 핵심입니다.

코드 맥락이 답변의 품질을 결정합니다

AI는 파일 하나만 보고도 개선안을 만들 수 있지만 코드가 어떤 환경에서 실행되는지 모르면 잘못된 가정을 할 수 있습니다. 언어와 버전, 프레임워크, 런타임, 스타일 규칙, 성능 민감도, 기존 테스트 여부를 함께 전달하세요. 예를 들어 TypeScript 프로젝트라면 strict 설정 여부와 타입 변경 허용 범위를 알려 주는 편이 좋습니다. React 코드라면 렌더링 최적화가 실제로 필요한지, 서버 컴포넌트인지도 결과에 영향을 줍니다.

또한 AI가 모르는 정보는 추측하지 않도록 지시해야 합니다. “확신할 수 없는 요구사항은 변경하지 말고 질문 또는 가정 목록으로 분리해 달라”는 문장을 넣으면 과도한 리팩토링을 줄일 수 있습니다.

단계별 가이드

1단계: 현재 코드의 문제를 먼저 관찰합니다

리팩토링을 시작하기 전, 코드가 왜 읽기 어려운지 짧게 기록해 보세요. 함수가 지나치게 길다, 변수명이 data, result, temp처럼 일반적이다, 동일한 유효성 검사가 여러 곳에 있다, 조건문 깊이가 깊다, 오류가 조용히 무시된다는 식으로 정리하면 됩니다. 이 목록은 AI에게 주는 작업 명세가 됩니다.

이때 모든 문제를 한 번에 해결하려고 하지 않는 편이 좋습니다. 하나의 프롬프트에서 구조 분리, 타입 재설계, 성능 최적화, 라이브러리 교체, 테스트 추가까지 요구하면 결과를 검토하기 어려워집니다. 한 번의 요청에는 한 가지 중심 목표를 두고 변경 폭을 관리하세요.

2단계: 변경 금지 조건을 명시합니다

AI가 코드의 동작을 바꾸지 않도록 경계선을 설정합니다. 외부에 노출된 함수명과 반환 타입을 유지할지, 새 패키지 설치를 허용할지, 데이터베이스 쿼리 횟수를 바꾸어도 되는지 기존 오류 메시지를 유지해야 하는지 등을 적습니다. 이 조건은 리팩토링의 안전장치입니다.

다음 문장을 기본 템플릿으로 활용할 수 있습니다.

다음 코드를 리팩토링해 주세요.
기능, 입력값, 반환값, 오류 동작과 공개 API는 유지해야 합니다.
새 의존성은 추가하지 말고, 확실하지 않은 요구사항은 추측해서 변경하지 마세요.
먼저 문제점을 분석한 뒤, 개선된 전체 코드와 변경 이유를 제시해 주세요.

프로젝트의 규칙이 있다면 이어서 덧붙입니다. 예를 들어 “TypeScript strict 모드를 유지하세요”, “eslint 규칙을 위반하지 마세요”, “함수형 스타일보다 현재 클래스 구조를 존중하세요”처럼 팀의 일관성을 보장하는 제약을 지정할 수 있습니다.

3단계: 원하는 개선 기준을 우선순위로 전달합니다

같은 코드도 어떤 기준을 앞세우는지에 따라 결과가 달라집니다. 급하게 장애를 줄여야 한다면 예외 처리와 입력 검증이 우선입니다. 신규 팀원이 빠르게 이해해야 한다면 명확한 이름과 작은 함수가 우선입니다. 성능 병목이 의심된다면 측정 전제와 복잡도 분석이 필요합니다.

추천하는 요청 구조는 “반드시 개선할 항목”, “가능하면 개선할 항목”, “변경하지 말 항목”의 세 구획입니다. 예를 들어 반드시 항목에는 중첩 제거와 중복 유효성 검사 통합을 넣고 가능하면 항목에는 주석 개선을 넣으며, 변경 금지 항목에는 함수 시그니처와 응답 JSON 형식을 넣습니다. 우선순위를 주면 AI의 제안이 프로젝트 목적에서 벗어나는 일을 줄일 수 있습니다.

4단계: 결과 형식을 지정해 검토 가능하게 만듭니다

코드만 바로 출력하게 하면 변경점 파악에 시간이 듭니다. 먼저 진단, 이어서 변경 계획, 개선 코드, 마지막으로 변경 요약과 위험 요소를 출력하게 요청하세요. 수정 전후 차이를 보고 싶다면 unified diff 형식을 요청할 수도 있습니다. 큰 파일이라면 전체 재출력보다 함수별 패치와 영향 범위를 받는 편이 안전합니다.

검토용 프롬프트에는 “각 변경이 어떤 문제를 해결하는지 한 문장으로 설명하라”, “동작이 달라질 가능성이 있는 부분을 별도 표기하라”, “추가해야 할 테스트 케이스를 제안하라”를 포함하세요. AI의 결과물은 코드 생성물보다 검토 가능한 변경 제안서로 받아야 합니다.

5단계: 테스트와 리뷰 프롬프트를 이어서 사용합니다

리팩토링 결과를 받은 뒤에는 곧바로 적용하지 말고, 같은 AI에게 회귀 위험을 점검하게 하세요. 원본 코드와 개선 코드를 함께 제공하고 동작 차이와 누락된 엣지 케이스를 찾아 달라고 요청합니다. 기존 테스트가 있다면 변경 이후에도 의미가 유지되는지 검토하고 없다면 핵심 경로 중심의 테스트 시나리오를 먼저 작성하게 합니다.

마지막으로 사람이 직접 diff를 읽어야 합니다. AI는 문맥에 없는 운영 제약, 팀의 암묵적 합의, 실제 사용자 데이터의 특성을 알지 못합니다. 테스트 통과는 필요조건일 뿐, 변경 의도를 이해하는 리뷰를 대체하지 않습니다.

실전 예시

예시 1: 긴 함수의 책임 분리

주문 정보를 검증하고 할인 금액을 계산하고 결제를 요청하고 로그까지 남기는 함수가 있다고 가정해 보겠습니다. 이런 함수는 한 줄을 수정할 때 다른 단계에 영향을 줄 가능성이 커서 읽기 어렵습니다. 다음과 같이 요청할 수 있습니다.

아래 TypeScript 주문 처리 함수를 리팩토링해 주세요.

목표:
- 한 함수에 섞인 입력 검증, 가격 계산, 결제 요청, 로깅 책임을 분리
- 중첩 if를 조기 반환으로 줄이기
- 모호한 변수명을 도메인 의미가 드러나는 이름으로 변경

제약:
- processOrder의 함수 시그니처와 반환 객체 형식은 변경 금지
- 결제 API 호출 순서와 오류 메시지는 유지
- 새 라이브러리 추가 금지

출력 순서:
1. 현재 코드의 가독성 및 유지보수 문제 3~5개
2. 리팩토링 전략
3. 개선된 전체 코드
4. 추가하면 좋은 테스트 케이스

[코드 붙여넣기]

이 프롬프트는 AI가 단순히 함수를 잘게 나누는 데 그치지 않고 어떤 책임을 분리했는지 설명하게 만듭니다. 특히 결제 API 호출 순서와 오류 메시지를 보존한다는 제약은 서비스 동작이 우연히 달라지는 일을 막아 줍니다.

예시 2: 조건문과 중복 로직 정리

사용자 권한에 따라 화면 데이터를 구성하는 코드에는 비슷한 조건이 여러 번 등장하기 쉽습니다. 이 경우에는 “조건을 줄여 달라”보다 정책을 명시적으로 표현해 달라고 요청하는 편이 낫습니다.

다음 JavaScript 코드를 가독성 중심으로 리팩토링해 주세요.

개선 기준:
- 반복되는 역할(role) 비교를 한 곳으로 모으기
- boolean 플래그가 무엇을 뜻하는지 이름으로 드러내기
- 조건문 깊이를 2단계 이하로 낮추기
- 현재 결과값과 예외 동작은 완전히 유지하기

주의:
- 역할 체계를 새로 설계하거나 권한 정책을 변경하지 마세요.
- 코드가 짧아지는 것보다 읽는 사람이 의도를 이해하기 쉬운 것을 우선하세요.
- 변경 전후의 조건 판단이 동일한지 사례를 들어 설명하세요.

[코드 붙여넣기]

여기서 중요한 점은 역할 체계를 바꾸지 말라고 지정한 부분입니다. AI는 종종 enum, 권한 매트릭스, 정책 객체 같은 더 큰 구조를 제안할 수 있습니다. 그것이 장기적으로 유익할 수는 있지만 현재 목표가 안전한 가독성 개선이라면 범위를 분리하는 것이 좋습니다.

예시 3: 이름과 주석을 개선하는 저위험 요청

프로덕션 코드에 큰 구조 변경을 적용하기 어렵다면 먼저 이름과 설명을 개선하는 작은 리팩토링부터 시작할 수 있습니다.

아래 코드를 동작 변경 없이 읽기 쉽게 다듬어 주세요.

- 변수, 함수, 매개변수 이름을 도메인 의미가 분명하게 바꾸세요.
- 구현을 반복하는 주석은 제거하고 이유나 제약을 설명하는 주석만 제안하세요.
- 매직 넘버와 문자열 중 재사용되거나 의미가 불분명한 값은 상수 후보로 표시하세요.
- 이름 변경으로 외부 호출부 수정이 필요한 항목은 별도 목록으로 알려 주세요.

[코드 붙여넣기]

이 방식은 변경 위험이 낮고 팀의 네이밍 규칙을 정리하는 출발점으로도 좋습니다. 단, 널리 사용되는 공용 함수의 이름을 바꿀 경우에는 호출부 전체를 함께 확인해야 합니다.

프로 팁과 트러블슈팅

AI가 과하게 현대화할 때

AI가 익숙한 최신 패턴이나 라이브러리로 코드를 바꾸려는 경우가 있습니다. 예를 들어 단순한 유틸리티 함수에 불필요한 추상화 계층을 만들거나, 기존 프로젝트와 다른 스타일을 도입할 수 있습니다. 이때는 “현재 프로젝트의 패턴을 우선 따르고, 새로운 아키텍처 제안은 코드 변경과 분리해 선택 사항으로만 제시하라”고 요청하세요.

현재 문제를 해결하는 최소 변경과 장기 개선 제안을 분리해 받으세요. 최소 변경은 바로 리뷰할 수 있고 장기 개선은 팀 논의의 재료가 됩니다. 두 결과를 섞으면 작은 리팩토링이 예측하기 어려운 구조 개편으로 커질 수 있습니다.

코드가 너무 짧아져 이해하기 어려울 때

가독성 개선을 요청했는데 체이닝, 복잡한 삼항 연산자, 지나친 함수형 표현 때문에 오히려 읽기 어려워지는 경우도 있습니다. 이때 “한 줄로 줄이는 것을 목표로 하지 말 것”, “복잡한 조건은 이름 있는 boolean 변수로 분리할 것”, “팀의 중급 개발자가 디버깅하기 쉬운 명시적 제어 흐름을 선호할 것”이라고 구체적으로 지시하세요.

특히 조기 반환은 중첩을 줄이는 데 유용하지만 너무 많은 반환 지점이 리소스 정리나 로깅 순서를 헷갈리게 만들 수 있습니다. try/finally가 필요한 코드나 트랜잭션 경계가 있는 코드는 제어 흐름을 바꾸기 전에 정리 보장 조건을 먼저 확인해야 합니다.

타입 변경으로 숨은 오류가 생길 때

TypeScript 리팩토링에서는 any를 제거하거나 타입을 좁히는 과정이 유익하지만 외부 데이터의 불확실성을 타입만으로 해결하려 해서는 안 됩니다. API 응답이나 사용자 입력처럼 신뢰할 수 없는 값은 런타임 검증이 필요합니다. AI에게 “컴파일 오류를 없애기 위해 강제 단언이나 any를 추가하지 말고, 필요한 경우 검증 경계를 제안하라”고 요청하면 더 견고한 결과를 받을 수 있습니다.

또한 타입을 더 정밀하게 바꾸면 기존 호출부가 깨질 수 있습니다. 따라서 공개 타입 변경은 별도 작업으로 분리하고 호환성이 필요한 경우에는 마이그레이션 단계와 deprecated 처리 방안까지 함께 검토하세요.

프롬프트 결과를 신뢰하기 어려울 때

AI가 제시한 코드가 맞는지 확신이 없다면 답을 다시 생성해 달라고 하기보다 검증 역할을 분리하세요. 첫 번째 요청은 리팩토링, 두 번째 요청은 비판적 코드 리뷰, 세 번째 요청은 테스트 설계로 나누면 각 단계의 목적이 분명해집니다. 동일한 AI를 사용하더라도 “이제 작성자가 아니라 엄격한 리뷰어로 행동하라”고 역할을 바꾸면 놓친 위험을 발견하는 데 도움이 됩니다.

검증 프롬프트 예시는 다음과 같습니다.

원본 코드와 리팩토링된 코드를 비교해 주세요.
기능 동작이 달라질 수 있는 부분, 예외 처리 누락, null/undefined 경계 조건,
성능 저하 가능성, 외부 API 계약 변경 가능성을 우선적으로 찾아 주세요.
문제가 없다고 단정하지 말고, 확인이 필요한 가정도 목록으로 분리해 주세요.

결론

AI를 활용한 리팩토링의 성패는 모델이 얼마나 많은 코드를 생성하느냐가 아니라 사람이 얼마나 명확한 판단 기준을 제공하느냐에 달려 있습니다. 현재 코드의 문제를 관찰하고 기능적으로 유지해야 할 계약을 정하고 개선 우선순위와 출력 형식을 지정하면 결과의 품질과 안전성이 크게 높아집니다.

처음에는 작은 함수 하나, 반복되는 조건문 하나, 모호한 이름 묶음처럼 검토하기 쉬운 범위부터 시작하세요. 개선된 코드를 테스트와 diff로 확인하는 습관을 쌓으면, 이후에는 모듈 분리나 복잡한 도메인 로직 정리에도 AI를 더 자신 있게 활용할 수 있습니다. 좋은 프롬프트는 AI에게 답을 맡기는 문장이 아니라 좋은 코드의 기준을 공유하는 작업 지시서입니다.

핵심 요약

  • 리팩토링 요청 전에는 기능, 공개 API, 오류 동작처럼 반드시 유지할 계약을 먼저 정의합니다.
  • “깔끔하게” 같은 표현 대신 중첩 축소, 책임 분리, 중복 제거, 이름 개선처럼 구체적인 기준을 제공합니다.
  • 한 번에 모든 것을 바꾸지 말고, 중심 목표 하나와 검토 가능한 범위를 정합니다.
  • 개선 코드만 받지 말고 문제 진단, 변경 이유, 위험 요소, 테스트 케이스를 함께 요청합니다.
  • AI의 제안은 적용 전 반드시 diff, 테스트, 사람의 코드 리뷰로 검증합니다.

자주 묻는 질문 (FAQ)

Q. AI에게 리팩토링을 맡겨도 기능이 바뀌지 않나요?
보장되지는 않으므로 입력·출력·오류 동작을 유지하라는 제약과 테스트 검증을 함께 사용해야 합니다.
Q. 가독성 개선 프롬프트에 가장 중요한 정보는 무엇인가요?
현재 코드의 문제, 변경 금지 조건, 우선순위, 원하는 출력 형식을 구체적으로 적는 것이 중요합니다.
Q. 리팩토링 결과를 바로 적용해도 되나요?
아니요. 변경 diff를 검토하고 기존 테스트 및 경계 조건 테스트를 통과한 뒤 적용하세요.