- AI가 생성하는 코드의 양과 규모가 기하급수적으로 증가하면서, 기존의 수동 코드 리뷰 방식이 더 이상 유효하지 않은 상황
- AI 도입률이 높은 팀은 작업 완료량이 21% 증가하고 PR 병합은 98% 늘었지만, PR 리뷰 시간은 91% 증가하는 역설적 현상 발생
- 코드를 직접 검토하는 대신 스펙과 수용 기준(Acceptance Criteria) 을 리뷰하는 상류 검증으로 인간의 역할이 이동해야 함
- 단일 검증 게이트 대신 다중 에이전트 경쟁, 결정론적 가드레일, BDD, 권한 시스템, 적대적 검증 등 스위스 치즈 모델 기반의 다층 신뢰 구조 필요
- "빠르게 배포하고, 모든 것을 관찰하고, 더 빠르게 되돌리는" 방식이 느린 리뷰 후 프로덕션 디버깅을 대체하는 새로운 패러다임
인간은 이미 코드 리뷰를 감당하지 못하고 있음
- PR이 며칠씩 방치되고, 형식적 승인이 이루어지며, 리뷰어들이 500줄짜리 diff를 훑어보는 것이 현실
- 코드 리뷰는 품질 게이트로 여겨지지만, 라인별 리뷰 없이 수십 년간 소프트웨어를 출시해 온 팀이 존재하며, 코드 리뷰가 보편화된 것은 2012~2014년경
- 리뷰가 있어도 장애는 발생하며, 이에 대응해 feature flag, 점진적 롤아웃, 즉시 롤백 같은 시스템을 구축해 옴
모든 코드를 읽는 것을 포기해야 함
- AI 도입률이 높은 팀에서 변경 건수와 변경 크기 두 가지가 동시에 기하급수적으로 증가 중
- 10,000명 이상의 개발자, 1,255개 팀 데이터 기반(Faros 분석)
- 개발자들은 AI 생성 코드 리뷰가 동료 코드 리뷰보다 더 많은 노력이 필요하다고 체감
- 수동 코드 리뷰로는 이 싸움에서 이길 수 없으며, 코드 리뷰는 현재 작업 형태와 맞지 않는 과거의 승인 게이트
AI 코드 리뷰도 여전히 '리뷰'일 뿐
- AI가 코드를 작성하고 AI가 리뷰한다면, 예쁜 리뷰 UI를 띄울 이유가 없음
- AI 코드 리뷰 도구는 시간을 벌어줄 뿐이며, 이러한 리뷰는 개발 주기의 왼쪽(shift left) 으로 이동하게 될 것
- CI 리소스를 낭비하고 리뷰 사이클 사이에 버전 관리를 할 이유 없음
- 에이전트가 코드를 작성하는 환경에서 "새로운 눈"은 같은 맹점을 가진 또 다른 에이전트일 뿐이며, 가치는 승인 게이트가 아닌 반복 루프에 있음
- "한 번 AI가 멍청한 짓을 하는 걸 봤으니 항상 확인해야 한다"는 본능은, 수동 검증이 가능했을 때는 합리적이었지만 현재 규모에서는 더 이상 실행 불가능
코드 리뷰에서 의도(Intent) 리뷰로 전환
- 인간의 체크포인트를 상류(upstream) 로 이동해야 함
- 소프트웨어 개발에서 체크포인트가 이동한 선례 존재: 워터폴 사인오프 → 지속적 통합(CI)
-
스펙 기반 개발(Spec-driven development) 이 AI 협업의 주요 방식으로 부상 중
- 인간은 스펙, 계획, 제약조건, 수용 기준을 리뷰해야 하며, 500줄짜리 diff를 리뷰할 필요 없음
- 새로운 패러다임에서 스펙이 진실의 원천(source of truth) 이 되고, 코드는 스펙의 산출물
- 코드를 리뷰하는 것이 아니라 단계(steps)와 검증 규칙(verification rules), 코드가 이행해야 할 계약(contract)을 리뷰
- Human-in-the-loop 승인이 "이것을 올바르게 작성했는가?"에서 "올바른 제약조건으로 올바른 문제를 풀고 있는가?" 로 전환
- 가장 가치 있는 인간의 판단은 코드 생성 이후가 아닌 첫 번째 줄이 생성되기 전에 발휘됨
다층 신뢰 구축 — 스위스 치즈 모델
- LLM은 명령을 잘 따르지 않고 빈번히 이탈하며, 자기 검증에도 신뢰할 수 없음(코드가 타는 중에도 자신 있게 "작동한다"고 답변)
- 해결책은 LLM에게 검증을 요청하는 것이 아니라, 검증하는 스크립트를 작성하게 하는 것 — 판단에서 산출물로 전환
- 신뢰는 층층이 쌓이는 구조이며, 스위스 치즈 모델에 따라 불완전한 필터를 겹겹이 쌓아 구멍이 정렬되지 않도록 함
Layer 1: 다중 옵션 비교
- 하나의 에이전트에게 정답을 요구하는 대신, 세 개의 에이전트가 서로 다른 방식으로 시도하고 최선의 결과를 선택
- 선택은 수동일 필요 없으며, 가장 많은 검증 단계를 통과하는 것, 가장 작은 diff, 새로운 의존성을 추가하지 않는 것 등 기준으로 순위 매김 가능
- 옵션의 비용이 소프트웨어 엔지니어링 역사상 가장 낮은 수준
Layer 2: 결정론적 가드레일
- 작업을 검증하는 결정론적 방법 필요 — 테스트, 타입 체크, 계약 검증 등 의견이 아닌 사실만 다루는 것
- LLM에게 "이거 됐어?"라고 묻는 대신, 일련의 pass/fail 산출물을 생성하는 검증 단계를 정의
- 가드레일의 계층 구조:
-
코딩 가이드라인 — 커스텀 린터로 구현 가능
-
조직 전체 불변 규칙 — 하드코딩된 자격증명, API 키, 토큰 금지 등 비협상 사항
-
도메인 계약 — 프레임워크, 서비스, 코드베이스 영역별 규칙 (예: 결제 도메인에서 모든 금액은 Money 타입 사용)
-
수용 기준(Acceptance Criteria) — 작업별 고유 기준
- 검증 단계는 코드 작성 전에 정의되어야 하며, 이미 있는 것을 확인하기 위해 사후에 만들면 안 됨
- 에이전트가 코드와 테스트를 모두 작성하면 문제를 이동시킨 것에 불과하며, 검증 기준은 구현이 아닌 스펙에서 나와야 함
Layer 3: 인간이 수용 기준을 정의
- 인간이 가치를 더하는 지점은 상류에서 성공의 정의를 내리는 것
-
BDD(Behavior-Driven Development) 가 새롭게 관련성을 가짐
- 자연어로 기대 행동을 기술하고 이를 테스트로 자동화하는 방식
- 과거에는 코드도 작성해야 했기에 스펙 작성이 추가 작업처럼 느껴졌지만, 에이전트 환경에서는 스펙이 1차 산출물
- 인간이 스펙을 작성하면 에이전트가 구현하고, BDD 프레임워크가 검증 — 실패하지 않는 한 구현을 읽을 필요 없음
- 인간이 잘하는 일: "올바름"의 정의, 비즈니스 로직과 엣지 케이스의 인코딩, 잘못될 수 있는 것에 대한 사고
- 인간이 작성하고 기계가 검증하는 수용 기준이 실제로 중요한 게이트
Layer 4: 권한 시스템을 아키텍처로
- 에이전트가 무엇을 건드릴 수 있고 무엇이 에스컬레이션을 필요로 하는지가 아키텍처 결정이 되어야 함
- 대부분의 에이전트 프레임워크는 권한을 올오어낫싱(all-or-nothing) 으로 처리하지만, 세분화가 중요
- 유틸리티 함수 버그를 수정하는 에이전트에게 인프라 설정 접근 권한이 불필요
- 테스트 작성 에이전트에게 CI 파이프라인 수정 권한이 불필요
- 범위는 에이전트가 유용한 작업을 할 수 있는 한 최대한 좁아야 함
- 예: "utils/dates.py의 날짜 파싱 버그 수정" 작업이면 해당 파일과 테스트 파일만 접근 허용
-
에스컬레이션 트리거도 중요: 인증 로직 수정, 데이터베이스 스키마 변경, 새 의존성 추가 등 특정 패턴은 에이전트의 확신도와 무관하게 자동으로 인간 리뷰를 트리거
Layer 5: 적대적 검증
- 책임 분리: 하나의 에이전트가 작업하고, 다른 에이전트가 검증 — 서로를 신뢰하지 않는 것이 핵심
- QA 팀이 엔지니어링 매니저에게 보고하면 안 되고, 코드 작성자만이 리뷰하면 안 되는 것과 같은 오래된 패턴
- 아키텍처적으로 강제 가능: 코딩 에이전트는 검증 에이전트가 무엇을 확인할지 모르고, 검증 에이전트는 코드를 수정할 수 없음 — 설계상 적대적
- 더 나아가 세 번째 에이전트가 첫 번째 에이전트가 만든 것을 엣지 케이스와 실패 모드를 겨냥해 파괴 시도 — 레드팀/블루팀 자동화를 모든 변경에 적용
"좋은 코드"의 의미가 변하고 있음
- 에이전트 시스템의 인센티브는 단순: 주어진 작업을 완료하고, 지시한 사람을 만족시키는 것 — 장기적 정확성이나 비즈니스 요구사항이 본질적 동기가 아님
- 이를 제약조건에 인코딩하는 것이 인간의 역할
- 에이전트가 생성하고 에이전트가 읽는 코드에서 "좋은 코드"의 형태는 더 표준화될 것이며, 새로운 코드베이스에서 제공해야 할 방향이 줄어듦
- 미래의 방향: "빠르게 배포하고, 모든 것을 관찰하고, 더 빠르게 되돌림"
- 반대: "느리게 리뷰하고, 어차피 버그를 놓치고, 프로덕션에서 디버깅"
- 기계를 더 많이 읽어서 이길 수 없으며, 결정이 실제로 중요한 상류에서 기계를 능가하는 사고가 필요
- 에이전트가 코드를 잘 처리할 수 있다면, 인간이 그 코드를 읽을 수 있는지 여부는 더 이상 중요하지 않음