
AI가 생성한 코드를 「운영 가능한 상태」로 만들기──결핍을 보완하는 사이클의 설계
요약
AI가 생성한 코드를 실제 운영 환경에서 신뢰할 수 있는 상태로 만들기 위한 분업 설계와 프로세스를 다룹니다. 인간은 목적 정의와 범위 관리에 집중하고, 구현과 리뷰, 수정은 AI가 수행하는 사이클을 통해 코드의 결핍을 보완하는 방법을 제시합니다.
핵심 포인트
- AI는 주어진 스코프 내에서만 정합성을 유지하므로 인간의 범위 정의가 필수적임
- 하지 않을 일을 결정하는 '실행 범위 관리'가 AI 코딩의 핵심
- 고병렬 환경에서의 원자적 업데이트 및 취소 처리 등 신뢰성 문제 해결 필요
- 구현, 리뷰, 수정 PR 과정을 AI에게 맡기고 인간은 승인과 방향성에 집중
AI에게 코드를 작성하게 했다. 작동했다. 리뷰를 통과했다. 운영 환경에 투입했다. 망가졌다.
이전 기사에서 이 시나리오를 썼다. 이번에는 그 후속편이다. 「결핍을 어떻게 보완할 것인가」라는 질문에, 구현으로 답을 내린 기록이다.
문제의 재정의
이전 결론을 한 줄로 요약하면 다음과 같다.
AI는 「주어진 스코프(Scope) 내에서 정합성이 맞는 코드」를 생성한다. 스코프 밖에서 무슨 일이 일어날지는 인간이 정의해야 한다.
이것은 「AI의 한계」가 아니라 「분업의 설계」에 관한 이야기다. AI가 국소적으로 올바른 코드를 계속해서 내놓는다는 사실은 변하지 않는다. 바꿀 수 있는 것은 그 코드를 어떻게 다룰 것인가 하는 프로세스 측면이다.
그렇다면 실제로 무엇을 바꾸었는가.
세 가지 판단과 하나의 사이클
이번에 한 일은 단순해 보인다. MailKit.Pooling이라는 라이브러리를 만들고, 문서를 정비하고, 리뷰를 거쳐 수정했다. 하지만 중요한 것은 그 「만드는 방식」이다.
인간이 수행한 것은 단 세 가지뿐이었다.
목적의 정의. 「이전 기사에서 제기한 문제──per-request의 커넥션 생성, 망가진 세션의 재사용, reconnect storm, 맹목적인 리트라이(Retry)──를 구조적으로 봉쇄하는 라이브러리를 만든다」라는 방침을 결정했다. 무엇을 만들 것인가가 아니라, 무엇을 「만들지 않을 것인가」까지 포함하여 정의했다.
실행 범위의 관리. MailKit.Pooling의 문서에는 What It Does Not Do라는 섹션이 있다.
템플릿 렌더링, 알림 오케스트레이션(Notification Orchestration), 내구 큐(Durable Queue), 비-SMTP 트랜스포트(Non-SMTP Transport)의 추상화는 대상에서 제외한다고 명시했다. 이 경계선은 구현자(AI)가 아니라, 이 판단을 내린 인간이 그었다. AI는 「모든 것을 다 하려고 하는」 경향이 있다. 하지 않을 일을 결정하는 것은 인간의 일이다.
리뷰 결과에 따른 수정 지시. 리뷰는 XRefKit(자작 지식 관리 도구)로 진행했다. AI가 리뷰를 실시하여 구조적인 문제를 세 가지 검출했다. 그 결과에 따라 「수정하라」고 지시했다. 수정 PR(Pull Request)도 AI가 만들었다.
구현, 리뷰, 수정 PR, 모든 것을 AI가 수행했다. 인간이 수행한 것은 목적의 정의, 범위의 관리, 수정의 승인뿐이었다.
AI가 검출한 세 가지 문제
XRefKit의 리뷰가 내놓은 지적은 모두 「작동은 하지만 신뢰할 수 없는」 영역의 것들이었다.
waitingCallers의 비원자적(Non-atomic) 업데이트. SmtpPool.cs의 증감 처리가 Interlocked가 아닌 일반 ++/--로 이루어져 있어, 고병렬(High-concurrency) 시에 카운트가 깨진다. metrics와 diagnostics의 신뢰성에 직결되는 문제다.
취소(Cancel) 시의 cleanup 대기. 취소되었어야 할 SendAsync가 즉시 반환되지 않는다. cleanup 처리가 망가진 SMTP 연결에서 블록되어, 사용자의 CancellationToken이 이미 취소되었음에도 불구하고 매달려 있다. 「취소는 작업 중지의 의사 표시」라는 API 계약이 지켜지지 않고 있다.
cleanup 시의 원래 예외 덮어쓰기. cleanup에 호출 측의 토큰을 그대로 전달하고 있기 때문에, 해당 토큰이 나중에 취소되면 OperationCanceledException이 먼저 발생하여 원래의 SmtpSendFailedException으로 정규화되지 않는다. 이용자가 기대하는 Classification과 Attempts 정보가 손실된다.
2번과 3번은 근본 원인이 같다. cleanup은 「원래의 문맥에서 분리된 사후 처리」임에도 불구하고, 호출 측의 토큰에 의존하고 있었다. CancellationToken.None 또는 전용 내부 타임아웃으로 실행되도록 하고, 원래의 예외를 오염시키지 않는 설계로 함으로써 두 문제 모두 해결된다.
이러한 문제들은 코드를 읽어도 잘 보이지 않는다. 고병렬이나 에러 패스(Error path)라는 「운영 환경에서만 나타나는」 조건하에서 현상화된다. 이전 기사에서 말한 「검증할 기준을 가지고 있지 않았다」에 해당하는 영역이다. 이번에는 그 기준을 AI 스스로가 가지고 있었다.
결핍이 보완된 이유
왜 이번에는 잘 돌아갔는가.
이전의 실패 시나리오에서는 인간(주니어 엔지니어)이 AI에게 「문제를 풀어라」라고 계속 던졌다. AI는 매번 주어진 문제를 풀었고, 매번 다른 문제를 만들어냈다. 목적은 단 한 번도 전달되지 않았다.
이번의 차이점은 목적이 먼저 정의되어 있었다는 것이다. 「고병렬에서도 안정적으로 SMTP를 보낼 수 있을 것」, 「실패를 분류하여 이용자에게 전달할 것」, 「reconnect storm을 억제할 것」──이것들은 코드를 작성하기 전에 존재하고 있었다. AI는 그 스코프 안에서 구현했다.
실행 범위의 관리도 같은 구조다. What It Does Not Do의 경계선이 없었다면, AI는 알림 오케스트레이션(Notification Orchestration)이나 내구 큐(Durable Queue) 설계까지 시작했을지도 모른다. 경계를 설정함으로써 AI는 '주어진 스코프(Scope)' 내에서 일관성 있는 구현에 집중할 수 있었다.
리뷰도 마찬가지다. "코드를 보고 문제를 찾아라"라는 지시가 아니라, "이 코드가 고병렬(High-concurrency) 환경에서 신뢰할 수 있는가"라는 기준으로 리뷰를 시켰다. 기준이 외부에서 주어졌기에, AI는 국소적인 정합성 체크가 아니라 운영 문맥(Operational Context)에서의 문제 검출을 할 수 있었다.
이전 패턴:
문제 발생 → AI에게 보고 → AI가 국소적으로 수정 → 다른 문제 발생 → 반복
이번 패턴:
...
사이클이 돌아간 이유는 AI의 능력이 향상되었기 때문이 아니다. 인간이 전달하는 것이 변했기 때문이다.
인간이 담당하는 업무의 정체
이 사이클을 통해 인간이 담당한 업무를 다시 정리하면 세 가지가 된다.
목적의 정의. 무엇을 만들 것인가, 무엇을 만들지 않을 것인가. 이 판단은 AI에게 넘길 수 없다. AI는 주어진 스코프를 최대화한다. 스코프를 결정하는 것은 인간이다.
실행 범위의 관리. 어디서 멈출 것인가에 대한 판단. 이번 사례로 말하자면, 내구 큐나 알림 오케스트레이션을 "이 라이브러리 외부에 둔다"라고 결정한 것이다. 이 판단 없이는 구현이 끝없이 확장된다.
리뷰 결과의 인수. AI가 검출한 문제를 "수정해야 한다"라고 판단한 것은 인간이다. AI는 리뷰를 통해 문제를 보고했지만, 그것을 수정할지 여부는 인간이 결정했다.
이것들은 전부 "조정(Adjustment)"의 업무다. 목적을 관계자(자신, 이용자, 라이브러리) 사이에서 조정한다. 범위를 조정한다. 품질 기준을 조정한다. AI는 이 조정을 지원할 수는 있지만, 조정 그 자체를 담당할 수는 없다.
AI가 작업을 담당하고 인간이 조정을 담당한다. 이 구조가 기능할 때, "동작하는 코드"는 "운영 가능한 코드"에 가까워진다.
무엇이 변하고, 무엇이 변하지 않는가
이번 사이클에서 변한 것은 인간이 전달하는 것이다. "문제를 풀어라"가 아니라 "이 목적을 달성하라". "코드를 고쳐라"가 아니라 "운영 문맥에서 문제를 찾아라".
변하지 않는 것은 AI가 "주어진 스코프 내에서 일관성 있는 출력을 반환한다"라는 특성이다. 이것은 지난번이나 이번이나 같다.
지난번의 실패는 이 AI의 특성을 이해하지 못한 채 "문제 보고"를 스코프로 계속 전달했다는 점에 있다. 이번에는 이 특성을 전제로 하여, 인간이 스코프 설계를 담당했다.
MailKit.Pooling이라는 라이브러리는 그 결과로서 존재하고 있다. 문서의 What It Does Not Do 섹션은 스코프 설계의 흔적이다. XRefKit의 리뷰 지적 세 가지 포인트는 운영 문맥에서의 검증 기준이 존재했다는 증거다.
"AI가 생성한 코드에서 무엇이 결여되어 있는가"라는 질문에 대한 답은 지난번과 다르지 않다. 결여된 것은 코드 생성 능력이 아니라, 스코프의 정의와 운영 문맥에서의 검증 기준이다.
그것을 보완하는 것은 계속해서 인간의 몫이다.
참조
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기