코드 리팩토링 기법: 실제로 측정 가능한 결과를 만드는 방법
요약
코드 리팩토링 기법 9가지를 우선순위 기준과 함께 정리했다. Extract Method, 다형성 기반 조건문 제거, 핫스팟 분석, Branch-by-Abstraction 등을 다룬다. BCG 데이터 기준 체계적 리팩토링은 임시방편 대비 ROI가 3배다. AI 도구가 기계적 리팩토링은 도와주지만 '어디를' 해야 하는지는 여전히 개발자 판단이다.
팀원 세 명이 독립적으로 그 모듈을 '공포의 구역'이라고 부른다. 버그는 거기 몰려 있고, 그 파일을 스치기만 해도 PR 리뷰가 두 배로 길어진다. 지난번에 리팩토링을 시도한 사람은 스프린트 두 개를 통째로 쓰고, 피처 플래그를 망가뜨린 채 나왔다.
코드 리팩토링 기법은 '변수 이름 바꾸기'부터 '서비스 경계 전체를 재구성하기'까지 스펙트럼이 넓다. 이 글에서는 실제로 측정 가능한 지표를 바꾸는 기법들만 다룬다. 새 엔지니어의 첫 커밋까지 걸리는 시간, 모듈별 버그 발생률, PR 리뷰 소요 시간이 기준이다.
Extract Method: 오늘 당장 할 수 있는 리팩토링
코드베이스에 기법을 하나만 적용해야 한다면 Extract Method다. 긴 함수 안에서 단일한 역할을 하는 코드 블록을 찾아 별도 함수로 분리하는 것이다. 즉각적인 효과가 두 가지다: 원래 함수가 읽기 쉬워지고, 분리된 함수는 독립적으로 테스트할 수 있다.
기준은 단순하다. 코드 블록에 주석을 달아야 무슨 역할인지 이해가 된다면, 그 블록은 함수여야 한다. 함수 이름이 곧 주석이 된다. 주석과 달리, 함수 이름은 낡아지면 빌드를 깨뜨린다.

실무에서 흔히 보이는 패턴이 있다. 200줄짜리 함수를 열면 데이터 검증, 비즈니스 로직 계산, DB 저장, 이메일 발송이 전부 한 곳에 들어 있다. 각 단계를 validate_order_input(), calculate_discount(), persist_order(), notify_customer()로 분리하면 테스트 커버리지 작성 시간이 절반으로 줄고, 다음 기능 추가 시 어느 부분을 수정해야 하는지 바로 보인다.
조건문을 다형성으로 교체하기
타입 필드를 체크하는 긴 if/elif/else 체인이나 switch 문은 코드 확장을 가장 어렵게 만드는 패턴 중 하나다. 수정 방법은 조건 분기를 클래스 계층구조나 전략 패턴으로 교체하는 것이다. 각 케이스가 동일한 인터페이스를 가진 독립 클래스가 된다.
단, 이 기법은 조건 분기가 둘 이하이고 앞으로 늘어날 가능성이 낮다면 건너뛰는 것이 낫다. 다형성은 오버헤드가 있다. 함수 하나가 있던 자리에 파일 여러 개가 생긴다. 규모가 커질수록 ROI가 나오는 기법이다.
한국 현업에서 자주 보이는 사례: 결제 방식에 따라 분기되는 로직. 카드, 계좌이체, 간편결제, 포인트가 하나의 함수에 if 블록으로 들어가 있다. 각 결제 수단을 PaymentMethod 인터페이스를 구현하는 클래스로 분리하면, 새로운 결제 수단 추가가 기존 코드 수정 없이 클래스 하나 추가로 끝난다.
핫스팟 분석: 어디를 먼저 리팩토링해야 하는가
순환 복잡도(cyclomatic complexity)와 변경 빈도를 함께 본다. 모듈이 아무리 복잡해도 3년째 아무도 건드리지 않는다면, 그것을 리팩토링하는 건 고고학이지 엔지니어링이 아니다. 비용을 발생시키는 모듈은 복잡하면서도 팀이 매주 수정하는 파일들이다.

