낯선 코드 읽기: 바깥에서 안으로
숙련된 엔지니어는 코드를 산문처럼 위에서 아래로 읽지 않습니다. 바깥에서 안으로 읽습니다. AI 설명기도 같은 방식으로 몰아갈 때 가장 유용합니다.
경계부터 시작하세요. 무엇이 들어가고 무엇이 나오는가. 진입점(내보낸 함수, 라우트 핸들러, 메인 루프)과 출구(반환값, 던져지는 에러, 데이터베이스나 파일 쓰기)를 찾으세요. 어떤 줄이 무슨 일을 하는지 묻기 전에, 입력·출력·부수 효과를 짚어달라고 요청하세요. 그 질문 하나가 지형도를 그려줍니다.
두 번째 패스: 구체적인 값 하나를 코드 전체로 따라가세요. 현실적인 입력(예: orders 배열이 비어 있는 user 객체)을 골라 한 줄씩 추적해 달라고 하세요. 특정 값을 추적하면 일반적인 요약이 뭉개고 지나가는 분기, 변이, 조기 반환이 드러납니다.
세 번째 패스: 관용구에 이름을 붙이세요. 대부분의 코드는 80%가 패턴이고 20%가 결정입니다. 디바운스 래퍼, 지수 백오프 재시도 루프, 리듀서 — 패턴에 이름이 붙으면 패턴에서 벗어난 부분만 진짜 주의가 필요합니다. 직접 물어보세요. 이 중 어디가 표준 패턴이고, 어디서 패턴을 벗어나는가?
그다음에야 줄 단위로 읽되, 앞의 세 패스를 거치고도 진짜 불명확하게 남은 부분만 읽으세요. 200줄짜리 파일이라면 보통 중요한 20줄 정도만 남습니다.
AI 코드 설명기가 틀리는 지점
AI 설명의 오류에는 패턴이 있고, 그 패턴은 점검이 가능할 만큼 예측 가능합니다.
환각된 API가 고전적인 실패입니다. 설명이 존재하지 않는 매개변수, 다른 라이브러리에 있는 비슷한 이름의 메서드, 다른 메이저 버전의 동작을 묘사합니다. 모델은 학습 때 본 수백 개의 라이브러리를 뒤섞기 때문에, lodash 호출에 대한 설명이 슬그머니 Underscore의 동작을 묘사하거나, pandas 코드 설명이 두 버전 전에 제거된 인자를 인용할 수 있습니다.
부수 효과 누락은 더 교묘합니다. 설명기는 함수가 무엇을 계산하는지는 요약하면서, 인자를 변이시키고, 캐시에 쓰고, 개인정보를 로깅하고, 분석 이벤트를 쏘는 것은 빠뜨립니다. 요약은 반환값 쪽으로 치우치는데, 실무의 버그는 부수 효과에 삽니다. 항상 따로 물어보세요. 이 코드가 자기 스코프 밖에서 바꾸는 상태는 무엇인가?
낡은 관용구 문제는 양쪽으로 벱니다. 모델은 멀쩡히 현대적인 코드를 '구식'이라 부르기도 하고, 폐기된 패턴(var, componentWillMount, Python 2 나눗셈 의미론)을 정상인 것처럼 제시하기도 합니다. 두 시대가 모두 학습 데이터에 있기 때문입니다. '현재 모범 사례'에 대한 어떤 주장이든 기본적으로 유효기간이 지났다고 간주하세요.
마지막으로 자신만만한 복잡도 주장. "이건 O(n log n)으로 동작한다"는 모델이 유창하게, 그리고 틀리게 생성하는 전형적인 문장입니다. sort, includes, 스프레드처럼 라이브러리 호출 안에 숨은 루프가 있을 때 특히 그렇습니다. 복잡도가 중요하다면 직접 유도하거나, 공식을 단언하게 하지 말고 구체적인 입력 크기에서 연산 횟수를 세게 하세요.
설명 깊이를 맞추는 프롬프트
'이 코드 설명해 줘'는 코드를 자연어로 다시 읊는 문단을 낳습니다. 기술적으로는 맞지만 거의 쓸모가 없습니다. 해법은 내가 이미 아는 것과 이 설명이 뒷받침해야 할 결정을 선언하는 것입니다.
입문자라면 비유와 추적을 함께 요구하세요. "이 코드가 하는 일을 현실 세계 비유로 설명한 다음, 예시 입력 하나를 단계별로 통과시켜 줘." 추적 없는 비유는 막연한 안심만 주고, 비유 없는 추적은 상태 변화의 벽만 세웁니다.
언어는 읽을 줄 알지만 이 코드베이스가 처음이라면 문법은 통째로 건너뛰세요. "JavaScript는 잘 안다고 가정하고, 의도, 뻔하지 않은 결정, 유지보수자가 놀랄 만한 부분만 설명해 줘." 코드 리뷰 준비에 가장 지렛대 효과가 큰 프롬프트입니다.
디버깅 중이라면 아예 설명을 요구하지 마세요. 반박을 요구하세요. "작성자는 이 함수가 정렬된 복사본을 반환한다고 믿는다. 특정 줄을 근거로 그 믿음에 대한 찬반을 논증해 줘." 모델은 해설자보다 비평가 역할을 줄 때 문제를 눈에 띄게 더 잘 찾습니다.
이 도구의 수준 선택기는 이런 틀을 대신 써 줍니다. 생성된 프롬프트를 편집해 뭉뚱그린 수준 대신 실제 언어 경험을 명시하세요.
Instead of:
"Explain this code."
Try:
"I know Python well but have never used asyncio.
1. What is the intent of this function in one sentence?
2. Trace the input [3, 1, 2] through it line by line.
3. List every side effect (I/O, mutation, global state).
4. What would surprise a maintainer? What could break
under concurrency?
Do not explain basic syntax."실전 예시: 받아쓰기 설명 vs 쓸모 있는 설명
대부분의 설명기가 똑같이 얕게 설명하는 다섯 줄짜리 함수를 봅시다. 아래 스니펫은 이메일 기준으로 사용자를 중복 제거하되 마지막 항목을 남깁니다.
받아쓰기 설명은 이렇게 말합니다. "이 함수는 users 배열을 순회하며 이메일을 키로 하는 Map을 만들고, Map의 값들을 배열로 반환한다." 모든 단어가 사실입니다. 그리고 아무것도 유용하지 않습니다. 코드를 소리 내어 읽은 것뿐입니다.
쓸모 있는 설명은 코드가 던지는 질문에 답합니다. 왜 Set이나 객체가 아니라 Map인가? (Map은 삽입 순서를 보존하고 어떤 키 타입도 허용합니다. 여기서는 순서가 핵심입니다.) 왜 마지막 중복이 이기는가? (Map.set은 덮어쓰므로 뒤의 항목이 앞의 것을 대체합니다. 배열이 오래된 순으로 정렬돼 있다면 이 코드는 조용히 최신 레코드를 남기는데, 의도일 수도 아닐 수도 있습니다.) 날카로운 모서리는 어디인가? (대소문자만 다른 이메일은 서로 다른 것으로 취급되고, undefined 이메일은 한 버킷으로 뭉개지며, 반환 배열은 새것이지만 안의 user 객체는 공유 참조라서 변이시키면 호출자에게 영향이 갑니다.)
마지막 문단이 바로 모든 설명기에게 요구해야 할 것입니다. 코드가 무엇을 하는가가 아니라, 무엇을 결정하고, 무엇을 가정하고, 어디서 당신을 다치게 할 수 있는가. 설명에 "주의할 점"으로 시작하는 문장이 하나도 없다면 다시 물어보세요.
function dedupeUsers(users) {
const byEmail = new Map();
for (const u of users) byEmail.set(u.email, u);
return [...byEmail.values()];
}
Shallow: "Builds a Map keyed by email and returns its values."
Useful: "Keeps the LAST user per email (Map.set overwrites).
Case-sensitive: [email protected] and [email protected] stay separate.
Returned array is new, but user objects are shared
references — mutating them affects the original."2분 검증 루틴
모든 AI 설명을 자신감 넘치는 인턴의 초안으로 취급하세요. 대체로 맞고, 가끔 중요한 지점에서 틀리며, 그 차이를 스스로는 절대 모릅니다.
언급된 API는 실제 문서와 대조하세요. 모델의 기억이 아니라요. 설명이 특정 함수의 동작(radix 없는 parseInt, 제자리에서 변이하는 Array.sort, 라이브러리 기본값)에 걸려 있다면, 문서 확인은 30초면 되고 가장 치명적인 오류를 잡아냅니다.
추적을 실행해 보세요. 설명기가 입력을 코드에 통과시켰다면, 그 입력을 REPL이나 임시 테스트에서 실제로 실행해 비교하세요. 서술된 추적과 실제 출력의 불일치는 설명이 틀렸다는 가장 강력한 신호입니다.
위험한 주장은 교차 심문하세요. 동시성, 변이, 에러 처리, 성능에 관한 내용은 새 세션에서 표현을 바꿔 같은 질문을 다시 하세요. 일관된 답은 정확성의 약한 증거이고, 일관되지 않은 답은 지금 보고 있는 것이 추측이라는 강한 증거입니다.
어느 것도 큰 수고가 아닙니다. 대안 — 검증되지 않은 의역으로만 이해한 코드를 배포하는 것 — 이 바로 미묘한 프로덕션 버그가 태어나는 방식입니다.