AI를 오너십 있게 쓴다는 것
AI가 코드를 쓰는 일이 당연해진 요즘에도 그 코드의 책임은 여전히 사람에게 있다고 생각합니다. AI가 매번 다른 답을 내는 동안 무엇을 읽고 이해하고 설명할 수 있어야 내 코드라고 말할 수 있는지, 직접 겪으며 정리한 고민입니다.
TL;DR
화상 통신 SDK를 만들고 있었어요. 네트워크가 잠깐 끊겼다 돌아오면 저절로 다시 연결돼야 하고, 이 재연결을 확인하는 자동 테스트는 전부 초록이었어요. 그런데 QA에서 네트워크를 한 번 끊었다 붙여 보니, 끊긴 채로 다시 연결되지 않았어요.
테스트를 열어 보니 다시 연결하라는 명령을 보냈는지만 확인하고 있었어요. 실제로 다시 연결됐는지는 보지 않았습니다. 코드도 테스트도 AI가 썼고, 초록불을 보고 다음으로 넘어간 건 저였습니다.
그렇다면 이 코드의 주인은 누구일까요?
AI가 매번 다른 코드를 내도, 그중 무엇을 남길지 정하는 사람이 주인이라고 생각해요. 그러려면 정할 기준이 먼저 있어야 해서, 이 글에서는 그 기준을 어떻게 세웠는지 정리해 보았습니다.
SDK 이야기를 하려는 건 아니에요. 그 SDK도 코드 대부분을 AI가 썼지만, 무엇을 만들든 AI에게 코드를 맡기면 같은 고민을 하게 된다고 생각해요. 저는 그 고민을 코드보다 먼저 쓴 문서와 규칙, 검증으로 풀어 봤어요.
AI는 같은 요구에도 다른 코드가 나와요
AI로 개발하면서 반복해서 겪은 일이 셋 있어요.
- AI가 짠 코드가 제 환경에서는 잘 돌다가 배포한 뒤 다른 환경에서 실패해요.
- 어제 실수해서 고쳐 둔 부분을 오늘 또 틀려요.
- 테스트 코드가 통과하면 구현 코드는 읽지 않고 넘어가요. 나중에 이슈가 생겨 다시 열어 보면 왜 그렇게 짜였는지 아는 사람이 없어요.
셋의 공통점은 하나예요. 개발자가 AI를 오너십 있게 쓰지 못했다는 점입니다. 무엇을 남길지 사람이 정하지 않으니 AI가 만든 코드가 그대로 남았어요.
AI와 사람 사이에는 차이점이 둘 있어요. 하나는 비결정성이에요. 같은 입력을 넣어도 매번 다른 결과가 나온다는 뜻입니다. 다른 하나는 기억이 없다는 점이에요. 세션이 바뀌면 전에 정한 규칙을 기억하지 못해서, 같은 규칙을 매번 다시 설명해야 합니다.
사람도 같은 요구를 매번 완전히 똑같이 구현하지는 않아요. 다만 사람은 설계를 하고, 제품의 스펙과 정책, 요구사항이 바뀐 히스토리를 알고 거기에 맞게 구현해요. 그래서 방식이 달라도 제품에 맞는 코드가 나오고, 왜 그렇게 짰는지 설명하고 책임질 수 있습니다. AI는 저장소에 적혀 있지 않은 이런 맥락을 모른 채 짜요. 같은 요구로 100번 돌리면 매번 완전히 다른 방식으로 짠 코드 100개를 주고, 그중 무엇이 맞는지는 알려 주지 않아요. 무엇을 남길지는 사람이 정해야 합니다.
다만 매번 달라지는 답을 전부 사람이 보고 고를 필요는 없어요. 같은 입력에 늘 같은 결과를 내는 도구로 AI가 볼 범위를 먼저 고정하면, 결과가 달라지는 범위 자체가 줄어들어요. 타입이 맞지 않는 코드는 컴파일러가 돌려보내고, 스키마에 없는 필드는 검사가 걸러내고, 빌드가 깨지면 거기서 멈춰요. 뒤에 나오는 문서와 규칙, 검증은 둘 중 하나예요. 달라지는 범위를 도구로 줄이는 쪽이거나, 남은 것을 사람이 고르는 기준이 되는 쪽입니다.
AI는 코드에 적히지 않은 규칙을 몰라요
비즈니스 로직, 제품에서 정의된 프로토콜, 운영 정책은 코드만 읽어서는 알 수 없어요. 코드에 안 적혀 있으면 AI에게는 없는 것과 같습니다.
실시간 통신에서는 순서도 코드에 적히지 않아요. 연결된 클라이언트끼리 약속된 순서대로 프로토콜 메시지를 주고받아야 하고, 주고받는 타이밍이 어긋나거나 순서가 보장되지 않으면 문제가 납니다. 순서가 곧 정답인데, 그 순서는 코드만 봐서는 몰라요.
이때 AI는 원인을 두고 증상만 지우는 쪽으로 가요. 순서가 어긋나면 그 사이에 setTimeout을 넣어 의미 없는 기다림을 만들고, 안 되면 플래그로 우회하고, 그래도 안 되면 무한 재시도를 붙여요. 제 컴퓨터에서는 되고 다른 네트워크에서는 같은 문제가 다시 납니다.
그래서 순서는 문서로 정하고 우회는 룰로 막았습니다. 룰은 AI가 코드를 읽고 쓸 때 함께 따르는 규약 파일이에요. 무엇을 먼저 보내는지, 넘겨주기 전에 무엇을 모아 두는지, 다시 들어오면 순번을 어떻게 다시 세는지를 문서에 적었어요. 재연결 간격이나 연결 확인처럼 원래 시간이 필요한 타이머는 그대로 둡니다. 룰이 금지하는 것은 순서 문제를 시간 지연으로 덮는 타이머와 플래그, 무한 재시도예요. 그래도 들어오면 리뷰에서 돌려보내요.
코드를 읽지 않는 바이브 코딩은 하지 않았어요
바이브 코딩은 코드를 읽지 않고 되는지만 봐요. 혼자 써 보고 버릴 코드라면 괜찮아요. 제품에서는 검증 안 된 코드가 그대로 쌓여요. 구현에서 아낀 시간보다 유지보수에 드는 비용이 오히려 더 커지고, 이슈도 잦아질 수 있습니다.
반대로 AI가 짠 코드를 직접 읽고, 테스트하고, 남에게 설명할 수 있다면 도구만 바뀐 개발이에요. 코드를 짠 건 AI여도 무엇이 맞는지 판단하는 건 여전히 개발자입니다.
미트 프록시가 되지 않으려고 세 가지를 물어요
커피챗 같은 자리에서 자주 받는 질문이 있어요. 같이 일하기 싫은 개발자는 어떤 유형이냐는 거예요.
요즘 저는 AI가 낸 결과를 그대로 전달하고 책임은 지지 않으려는 사람이라고 답합니다.
이런 사람을 미트 프록시라고 부르더라고요. AI가 내놓은 답을 읽지도, 이해하지도, 검증하지도 않고 그대로 다른 사람에게 옮기는 사람이에요. 답변이 "Claude가 이렇게 말했어"로 시작하거나, AI가 쓴 글을 그대로 커밋하는 경우예요.
심한 말은 모자이크했어요. 가리지 않은 원문은 dontpastetheai.com/angry/ko (새 창에서 열림)에서 볼 수 있어요.
AI로 개발하는 게 당연해지면서 주변에도 이런 사람이 늘고 있어요. 지금 AI 개발에서 가장 큰 문제는 모델보다 이쪽이라고 생각합니다. 그래서 저라도 미트 프록시가 되지 않으려고, AI가 낸 결과를 쓰기 전에 스스로에게 세 가지를 물어요.
AI의 분석을 읽었나?
양이 많으면 요약을 시켜서라도 읽어요. 안 읽으면 그럴듯한 값이 그대로 확정돼요.
AI의 코드를 이해했나?
한 줄 한 줄이 아니라 공개 API와 검증 결과를 읽어요. 설명하지 못하는 코드는 남기지 않고, 초록불만 보고 넘기지 않아요.
AI를 쓰는 기준을 설명할 수 있나?
그 기준을 룰과 문서에 적어 두어서 누가 물어도 같은 답이 나와요.
그렇다고 AI가 만든 코드를 한 줄 한 줄 전부 읽는다면 AI를 사용하는 장점이 사라진다고 생각해요. AI를 쓰는 이유가 생산성이기 때문이에요. 그래서 저는 한 줄씩 읽는 대신 코드보다 설계와 인터페이스를 먼저 정하고, 그 인터페이스가 약속대로 동작하는지를 확인해요.
책임은 이렇게 나눴어요.
| 누가 | 무엇을 | 성격 |
|---|---|---|
| 사람 | 요구 해석, 인터페이스 결정, 확인할 시나리오와 기대 동작 결정, 미결 사항과 완료 여부 결정 | 되돌리기 어려운 일 |
| AI | 인터페이스 확인, 구현, 테스트 코드 작성, 문서 맞추기. 안쪽 구현은 맡기되 맞는지는 검증이 확인 | 되돌리기 쉬운 일 |
| 툴 | 커밋과 푸시마다 코드 검사와 빌드, 테스트를 자동 실행. 사람에게도 AI에게도 예외 없음 | 예외 없이 막아야 하는 일 |
테스트 코드는 AI가 쓰지만 무엇을 확인할지는 사람이 정해요. 셋 중 하나라도 빠지면 AI가 만든 코드가 그대로 제품이 돼요. 셋이 다 있어도 새는 곳이 있다는 것은 뒤의 결함 둘에서 드러나요.
사람이 하는 일의 공통점은 되돌리기 어렵다는 거예요. 구현은 틀리면 다시 짜면 되지만, 공개 API나 인터페이스는 한번 릴리스되면 쓰는 쪽 코드가 거기에 맞춰 짜여요. 아직 정하지 못한 값도 마찬가지예요. AI가 그럴듯한 임시 값으로 채워 두면 다른 코드가 그 값을 쓰기 시작하고, 나중에는 바꾸기 어려워져요. 그래서 반복적이고 매번 결과가 달라도 괜찮은 작업은 AI에게 맡기고, 결정이 필요한 일은 사람이 합니다.
개발 순서를 뒤집었어요
무엇을 남길지 정하려면 기준이 먼저 있어야 해요. 그래서 코드보다 기준을 먼저 만들었습니다.
보통은 요구를 듣고 코드를 짠 다음 테스트를 붙이고, 문서는 시간이 남으면 써요. 저는 이 순서를 뒤집었어요. 인터페이스를 먼저 정하고, 무엇이 되면 완료인지를 문장으로 적고, 그 문서를 기준으로 AI가 일할 규칙을 만든 뒤에야 코드를 짰어요. 다 짠 뒤에는 처음 적어 둔 완료 기준에 맞는지를 근거와 함께 확인했습니다.
인터페이스를 먼저 정하면 구현을 맡길 수 있어요
여기서 말하는 인터페이스는 바깥에 드러나는 공개 메서드와 이벤트, 에러 코드, 메시지 규약이에요. 인터페이스는 사람이 먼저 정하고, 그 안쪽은 AI가 채우고, 검증은 뒤에서 해요.
순서를 이렇게 뒤집은 이유가 비결정성이에요. AI가 다른 구현 100개를 내더라도 인터페이스가 고정돼 있으면 그 차이는 인터페이스 안쪽에만 머물러요. 쓰는 쪽이 보는 메서드와 이벤트는 사람이 정한 그대로예요. 함수 하나, API 하나도 마찬가지예요. 정해진 인자를 넣으면 약속한 값을 돌려주고 약속한 에러만 낸다면, 안쪽을 100번 다르게 짜도 믿을 수 있는 코드라고 생각해요. 그래서 제가 이해해야 하는 범위도 한 줄 한 줄의 구현에서 인터페이스와 검증 결과로 좁혀지고, 무엇을 넣으면 무엇이 나오는지는 제가 정했으니 남에게도 설명할 수 있습니다.
정하지 않고 두면 AI가 정해요. 아무도 정해 두지 않은 설계는 에이전트가 구현 도중에 정해 버리고, 그 결정은 돌릴 때마다 달라집니다.
정한 인터페이스는 PRD와 프로토콜 문서, API 명세에 적어 두었어요.
AI는 저장소에 적힌 것만 알아요
실무에서는 회의나 메신저에서 결정이 내려지는 일이 잦아요. 말로 업무가 전달되는 일도 많습니다. 왜 그렇게 짜는지, 무엇이 되면 끝인지, 어디까지 건드리면 안 되는지도 팀 안에서는 말하지 않아도 알아서 어디에도 적혀 있지 않아요. 이렇게 사람들 사이에서만 공유되고 문서로 남지 않은 지식을 암묵지라고 해요. AI는 이 암묵지를 전부 모릅니다. 제가 본 AI의 실수도 이 적히지 않은 곳에서 났어요.
AI는 모르면 지어내요. 제가 정한 기준이 저장소에 없으면 AI는 다른 기준으로 짜고, 그 결과를 저는 설명하지 못합니다. 그래서 결정은 저장소에 적고, 모르는 것은 묻게 했어요. 기준을 문장으로 적어 두면 AI에게도, 새로 온 동료에게도 그대로 넘어가요. 진행을 막는 미결은 그럴듯한 임시 값으로 채우지 않고 사람이 정합니다.
모델이 모르는 것만 적어요
그렇다고 많이 적을수록 나은 것은 아니에요. 모델이 저장소를 읽거나 학습으로 이미 아는 것을 다시 적으면 읽는 비용만 늘어요. 결과가 달라지는 것은 모델이 알 방법이 없는 것을 적었을 때라고 봐요. 저장소에만 있는 결정이 그쪽입니다.
그래서 세션마다 읽는 파일은 짧게 두었어요. CLAUDE.md는 9줄이고, 그중 한 줄이 AGENTS.md를 불러와요. AGENTS.md까지 합치면 세션마다 읽는 양은 90줄 정도예요. 여기에는 무엇이 공개 인터페이스인지, 어떤 문서가 무엇의 정본인지, 정본끼리 어긋나면 어떻게 하는지, 이 저장소에서 자주 틀리는 것처럼 모델이 읽어 낼 곳이 없는 결정만 적었습니다.
주제마다 믿을 곳을 하나 정했어요
문서를 쓰고 나니 같은 내용이 여러 곳에 생겼어요. 프로토콜 문서와 시퀀스 그림, 코드에 같은 내용이 조금씩 다르게 적혀 있었고, AI는 그중 아무거나 골라 썼어요.
그래서 주제마다 기준으로 삼는 곳을 하나씩 정했어요. 이걸 정본이라고 부르고, 주제마다 정본을 하나만 두는 방식을 SSOT(Single Source of Truth)라고 해요. 실시간 규약은 프로토콜 문서, 메시지 순서는 시퀀스 그림, 에러 코드는 코드, 서버 API는 API 명세가 정본입니다. 둘이 어긋나면 어느 쪽이 이기는지도 규칙으로 적어 두었습니다.
그 규칙이 답하지 못하는 충돌도 생겨요. 규칙에 없는 조합이거나, 이겨야 할 쪽이 명백히 틀린 경우예요. 이런 충돌에서 AI가 묻지 않고 한쪽을 고르면 제가 모르는 결정이 하나 생깁니다. 그래서 세션마다 읽는 파일에 이렇게 적어 두었어요.
어떤 문서가 기준인지 정하는 일은 AI에게 맡기지 않아요.정본끼리 어긋나면 어느 쪽이 맞는지 단정하지 않고 둘 다 보여주고 묻는다.
정본과 코드가 어긋나면 코드를 고치는 쪽으로 보되, 고치기 전에 어긋난 곳을 보여 주고 제 확인을 받게 했어요. 정본 자체를 바꿔야 한다면 그건 사람이 정합니다.
지금 정본은 개발이 쓰는 문서 안에만 있어요. 기획과 QA, 운영까지 같은 곳을 보고, 한 곳을 고치면 나머지가 따라오는 SSOT는 아직 못 만들었습니다.
문서를 기준으로 규칙과 절차를 만들었어요
문서를 써 두는 것만으로는 부족했습니다. 세션마다 그 문서를 다시 읽으라고 말해야 한다면, 어제 한 설명을 오늘 또 하는 것과 같아요. 그래서 문서를 기준으로 AI가 일하는 규칙과 절차를 저장소에 만들었어요. 이걸 하네스라고 부릅니다.
하네스가 지키려는 것은 하나예요.
추측 위에 코드를 쌓지 않는다.되돌리기 어려운 넷은 사람이 정해요
사람이 직접 정하는 것은 넷입니다. 진행을 막는 미결 사항, 공개 인터페이스 변경, 완료 여부, 커밋이에요. 앞의 책임 표에서 되돌리기 어렵다고 한 일들이고, 이 넷에 해당하면 에이전트는 진행하지 않고 저에게 물어요. 나머지는 하네스가 돌립니다.
하네스는 네 가지로 구성했어요.
| 구성 | 역할 | 이 프로젝트에서 |
|---|---|---|
| 스킬 | 절차. 누가 언제 무엇을 하는지 | 개발 스킬과 검증 스킬. 규모 판단, 인터페이스 확인, 설계 승인, 구현과 검증 반복, 문서 동기화, 완료 판단 순서 |
| 에이전트 | 역할. 산출물을 주고받는 단위 | 인터페이스 확정, 설계, 구현, 경계 검증, 문서 동기화. 각자 자기 컨텍스트에서 일하고, 만든 쪽이 검사하지 않음 |
| 룰 | 규약. 파일을 읽을 때 같이 적용 | 경로마다 붙은 코드 규약 15종 |
| 훅 | 강제. 무조건 실행되는 검사 | 저장과 커밋마다 실행 |
룰과 훅을 나눈 이유가 있어요. 룰은 권고입니다. AI가 읽고 따를 수도 있고 안 따를 수도 있어서, 룰에 적은 규칙은 세션마다 어겨질 수 있어요. 어기면 안 되는 것은 테스트나 훅으로 옮겨야 지켜집니다. 그래서 저장과 커밋마다 도는 훅이 막게 했습니다.
원칙은 세 가지였어요. 매번 읽는 것은 짧게 두고, 절차는 필요할 때만 불러오고, 무조건 지킬 것은 훅으로 강제합니다. 절차는 스킬에, 에이전트마다 맡을 일은 에이전트 정의 파일에 두고 필요할 때만 불러요.
매번 하던 설명이 한 줄이 됐어요
하네스 전에는 같은 설명을 매일 했고, 그래도 AI는 테스트를 주석 처리하고 커밋까지 했어요. 하네스 뒤에 제가 친 것은 한 줄이에요. 그 뒤는 스킬이 정한 순서대로 흘러가고, 진행을 막는 미결 사항과 설계 승인, 완료 판정, 커밋에서만 저에게 돌아와요.
만든 쪽은 채점하지 않아요
코드를 만든 에이전트와 검사하는 에이전트는 따로 두었어요.
모델이 자기 결과를 한 번 더 보는 것과, 다른 역할이 결과를 정본과 대조하는 것은 다르다고 봤어요. 앞의 것은 같은 판단의 반복이고, 뒤의 것은 기준이 다른 판단이에요. 다만 이 구조도 완전하지 않았습니다. 검증 절의 결함 둘이 그걸 보여 줍니다.
설명할 수 없는 하네스는 쓰지 않았어요
기존에 쓰던 하네스는 그대로 가져오지 않았어요. 12,085줄 가운데 7,887줄이 외부 스킬 하나였는데, 스킬 하나가 모든 일을 하면 어느 지시가 지금 동작에 영향을 줬는지 설명하기 어렵습니다. 제가 설명할 수 없는 하네스가 AI를 움직이면, 그 AI가 쓴 코드도 제가 설명할 수 없어요. 그래서 이 프로젝트에서만 알아야 하는 결정과 어기면 안 되는 것을 막는 훅만 남겨 다시 세웠습니다. 모델이 바뀔 때마다 무엇을 지울지는 이 시리즈의 첫 글에서 다뤘어요.
검증은 사용자가 쓰는 순서대로 해요
AI가 쓴 코드 중 무엇을 남길지 고르는 마지막 기준이 검증이에요. 검증 기준을 AI가 정하게 두면 AI가 쓴 코드를 AI가 채점하게 됩니다. 그래서 기준은 사용자가 실제로 쓰는 순서에서 뽑았어요.
참가자가 방에 들어와 화상 통화를 하고, 끊겼다 돌아오고, 나가는 흐름이 있어요. 이 흐름에서 시나리오를 뽑아 세 층에서 확인해요.
| 층 | 무엇 | 어떻게 |
|---|---|---|
| 자동 | 단위 테스트와 자동 검사 | 코드 옆의 작은 테스트가 값 검사와 오류 처리, 상태 변화를 확인. 빌드와 테스트, 코드 검사는 작업마다 자동 실행 |
| 반자동 | 브라우저를 실제로 띄우는 테스트 | 서버가 필요 없는 것은 자동으로, QA 서버가 필요한 것은 사람이 실행. 접속 정보가 없으면 스스로 건너뛰고 이유를 남김 |
| 사람 | TC와 브라우저 확인 | TC는 완료 기준과 PRD, 시퀀스 그림에서 뽑음. 번호마다 PASS, FAIL, 미검증 중 하나와 판단 이유 한 줄. 안 돌려 본 것은 통과로 치지 않음 |
제품 코드를 만든 에이전트는 검사하지 않게 했어요. 할 수 없었던 확인은 할 수 없었다고 적는 것도 규칙이에요. TC의 "미검증"이 그 칸입니다.
시나리오 하나를 예로 들면 이렇습니다.
- 전제: 참가자 두 명이 화상 통화 중
- 단계: 한 참가자의 네트워크가 끊겼다 돌아옴. 지하철이나 와이파이 전환처럼 실제로 자주 생기는 일
- 기대: 상대 화면에 이탈 알림이 뜨고, 돌아오면 같은 방에서 화상 통화가 이어짐. PRD에 적힌 동작이고, 브라우저 두 개로 확인
자동 검사를 전부 통과한 결함 둘이 QA에서 다시 열렸어요
자동 검사가 전부 초록이었는데 QA에서 다시 열린 결함이 둘이에요.
하나는 확인을 반만 한 경우였어요. 네트워크가 돌아왔는데도 다시 연결되지 않은 그 결함입니다. 명령을 보내는 코드는 맞았으니 테스트는 통과했고, 브라우저 두 개로 실제 화상 통화처럼 돌려 보고 나서야 잡았어요.
다른 하나는 테스트가 틀린 순서를 정답으로 굳힌 경우였어요. 메시지 순서가 틀렸는데 검사를 통과했습니다. 테스트는 실제 서버 대신 서버를 흉내 내는 가짜 서버와 메시지를 주고받는데, 그 가짜 서버가 틀린 순서도 받아 줬어요.
두 결함 모두 테스트가 본 범위가 사용자가 겪는 범위보다 좁았어요. 명령을 보낸 것까지만 봤고, 실제 서버라면 거부했을 순서도 받아 주는 가짜 서버로만 확인했습니다. 기능이 있다는 것과 사용자가 끝까지 쓸 수 있다는 것은 다른 판정입니다.
메시지 순서 결함은 정본과 맞물려 있어요. 순서가 곧 정답이라고 프로토콜 문서에 적어 두고도, 가짜 서버는 틀린 순서를 받아 줬습니다. 가짜 서버와 테스트 기댓값도 검증 대상인데, 그것들이 정본인 프로토콜 문서와 맞는지 확인하는 절차가 없었어요. 만든 쪽은 채점하지 않는다는 원칙을 제품 코드에만 적용하고 테스트 도구에는 적용하지 않은 것입니다.
정본과 대조하는 검증 역할을 두었는데도 놓쳤어요. 대조 대상에 테스트 도구가 빠져 있었습니다.
"이해했나"를 공개 API와 검증 결과로 한정한 제 기준의 한계도 여기서 드러났습니다. 설명하지 못하는 코드는 남기지 않는다고 했지만, 테스트 도구는 그 기준 밖에 있었어요. 검증 결과를 읽는다는 말에는 그 결과를 낸 검증 도구가 믿을 만한지 읽는 것까지 들어가야 했습니다. 초록이라는 결과만 읽으면, 테스트가 초록이라는 이유로 읽지 않고 병합하게 됩니다.
그래서 보완책을 넷 정했어요.
- 가짜 서버도 실제 서버만큼 엄격하게. 실제 서버가 거부하는 순서는 가짜 서버도 거부해야 합니다.
- 실제로 돌려 본 결과를 남기기. 명령을 보냈다는 로그가 아니라 다시 연결된 상태를 증거로 남겨요.
- 만들기 전에 재는 방법부터 정하기. 무엇이 일어나야 통과인지를 구현보다 먼저 적어요.
- 일부러 틀린 코드를 넣어 검사가 잡는지 확인하기. 뮤테이션 테스트의 발상이에요. 틀린 코드를 넣었는데도 초록이면 그 검사는 아무것도 확인하지 않고 있다는 뜻입니다.
숫자로 보여 줄 수 있는 것은 많지 않아요
개발자는 저 한 명이었어요. 커밋 메시지의 타입으로 세면 커밋 396개 가운데 문서 커밋이 126개로 셋 중 하나쯤이고, 기능 커밋 92개보다 많습니다. TC마다 판정과 판단 이유 한 줄이 붙어 있고, 공개 인터페이스가 바뀔 때마다 제가 하나씩 승인했어요.
인터페이스를 먼저 정하고, 정본을 두고, 만든 쪽과 검사하는 쪽을 나누는 습관은 AI 전과 같아요. 새로 생긴 일은 둘입니다. 세션이 끝나면 사라지는 기억을 저장소에 적어 두어야 하고, 그 저장소의 지시를 모델이 바뀔 때마다 다시 줄여야 해요.
다음에 해 볼 것도 정해 두었어요. 사용자 흐름 시나리오를 검증의 정본으로 두고 자동 테스트가 그 문장을 그대로 실행하게 하는 것, 하네스를 더 깎는 것, 개발 문서 안에만 있는 정본을 기획과 QA, 운영까지 넓히는 것이에요.
혼자라서 겪지 않은 문제가 있어요
이 프로젝트에서 리뷰어는 저 하나였어요. 그래서 리뷰 병목은 겪지 않았습니다. 팀이 되면 코드가 나오는 속도보다 사람이 그 코드를 이해하는 속도가 먼저 한계에 닿을 수 있고, 제 방식이 그때도 버틸지는 모릅니다.
혼자여도 피할 수 없는 문제도 있어요. AI를 감독하려면 코딩 역량이 필요한데, AI를 많이 쓸수록 그 역량이 약해질 수 있습니다. 결국 사람이 검증 구조를 설계하고 결과를 읽어야 해서, 그 사람의 코딩 역량이 약해지면 이 방식도 같이 약해집니다.
누군가 이렇게 묻는다면 이렇게 답해요
AI로 코드를 쓴다고 하면 동료나 팀장에게서 비슷한 질문을 받을 수 있어요. 면접에서도 나오는 질문이에요. 그중 셋에 이 글의 경험으로 답해 봤어요. 답의 순서는 셋 다 같아요. 기준을 말하고, 그 기준이 실패한 사례를 대고, 그 뒤에 바꾼 것을 말합니다.
할루시네이션은 어떻게 해결하나요?기준은 저장소에 없으면 없는 것으로 보고, AI가 모르면 묻게 하는 거예요. 그런데 지어내는 것만 문제가 아니었어요. 어제 한 말을 기억하지 못하고 여러 곳 중 아무거나 고르는 것도 같은 결과를 냈어요. 어제 정한 테스트 도구와 서버를 오늘 또 말해야 했고, 같은 내용이 여러 문서에 다르게 적혀 있으면 그중 아무거나 골라 썼습니다. 그래서 말로 하던 것을 저장소에 적고, 주제마다 정본을 하나씩 정했어요.
AI가 작성한 코드는 어떻게 믿나요?코드보다 검증 구조를 봐요. 만든 에이전트가 검사하지 않고, 사용자 흐름에서 뽑은 시나리오로 확인합니다. 그런데 그 검증 구조 안의 가짜 서버가 틀린 메시지 순서를 받아 줘서, 틀린 코드가 검사를 통과한 적이 있어요. 그 뒤로는 검사를 통과했다는 사실보다, 그 검사를 한 도구가 실제 서버만큼 엄격한지를 먼저 봐야 한다고 생각해요. 가짜 서버와 테스트 기댓값을 정본과 맞춰 보고, 일부러 틀린 코드를 넣어 검사가 잡는지 보기로 했습니다.
AI가 틀린 것을 알아챈 경험이 있나요?기준은 사용자 흐름에서 뽑은 시나리오였어요. 그런데 끊겼다 돌아오는 시나리오에서 테스트는 다시 연결하라는 명령을 보냈는지만 확인하고 있었고, 실제로는 다시 연결되지 않았습니다. 브라우저 두 개로 실제 화상 통화처럼 돌려 보고 나서야 알았어요. 그 뒤로는 기능이 있는지와 사용자가 끝까지 쓸 수 있는지를 따로 확인하고, 실제로 돌려 본 결과를 남기기로 했습니다.
무엇을 남길지는 제가 골라요
하네스 전의 대화에서 AI는 커밋하지 말라는 말을 어겼어요. 지금은 제가 요청할 때만 커밋해요. 다만 이 약속은 아직 룰이에요. 훅이 막는 것은 기본 브랜치에 바로 하는 커밋, 훅을 건너뛰는 커밋, 강제 푸시 같은 위험한 git 명령까지이고, 작업 브랜치에서 AI가 커밋하는 것 자체는 막지 않아요. 가장 먼저 어겨졌던 약속이 아직 룰에만 있어서, 다음에 훅으로 옮길 첫 후보예요.
AI는 여전히 매번 다른 코드를 내요. 그중 무엇을 남길지는 제가 먼저 정한 인터페이스와 정본, 사용자 흐름의 시나리오로 고릅니다. 그 기준에도 빈 곳이 있었고, 결함 둘이 QA에서 다시 열린 뒤에야 알았습니다.
이런 글도 읽어보세요
요즘 에이전트 하네스에 대한 고민
프롬프트 엔지니어링에서 컨텍스트 엔지니어링, 그리고 하네스 엔지니어링으로 빠르게 옮겨가는 AI 코딩 패러다임의 변화. 몇 달 만에 베스트 프랙티스가 낡아가는 시대에 무엇을 쫓고 무엇을 끝까지 남길지에 대한 개발자의 깊은 고민.
Claude Code Agent Teams로 AI 뉴스봇 만들기
Claude Code의 새로운 Agent Teams 기능을 활용해 AI 뉴스 요약봇을 병렬로 개발하는 과정을 단계별로 안내합니다. Agent Teams의 개념부터 셋업, 실전 앱 개발, 트러블슈팅까지 실무 관점에서 정리했습니다.