실제 측정 방법은 두 단계다. 첫째, 정적 분석 도구로 함수/파일별 순환 복잡도를 뽑는다. Python은 radon, JS/TS는 complexity-report, Java는 checkstyle을 쓴다. 둘째, git 로그에서 지난 90일 기준 파일별 커밋 수를 뽑는다: git log --since="90 days ago" --name-only --format="" | sort | uniq -c | sort -rn | head -20.
두 점수를 곱하거나 행렬로 시각화하면 우선순위가 바로 나온다. 복잡도 상위 25%이면서 변경 빈도 상위 25%인 파일이 진짜 핫스팟이다. BCG 2024 리포트에 따르면 이런 체계적 접근법은 임시방편 대비 ROI가 3배다.
Branch-by-Abstraction: 운영 중인 시스템을 리팩토링하는 방법
서비스가 실제로 트래픽을 받고 있는 상태에서 핵심 모듈을 교체해야 할 때, 직접 수술하는 방식은 위험하다. Branch-by-Abstraction은 이 문제를 단계적으로 해결한다.
순서는 이렇다. 현재 구현을 감싸는 추상화 레이어를 먼저 만든다. 호출자들이 추상화를 통해 동작하도록 전환한다. 그 뒤에서 새 구현을 작성한다. 준비가 되면 스위치를 전환한다. 이것이 서비스 수준에서 Strangler Fig 패턴이 동작하는 방식이다.
이 접근법의 장점은 각 단계가 독립적으로 배포 가능하다는 점이다. 리팩토링이 스프린트 중간에 끼어도 언제든 멈출 수 있다. 팀이 동시에 다른 기능 작업을 계속할 수 있다.
매직 넘버를 명명된 상수로 교체하기
명명된 상수는 스타일 선호의 문제가 아니다. 단일 진실 공급원(single source of truth) 메커니즘이다. 상수가 바뀌면 전체 코드베이스에서 자동으로 반영된다.

timeout(30)과 timeout(REQUEST_TIMEOUT_SECONDS)는 동작은 같다. 하지만 6개월 뒤 타임아웃을 45초로 바꿔야 할 때, 전자는 코드베이스에서 30을 전부 찾아서 어떤 맥락의 30인지 판단해야 한다. 후자는 상수 선언 한 줄을 바꾸면 끝난다.
더 중요한 것은 맥락이다. PAYMENT_RETRY_LIMIT = 3은 비즈니스 규칙을 코드에 명시하는 행위다. 나중에 이 숫자를 5로 바꿔야 한다면, 그게 비즈니스 결정임을 코드 히스토리가 보여준다.
파라미터 객체 도입하기
인수가 여섯 개인 함수는 잘못 호출될 함수다. 그 파라미터들이 항상 함께 움직인다면, 그것들은 객체 안에 있어야 한다.
# 이전
def create_order(user_id, product_id, quantity, discount_code, shipping_address, payment_method):
...
# 이후
@dataclass
class OrderRequest:
user_id: int
product_id: int
quantity: int
discount_code: str | None
shipping_address: Address
payment_method: PaymentMethod
def create_order(request: OrderRequest):
...파라미터 순서를 틀릴 위험이 사라진다. 타입 힌트가 IDE에서 바로 보인다. 나중에 파라미터를 추가해도 기존 호출부를 전부 수정할 필요가 없다. Stack Overflow 설문에 따르면 개발자의 62%가 기술 부채에 좌절감을 느낀다고 응답했는데, 이런 파라미터 지옥이 그 원인 중 하나다.
준비적 리팩토링 마인드셋
기능을 추가하기 직전에 리팩토링한다. 별도 프로젝트로 분리하지 않는다. Kent Beck의 표현이 정확하다: '변화를 쉽게 만들어라, 그런 다음 쉬운 변화를 만들어라.'
실무에서 이것이 중요한 이유가 있다. 리팩토링을 독립 스프린트로 제안하면 비즈니스 승인을 받기 어렵다. 하지만 '이 기능 추가에 2일 필요한데, 코드 정리를 먼저 하면 1일로 줄일 수 있다'는 대화는 완전히 다른 맥락이다. 기능 작업에 리팩토링이 내장되어 있다면, 관리자의 별도 승인이 필요 없다.
McKinsey 2024 데이터에 따르면 체계적 현대화를 적용한 팀은 작업 완료 속도가 40-50% 빨랐다. 그 '체계적'이라는 단어 안에 준비적 리팩토링이 포함되어 있다.
AI 도구가 리팩토링에서 하는 것과 하지 못하는 것
Cursor, GitHub Copilot, Cody는 기계적 리팩토링의 마찰을 줄여준다. Extract Method, 변수 이름 변경, 파라미터 추출 같은 작업을 빠르게 처리한다. 이 부분은 실제로 도움이 된다.
하지만 이 도구들은 어디를 리팩토링해야 하는지 말해주지 못한다. 복잡도 트렌드를 추론하지 못하고, 팀이 어떤 파일을 가장 자주 수정하는지 모른다. 전략적 판단은 여전히 개발자의 몫이다.
핫스팟 분석은 AI가 대신해줄 수 없다. git 히스토리와 복잡도 데이터를 읽고, 팀의 도메인 지식을 결합해서 '이번 분기에 여기를 정리해야 한다'는 결정을 내리는 것은 사람이 해야 한다.
월요일 아침에 시작하는 방법
이번 주에 레포지토리에 핫스팟 분석을 돌려라. 점수가 가장 높은 파일을 하나 골라라. 그 파일에서 가장 긴 함수 세 개에 Extract Method를 적용하라. 테스트를 작성하라. 시작 전 복잡도 점수를 커밋 메시지에 기록하고 커밋하라.
다음 스프린트에 그 파일이 또 등장하면, 이전 커밋 메시지를 참조해서 얼마나 개선됐는지 확인할 수 있다. 측정 불가능한 리팩토링은 다음 스프린트 계획에서 정당화하기 어렵다.