forbidden code — fiction 04
센타우르
1997년 카스파로프는 딥블루에게 졌다.
그리고 인간과 컴퓨터가 함께 이기는 게임을 만들었다.
Part I
"1997년, 카스파로프"
2026년 3월 둘째 주. 일요일 오후.
진우는 집에서 노트북을 펴고 있었다. 코드가 아니라 글을 읽고 있었다. 가리 카스파로프의 에세이. 1997년 5월 11일, 뉴욕. 체스 세계 챔피언이 IBM의 딥블루에게 패배한 날에 대한 글이었다.
카스파로프는 졌다. 하지만 포기하지 않았다. 1998년, 그는 새로운 형식의 대회를 만들었다. Advanced Chess. 규칙은 간단하다. 인간이 컴퓨터의 도움을 받아 체스를 둔다. 인간+컴퓨터 vs 인간+컴퓨터.
센타우르. 반인반마. 진우는 그 단어를 곱씹었다.
2005년, 더 극적인 일이 벌어졌다. 프리스타일 체스 대회. 참가 제한 없이 누구나 어떤 도구든 쓸 수 있는 대회. 그랜드마스터가 슈퍼컴퓨터와 참전했다. 결과는?
약한 인간 + 기계 + 좋은 프로세스. 진우는 이 문장에 밑줄을 그었다. 좋은 프로세스. 기계를 어떻게 쓰느냐가 기계의 성능보다 중요하다는 뜻이다.
진우는 Harvard Business School의 연구를 찾았다. BCG 컨설턴트 244명을 대상으로 한 실험.
셀프오토메이터. 작업을 AI에게 위임하고 결과만 확인하는 사람. 역량 증가 없음.
나는 1편 전까지 셀프오토메이터였다. "이 코드 짜줘." AI가 짜줬다. 나는 결과만 확인했다. "좋아 보인다." 역량은 늘지 않았다. 아니, 퇴화했다.
센타우르. AI와 자신의 작업을 명확히 분리하고, AI의 출력을 선택적으로 수용하는 사람. 최고 정확도. 전체의 14%.
진우는 한 달 동안 자신이 어떻게 변했는지 되돌아보았다. 그리고 서연과 한결도.
Part II
세 개의 방법
한 달. 1편의 사건으로부터 한 달이 지났다. 세 사람은 각자의 방법을 찾았다.
method 01 — 박진우
진우의 워크플로우가 바뀌었다. 이전에는 터미널을 열고 "이 기능 짜줘"라고 입력하는 것이 시작이었다. 지금은 먼저 빈 파일을 열고, 직접 코드를 쓰는 것이 시작이다.
완성 후 Claude에게 보여준다.
TTL 전략에 대해 의견 줘. 코드를 다시 짜지 말고,
개선점만 알려줘.
RedisConnectionError 외에 TimeoutError도 처리하면 좋겠습니다. 둘째, TTL 300초는 대시보드에 적절하지만, 결제 관련 캐시에는 60초 이하를 권장합니다. 셋째, json.dumps에 default=str을 추가하면 datetime 직렬화 문제를 예방할 수 있습니다.
세 번째 제안. default=str. 이건 3편에서 서연이 발견한 버그와 같은 패턴이다. 진우는 이미 그 버그를 고쳤지만, Claude도 같은 지적을 한다는 것이 흥미롭다. AI는 패턴을 잘 잡는다. 하지만 3편에서 진우가 직접 코드를 짜지 않았다면, 이 패턴이 왜 중요한지 이해하지 못한 채 "좋아 보인다"로 넘어갔을 것이다.
생산성은 이전의 70%다. 하지만 진우는 모든 코드를 설명할 수 있다. 커밋 메시지에 Claude의 제안과 자신이 수용/거부한 이유를 기록한다.
feat: add Redis cache layer for dashboard API
TTL: 300s (dashboard data 5min staleness acceptable)
Fallback: direct DB query on Redis failure
Claude review notes:
- [accepted] added TimeoutError handling
- [accepted] added json default=str serializer
- [rejected] TTL 60s for payment cache
→ this is dashboard, not payment. 300s is fine.
[rejected] 라인. 진우는 AI의 제안을 거부했다. 이유를 적었다. "이것은 대시보드이지 결제가 아니다. 300초가 적절하다." 이전의 진우는 AI의 모든 제안을 수용했다. 이제는 거부할 수 있다. 거부하려면 이해해야 하기 때문이다.
method 02 — 이서연
서연의 방법은 가장 공격적이었다. AI를 동료가 아니라 적으로 다루는 것이다. 자기 코드를 공격하게 만든다.
깨지는 경우만. 엣지 케이스, 레이스 컨디션,
예상 못한 입력. 가능한 한 많이.
onFilter(undefined)가 호출됩니다 — undefined 대신 빈 배열을 반환해야 합니다. (2) 부서명에 특수문자가 포함되면 드롭다운 렌더링이 깨집니다. (3) 사용자가 빠르게 필터를 변경하면 이전 API 호출이 현재 호출보다 늦게 도착해 결과가 덮어씌워질 수 있습니다.
세 번째 케이스. 레이스 컨디션. 서연이 미처 생각하지 못한 것이었다. AI가 발견해줬다. 하지만 서연은 AI가 짜준 테스트를 그대로 쓰지 않는다. AI가 발견한 빈틈을 이해하고, 자기 코드를 수정한 후, 테스트를 직접 다시 짠다.
"AI가 적이 되어주는 거야. 내 코드를 공격하게 하는 거지. 내가 못 본 약점을 AI는 볼 수 있어. 그걸 고치는 건 나."
method 03 — 윤한결
useCallback은 언제 써야 해?" "이 에러가 뭘 의미하는 거야?" AI가 설명하면, 코드는 직접 짠다.한결의 방법은 가장 겸손했다. AI를 선생님으로 대하되, 숙제를 대신 해달라고 하지 않는 것이다.
리렌더링될 때? 언마운트될 때? 둘 다?
코드 예제 말고 동작 원리만 설명해줘.
한결은 설명을 듣고 노트에 적는다. 그리고 코드를 직접 짠다. AI의 설명을 자기 손으로 코드로 옮기는 과정에서 이해가 체화된다.
Anthropic의 연구에서 "개념 질문만 한 그룹"이 AI 보조 학습 효과를 65% 이상 유지했다. 한결이 정확히 그 패턴을 따르고 있었다. 한 달 만에 서연의 코드 리뷰를 통과하기 시작했다. useCallback을 왜 넣었는지 대답할 수 있게 됐다. 아니, 왜 넣지 않았는지도.
세 사람이 찾은 것은 같았다
"짜줘"를 "같이 하자"로 바꾸는 법
Part III
개발자라는 직업
3월 마지막 금요일. 네 번째 No AI Friday.
첫 번째 No AI Friday는 "금단 증상"이었다. 두 번째는 "근육통"이었다. 세 번째는 "워밍업"이었다. 네 번째는 "운동"이었다. 같은 금요일인데 분위기가 완전히 달랐다.
한결이 CSS Grid 레이아웃을 AI 없이 30분 만에 완성했다. 한 달 전에는 4시간 걸렸다. grid-template-columns를 타이핑하면서 MDN을 열지 않았다. 손가락이 기억했다.
진우가 PostgreSQL 쿼리를 AI 없이 최적화했다. EXPLAIN ANALYZE를 직접 읽었다.
SELECT u.id, u.name, COUNT(p.id) as payment_count
FROM users u
LEFT JOIN payments p ON u.id = p.user_id
WHERE p.created_at > NOW() - INTERVAL '30 days'
GROUP BY u.id, u.name
ORDER BY payment_count DESC
LIMIT 20"
Sort (cost=156.42..156.47 rows=20)
-> HashAggregate (cost=155.80..156.00 rows=20)
-> Hash Join (cost=45.00..150.00 rows=1160)
Filter: (p.created_at > ...)
Execution Time: 23.4 ms
진우는 EXPLAIN ANALYZE의 출력을 읽을 수 있다. HashAggregate가 뭔지, cost가 뭔지, rows 추정값이 왜 중요한지. 한 달 전에는 이 출력을 Claude에게 붙여넣고 "최적화해줘"라고 했다. 지금은 직접 읽고, WHERE 절의 위치를 JOIN 조건으로 옮기면 인덱스를 탈 수 있다는 것을 안다.
서연이 테스트를 AI 없이 짰다. 그리고 의외의 발견을 했다.
"테스트를 직접 쓰는 게 의외로 재미있어."
"재미있다고?" 진우가 의아하게 물었다.
"내 코드를 공격하는 거잖아. 내가 나를 이기려고 하는 거야. AI한테 시키면 남의 테스트인데, 직접 쓰면 자기 코드의 약점을 알아가는 거라서 되게 몰입돼."
GitHub의 Octoverse 보고서가 떠올랐다. AI를 사용하는 개발자의 새로운 정체성은 "코드의 크리에이티브 디렉터"라고 했다. 코드를 직접 짜느냐 AI가 짜느냐가 아니라, 코드의 모든 결정에 책임을 질 수 있느냐가 핵심이라고.
크리에이티브 디렉터. 이해하고, 지시하고, 검증하는 사람. AI가 짠 코드든 내가 짠 코드든, 내가 모든 줄의 이유를 알아야 한다. 그게 개발자라는 직업이다.
Stack Overflow의 한 개발자가 말했다. "AI can 10x developers... in creating tech debt." AI가 개발자의 생산성을 10배로 만들 수 있다 — 기술 부채를 만드는 데에서. 진우는 이제 그 말이 이해된다. 속도만 추구하면 부채만 쌓인다. 속도와 이해의 균형. 그것이 센타우르다.
84%가 AI를 쓴다. 72%가 바이브 코딩을 거부한다. 그 사이 어딘가에 센타우르가 있다. AI를 쓰되, 바이브로 내맡기지 않는 사람. 코드를 이해하되, AI를 버리지 않는 사람.
Part IV
"센타우르"
금요일 저녁. 6시. 세 사람이 퇴근하며 엘리베이터를 기다렸다.
한결이 먼저 말했다.
"오늘 CSS Grid 30분 만에 끝났어요."
"처음엔 4시간이었잖아." 서연이 웃었다.
"근육이에요. 쓰니까 돌아와요."
진우가 말했다.
"나도 비슷해. 한 달 전에 advisory_lock이 뭔지 몰랐는데, 지금은 EXPLAIN ANALYZE를 직접 읽어. 근데 그게 다가 아닌 것 같아."
"뭐가?"
"AI가 돌아왔을 때 — 사용량 제한이 풀렸을 때 — 처음으로 AI에게 '아니'라고 말할 수 있었어. AI가 제안한 걸 거부할 수 있다는 게 중요한 거야. 이해해야 거부할 수 있으니까."
서연이 고개를 끄덕였다.
"AI를 안 쓰는 게 답이 아니야. 84%가 쓰는 시대에 안 쓰는 건 고집이지 전략이 아니야. AI가 할 수 없는 일을 내가 하는 게 답이야."
"AI가 할 수 없는 일이 뭔데요?" 한결이 물었다.
"질문하는 거." 서연이 대답했다. "AI는 답을 잘 해. 하지만 '이 결과가 맞는 건가?'라는 질문은 안 해. '이 코드가 왜 여기 있어야 하는가?'라는 질문도 안 해. 그 질문은 사람만 할 수 있어."
엘리베이터가 도착했다. 세 사람이 탔다. 한결이 조용히 말했다.
"저는 아직 센타우르라기엔... 말 위에 타는 법부터 배우는 중이에요."
진우가 웃었다. "그게 시작이야. 말 위에 타는 법을 모르면 센타우르가 될 수 없으니까."
1층. 세 사람이 성수동 저녁 거리로 나왔다. 3월의 바람이 여전히 차갑지만, 2월보다는 따뜻했다. 한 달 전에는 AI가 사라져서 공포였다. 지금은 AI가 있어도 괜찮고, 없어도 괜찮다.
한결이 버스 정류장으로 걸어가며 손을 흔들었다. 서연이 반대 방향으로 걸어갔다. 진우만 사무실로 다시 올라갔다. 할 일이 남아 있었다.
월요일 아침. 진우는 터미널을 열었다.
Welcome back!
> _
커서가 깜박였다. 한 달 전, 이 커서가 사라져서 공포였다. 29시간 동안의 악몽. 하지만 그 29시간이 진우를 바꿨다. 서연을 바꿨다. 한결을 바꿨다. 팀을 바꿨다.
진우는 타이핑을 시작했다.
"짜줘"가 아니라 "같이 하자."
카스파로프는 딥블루에게 졌다. 그리고 인간과 컴퓨터가 함께 이기는 게임을 만들었다. 2005년, 아마추어 2명과 노트북 3대가 그랜드마스터와 슈퍼컴퓨터를 이겼다. 좋은 프로세스가 좋은 하드웨어를 이긴 것이다.
2026년, 세 명의 개발자가 비슷한 것을 발견했다. AI를 잘 쓰는 법은 AI에게 모든 것을 맡기는 것이 아니라, AI가 할 수 없는 것을 자기가 하는 것이다. 이해하는 것. 질문하는 것. 거부하는 것. 그리고 함께하는 것.
코드는 AI가 짠다. 하지만 개발자는 AI가 될 수 없다.
진우는 Claude의 응답을 기다리며 커피를 마셨다. 모니터 하나, 맥북 하나, 기계식 키보드 하나. 4년차 백엔드 개발자의 아침. 달라진 것은 하나. "짜줘"가 "같이 하자"로 바뀐 것. 그것만으로 충분했다.
카스파로프는 딥블루에게 졌다
그리고 함께 이기는 법을 만들었다
코드는 AI가 짠다. 하지만 개발자는 AI가 될 수 없다. 이해하고, 질문하고, 거부하고, 함께하는 것. 그것이 센타우르다.