AI를 위한 리팩토링: 코드 리뷰어가 기계일 때
I’m ready to translate the article for you, but I need the text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line and all formatting exactly as you specify.
Source: …
왜 이것에 신경 써야 할까
AI 어시스턴트(ChatGPT, Claude, Copilot)와 코딩하고 있다면, 이상한 현상을 눈치챘을 겁니다: ‘좋은 코드’에 대한 규칙이 바뀌고 있다는 점 말이죠.
전통적인 리팩터링 조언은 사람이 코드를 읽는다는 전제에 기반했습니다. 그런데 인간보다 AI가 코드를 더 자주 읽는다면 어떨까요? AI가 여러분의 “완벽히 읽기 쉬운” 코드를 혼란스러워한다면?
이 일은 지금 바로 일어나고 있으며, 우리는 이에 대해 이야기해야 합니다.
새로운 문제: 이해 부채
우리는 모두 기술 부채에 대해 알고 있습니다 – 나중에 고쳐야 할 코드. 하지만 AI‑네이티브 개발은 다른 문제를 만들죠: 이해 부채.
| 기술 부채 | 이해 부채 |
|---|---|
| “나중에 바꾸기 어려울 것” | “왜 지금 이렇게 동작하는지 아무도 모른다” |
| 미래 유지보수 비용 | 즉각적인 이해 비용 |
| 점진적으로 상환 가능 | 지금 바로 차단한다 |
원인은 무엇일까?
AI가 코드를 생성할 때:
- 코드를 이해하지 못한다 – 동작하니 그대로 배포한다.
- 일관성 부족 – 매번 다른 패턴이 나온다.
- 과도하게 복잡함 – AI가 요청하지 않은 엣지 케이스를 추가한다.
코드 작성 비용은 낮아졌고, 코드 이해 비용은 상승했습니다.
그런데… 과연 이해가 필요할까?
요즘은 코드를 실제로 읽는 경우가 거의 없습니다. 이해가 필요할 때 저는 다음을 합니다:
- AI에게 물는다: “이 함수는 무엇을 하나요?”
- AI에게 물는다: “왜 이렇게 설계됐나요?”
- AI에게 물는다: “X를 바꾸면 무슨 일이 일어나나요?”
AI가 인간보다 코드를 더 잘 설명한다면, “인간 가독성”이 여전히 목표가 될까요?
반전: 때로는 그렇고, 때로는 그렇지 않습니다. AI가 실패하는 경우를 보여드리죠.
AI가 막히는 순간: 디버그 루프 오브 둠
아마 경험해 보셨을 겁니다:
You: "This function has a bug, can you fix it?"
AI: *adds console.log()*
AI: *adds another console.log()*
AI: *adds error handling that doesn't help*
AI: *adds more logs in random places*
AI: *suggests rewriting the whole thing"
You: 😤
AI가 디버깅에 서툰 이유는:
- 기억력 부족 – 이미 시도한 내용을 잊어버린다.
- 가설 부재 – 해결책을 무작위로 던진다.
- 종료 지점 없음 – 끝없이 시도한다.
교훈: AI는 코드를 생성하고 설명하는 데는 뛰어나지만, 문제를 조사하는 데는 한계가 있다.
새로운 리팩터링 목표: AI가 길을 잃지 않게 만들기
전통적인 리팩터링은 인간 뇌에 최적화되었습니다:
- 짧은 변수명 → 명확한 이름
- 긴 함수 → 작은 함수
- 복잡한 로직 → 단순한 로직
새로운 리팩터링은 AI 정확도에 최적화됩니다:
- 작은 범위 – AI는 큰 파일에서 흐트를 잡는다.
- 명확한 의존성 – AI는 암묵적인 결합을 다루지 못한다.
- 상태 최소화 – AI는 전역 변이를 추적하지 못한다.
- 테스트 확대 – AI는 검증 체크포인트가 필요하다.
흥미로운 사실: 이 두 기준은 많이 겹칩니다! “인간에게 좋은 코드”와 “AI에게 좋은 코드”는 아직은 크게 다르지만, 점점 비슷해지고 있습니다.
인간과 AI가 의견이 다른 경우
함수 크기
인간은 선호한다:
// I want to see the whole story in one place
function processUser(user) {
// validate
// transform
// save
// notify
// all in one flow
}
AI는 선호한다:
// I can jump between functions instantly
function processUser(user) {
const validated = validate(user);
const transformed = transform(validated);
const saved = save(transformed);
notify(saved);
}
인간에게는 파일 간 이동이 정신적 흐름을 깨뜨립니다.
AI에게는 비용이 들지 않습니다.
실용적인 답변
지금은? AI에 최적화.
왜?
- 인간은 AI에게 흐름을 설명해 달라고 요청할 수 있다.
- AI는 인간에게 더 나은 파싱을 위해 구조를 재구성해 달라고 요청할 수 없다.
- AI의 제한이 더 제약이 된다.
실용적인 팁: 디버그 루프 중단
-
범위 좁히기
❌ "Fix the bug in this file" ✅ "Check if validateEmail() correctly handles subdomains" -
가설은 당신이 만들고, AI가 테스트한다
❌ "Why is this broken?" ✅ "I think the issue is timezone handling. Check lines 45‑60" -
세 번 시도 규칙 – AI가 같은 접근을 세 번 시도하면 중단하고 재고한다:
- 대화를 초기화한다.
- 다른 AI를 시도한다.
- 직접 디버깅한다.
-
AI 실험을 위한 별도 브랜치
# Don't let AI pollute your main branch git checkout -b ai-debug-session # Let it try stuff # If it works, cherry‑pick the good parts # If not, delete the branch -
항상 기능과 함께 테스트를 생성한다
❌ "Build a login system" ✅ "Build a login system with unit tests"
언제 리팩터링 할까
리팩터링이 필요함을 나타내는 빨간 깃발:
- AI가 같은 코드를 3번 이상 보면서 혼란스러워한다.
- 함수가 무엇을 하는지 설명할 수 없다.
- 기능을 추가하려면 5개 이상의 파일을 수정해야 한다.
- 테스트가 불안정하거나 누락되어 있다.
리팩터링을 진행해도 좋은 초록불:
- 스프린트 사이.
- 주요 기능을 추가하기 전에.
- 전용 시간이 있을 때(금요일 오후 제외).
빠른 성과:
- 큰 함수 나누기 (> 50줄).
- 전역 상태 제거.
- 테스트되지 않은 코드에 테스트 추가.
- 매직 넘버를 상수로 추출.
하루에 하나씩 진행하세요. 한 번에 모든 것을 리팩터링하려고 하지 마세요.
답답한 질문들
솔직히? 모든 답을 가지고 있지는 않아요.
- 새로운 모델이 나오면 AI의 선호도가 바뀔까요?
- 인간 가독성을 정말 낮춰야 할까요?
- AI가 복잡성을 더 잘 다루게 된다면 어떨까요?
내가 알고 있는 것은:
- “이 코드는 누구를 위한 것인가?”라는 질문이 이제 현실이 되었습니다.
- AI 디버깅의 한계가 현재 병목 현상입니다.
- “AI가 길을 잃지 않게” 최적화하는 것이 유용한 휴리스틱입니다.
오늘 시도해 보기
AI가 어려워하는 함수를 하나 골라서:
- 더 작은 조각으로 나누세요 (각각 하나의 책임).
- 테스트를 추가하세요.
- AI에게 해당 영역을 디버그하도록 요청하세요.
- 성능이 개선됐는지 확인하세요.
그럼 댓글로 알려 주세요 – 효과가 있었나요?
토론
당신의 경험은 어떠신가요?
- AI를 사용할 때 리팩토링 방식을 다르게 하시나요?
- AI 이해에 도움이 되거나 방해가 되는 다른 패턴을 찾으셨나요?
- 제가 이걸 너무 과하게 생각하고 있나요? 😅
아래에 의견을 남겨 주세요. 저는 아직 이 부분을 파악 중이며, 여러분에게 효과적인(혹은 그렇지 않은) 방법을 듣고 싶습니다.
이러한 사고 과정과 엔지니어링 결정에 대해 더 많이 제 블로그에 씁니다.
관심이 있으시면: