AI는 90%를 빠르게 만든다. 나머지 10%가 문제다
AI 코딩 도구를 팀에 붙이고 나면 초반 속도 향상은 체감이 확실하다. 보일러플레이트가 사라지고, 반복 패턴이 자동 완성되고, 스캐폴딩에 쓰던 시간이 줄어든다. 그런데 몇 주가 지나면 이상한 패턴이 보이기 시작한다. 빠르게 쌓인 코드가 어느 지점에서 딱 막힌다. 버그가 아니라 설계 판단이 필요한 지점에서.
dev.to에 올라온 두 편의 글이 이 현상을 각자 다른 각도에서 정확히 짚는다. 하나는 AI 생성 코드가 null, undefined, 빈 문자열을 구분 못 해 시스템이 무너지는 구조적 원인을 분석했고, 다른 하나는 실제 AI 에이전트를 운영하면서 마주친 '90% 완성 역설'을 증언한다. 이 두 관찰을 같이 놓고 보면, AI가 실패하는 지점의 패턴이 꽤 선명하게 드러난다.
AI가 "올바른 코드"를 짜도 시스템이 무너지는 이유
AI 코딩 도구는 해피 패스에 최적화되어 있다. 이상적인 입력, 명확한 계약, 예상된 흐름을 가정하고 코드를 생성한다. 그래서 출력물은 "기술적으로 맞아" 보인다. 문제는 현실이 개입하는 순간이다.
null을 정확히 보내야만 작동하는 시스템. 클라이언트가 undefined를 보내거나 필드를 아예 빠뜨리거나 빈 문자열을 넘기면 크래시가 난다. AI 입장에서는 본 패턴을 그대로 복제했을 뿐이고, 틀린 게 없다. 하지만 설계 관점에서 이건 명백한 실패다. 시스템이 입력의 미묘한 변형 하나에 무너진다는 건, 경계 정규화와 유효성 검증 로직이 잘못된 위치에 있거나 아예 없다는 신호다.
Robert C. Martin의 Clean Architecture가 강조하는 핵심은 간단하다. 시스템은 변화에 살아남도록 설계되어야 한다. 유즈케이스 레이어가 "무엇이 유효한가"를 정의해야 하고, 그 판단이 컨트롤러나 프레임워크 글루 코드에 흩어져 있으면 안 된다. AI는 이 질문 자체를 묻지 않는다. 'absence'가 무엇을 의미하는지, 이 필드가 필수인지 조건부인지, 빠졌을 때 기본 동작은 무엇인지—이 의미론적 경계는 사람이 명시적으로 정의해줘야만 AI가 올바르게 따를 수 있다.
에이전트도 같은 벽에 부딪힌다
이론적 한계가 아니라 실전 증거가 있다. Contenox Beam이라는 AI 에이전트를 직접 운영한 엔지니어가 목격한 장면이다. 에이전트에게 코드베이스 탐색을 요청했더니, 로컬 셸 실행을 시도하다 보안 정책에 막혔다. hook_policies 설정 하나면 10초에 해결되는 문제였다. 그런데 에이전트는 그 fix를 안내하는 대신, 스크립트에 정해진 안전한 응답으로 폴백하면서 수동 터미널 명령을 설명하기 시작했다.
이게 바로 90-10 법칙의 AI 버전이다. 처음 90%는 빠르게 처리한다. 그런데 컨텍스트를 벗어난 마지막 10%—설정이 빠졌거나, 예상 외 상태가 발생했거나, 계약이 명시되지 않은 경우—에서 에이전트는 스크립트를 이탈하지 못하고 멈춘다. 반면 엔지니어는 "지금 이 상황에서 스크립트를 벗어나 직접 고쳐야 한다"는 판단을 내린다. 이 판단 능력이 AI와 사람의 실질적 차이다.
완전 자동화 파이프라인이 보여주는 것
Command Garden 프로젝트는 흥미로운 대조군이다. 매일 하나의 피처를 완전 자동으로 제안·심사·구현·테스트·배포하는 파이프라인이다. AI가 후보를 생성하고, Claude·GPT·Gemini가 점수를 매기고, 승자가 자동 구현된다. 오늘 배포된 커뮤니티 반응 집계 기능은 기존 데이터를 재활용해 추가 API 호출 없이 구현됐고, E2E 테스트까지 자동 생성됐다.
이 파이프라인이 잘 작동하는 이유를 뒤집어 보면 답이 나온다. 자동화가 가능한 구간은 이미 계약이 명확하게 정의된 구간이다. 어떤 데이터를 쓸지, 어떤 컴포넌트 패턴을 따를지, 빈 상태일 때 어떻게 숨길지—이 모든 규칙이 사전에 설계되어 있기 때문에 AI가 실수 없이 실행할 수 있다. 새로운 판단이 필요한 영역에서는 여전히 AI끼리 점수를 겨루는 '심사' 단계가 사람의 기준을 대리한다.
팀이 설계해야 할 세 가지 경계
AI 도구를 팀 워크플로우에 붙일 때, 진짜 설계 작업은 도구 선택이 아니라 이 경계를 그리는 일이다.
첫째, 입력 정규화 경계. API 진입점에서 null, undefined, 빈 값을 단일 내부 표현으로 수렴시키는 레이어가 명시적으로 존재해야 한다. AI가 생성한 컨트롤러 코드를 그대로 믿으면 이 레이어는 없거나 잘못된 위치에 있다.
둘째, 유효성 검증의 책임 위치. 프레임워크 레이어에서 검증하는 건 편리하지만 위험하다. "이 값이 없으면 어떻게 된다"는 비즈니스 결정은 유즈케이스 레이어에 있어야 한다. AI는 이 배치 판단을 하지 않는다.
셋째, 명시적 실패 계약. 에이전트나 AI 도구가 막히는 지점은 대부분 계약이 암묵적으로 가정된 구간이다. 실패 모드를 코드 주석이 아니라 테스트와 명세로 명시해두면, AI도 그 계약을 따라 코드를 생성하고 에이전트도 폴백 대신 올바른 처리를 할 수 있다.
AI에게 맡길 것과 팀이 들고 있을 것
솔직히 말하면, AI가 생성한 코드의 90%는 검토 없이 써도 되는 수준까지 올라왔다. 반복 코드, 패턴 스캐폴딩, 테스트 케이스 초안—이 구간에서 망설일 이유가 없다. 문제는 나머지 10%를 AI가 처리했다고 착각하는 순간이다.
설계 판단, 의미론적 경계 정의, 변화에 대한 내성 설계—이건 AI가 "못 한다"기보다, 팀이 먼저 명시적으로 정의해줘야 AI가 따를 수 있는 영역이다. AI-First 워크플로우에서 팀의 역할이 줄어드는 게 아니라 올라가는 이유가 여기 있다. 구현을 위임할수록, 설계 결정의 명확성에 대한 요구 수준이 높아진다.
지금 당장 팀에서 할 수 있는 가장 실용적인 첫 걸음은 이것이다. AI가 생성한 코드 중 마지막에 디버깅하느라 시간을 가장 많이 쏟은 구간을 목록으로 만들어라. 그 목록이 바로 팀이 설계 계약을 명시해야 할 경계 지도다.