---
title: '코드를 읽거나 설명할 줄 몰라도, 스펙을 만족하고 버그를 고칠 수 있다면 상관없을까'
tags:
  - ai
  - essay
  - code-review
  - software-engineering
  - testing
published: true
date: 2026-06-12
description: '스펙을 만족하고 버그를 고칠 수 있다면 코드를 읽을 줄 몰라도 될까. 이해는 사라지는 게 아니라 어디로 이동하는지를 따진다.'
thumbnail: /thumbnails/2026/06/do-you-need-to-read-code.png
---

## 개요

PR이 올라온다. 에이전트가 1차 리뷰를 달고, CI는 초록불이고, 기획은 승인을 보낸다. 정작 그 코드를 머지한 사람은 끝까지 읽지 않았다. 점점 흔해지는 풍경이다.

여기서 두 질문이 갈라진다. 하나는 검증이다. AI가 단 리뷰가 맞는지, 그 코드가 정말 스펙을 만족하는지 판단하려면 — 결국 누군가는 코드를 읽어야 한다. AI가 자신 있게 틀리는 지점을 알아채려면 코드뿐 아니라 모델이 어떻게 실패하는지까지 알아야 한다. 얼마 전 특정 환경에서만 터지는 버그를 에이전트에 맡겼더니, 흔한 용의자만 줄줄이 헛짚고 정작 범인인 조건문 한 줄은 끝내 못 짚었다. 내가 직접 코드를 읽고서야 잡혔다. 다른 하나는 성장이다. 코드 작성을 AI가 가져가는 시대에, 이제 막 시작하는 사람은 대체 무엇을 잘해야 하는가. 둘 다 쉽게 답이 안 나온다.

마침 이 주제를 정면으로 다루는 글이 연달아 나왔다. 리누스 토르발스는 [Open Source Summit 기조연설](https://thenewstack.io/torvalds-ai-programming-productivity/)에서 "코드 99%를 AI가 썼다"는 말에 화가 난다며, 그렇게 말하는 사람들의 코드 100%는 사실 컴파일러가 쓴 것이라고 받아쳤다. AI도 기계어→어셈블러→컴파일러로 이어진 추상화 도구의 연장선일 뿐이고, 시스템을 이해하는 사람만이 좋은 결과를 얻는다는 입장이다. Jimmy Koppel은 [Software Design in the Age of AI](https://self-service.mirdin.com/software-design-in-the-age-of-ai)에서 저수준 구현이 자동화될수록 고수준 설계 능력이 인간의 핵심 우위가 된다고 주장했다. Josh Collinsworth는 [반대 방향에서](https://joshcollinsworth.com/blog/productivity), AI가 실제 생산성보다 "생산적인 기분"을 만들어주는 것 아니냐며, 그 우위 자체가 어떻게 깎여 나가는지를 경고했다. 본인이 에이전트로 밀린 작업을 폭발적으로 처리했는데, 돌아보니 코드베이스는 나아졌을지 몰라도 자신은 나아진 게 없었고, 자기가 올린 PR을 방어할 수 없었다는 고백이다. 이건 기분 탓만은 아니다. METR이 숙련 오픈소스 개발자들을 대상으로 한 [통제 실험](https://arxiv.org/abs/2507.09089)에서, AI 도구를 쓴 작업은 실제로 19% _느려졌는데_ 참가자들은 자신이 20% 빨라졌다고 느꼈다. 표본이 16명으로 작아 일반화에는 한계가 있지만, 느낌과 실제가 정반대로 갈릴 수 있다는 것만큼은 분명히 보여준다.

세 글을 관통하는 질문을 하나로 압축하면 이렇다.

**코드를 읽거나 설명할 줄 몰라도, 스펙을 만족하고 버그를 고칠 수 있다면 상관없을까?**

좀 더 구체적으로 하면: QA가 통과시키고, 기획이 승인하고, 고객이 만족한다면 — 그 코드를 만든 사람이 코드를 읽을 줄 몰라도 되는가.

직관적으로 "그래도 읽을 줄은 알아야지"라고 답하고 싶어진다. 하지만 직관은 논증이 아니다.

## 찬성: 우리는 이미 코드를 읽지 않고 살고 있다

"상관없다"는 입장을 제대로 변호해보자. 약하게 세워서 두들기면 의미가 없다. 가장 강한 논증은 이렇다.

**첫째, 우리는 이미 그렇게 살고 있다.** 프론트엔드 앱에서 직접 작성한 코드의 비중은 전체의 1%도 안 된다. 나머지는 node_modules, 브라우저, V8, OS, 컴파일러, CPU 마이크로코드다. 이 거대한 코드 더미를 읽어본 사람은 없다. 전부 겉으로 드러나는 동작으로만 확인한다. 동작하는가, 테스트를 통과하는가, 문제가 생기면 메인테이너가 응답하는가. AWS 코드를 읽고 쓰는 사람은 없고, "고객이 OK"하는 방식으로 신뢰한다. 소프트웨어 공학은 처음부터 이해에 의한 신뢰가 아니라 인터페이스에 의한 신뢰로 굴러왔다. "코드를 읽을 줄 알아야 한다"는 주장은, 이미 99%에 적용하지 않는 규칙을 마지막 1%에만 선택적으로 들이대는 것이다.

**둘째, 코드 읽기는 목적이 아니라 그걸 대신 보던 신호였다.** 엔지니어링의 진짜 목표는 언제나 올바른 동작, 감당할 만한 비용, 고치기 쉬움이었다. 코드 읽기는 테스트가 비쌌던 시대에 그 동작을 미리 가늠하는 가장 싼 도구였을 뿐이다. 동작을 직접 확인하는 일이 충분히 싸고 촘촘해지면 — 자동 테스트, 타입 체크, 카나리 배포, 관측성, 고객 피드백 루프 — 대신 보던 신호는 쓸모가 줄어든다. 애초에 우리 스스로 캡슐화와 정보 은닉을 좋은 설계의 원칙으로 세웠다. 구현을 읽지 않아도 되게 만드는 것이 좋은 설계라고 수십 년간 가르쳐놓고, AI가 구현을 쓰니까 갑자기 구현을 읽어야 한다고 말하는 건 자기 원칙의 부정이다.

**셋째, 공학의 역사는 하위 레이어를 버려온 과정이다.** 기계어 → 어셈블리 → C → GC 언어 → 프레임워크. 매 전환마다 "진짜 엔지니어는 아래 레이어를 알아야 한다"는 사람들이 있었고, 매번 경제가 그들을 기각했다. 메모리 관리를 모르는 개발자가 주류가 됐고 아무 문제 없다. 토르발스 본인의 논리를 그대로 빌릴 수도 있다. 아무도 "내 코드 100%는 컴파일러가 썼다"고 말하지 않고, 컴파일러 출력을 읽어서 검증하는 사람도 없다. 툴체인과 테스트를 신뢰한다. 수리조차 이해를 요구하지 않게 됐다. 생성 비용이 0에 수렴하면 고장 난 것을 외과적으로 패치하는 대신 재생성하는 게 합리적이다. 실패 케이스를 테스트로 스펙에 추가하고, 재생성하고, 재검증한다. 인프라에서 이미 이긴 논리다. 고장 난 컨테이너를 고치는 사람은 없다. 재배포한다. [Cattle, not pets](http://cloudscaling.com/blog/cloud-computing/the-history-of-pets-vs-cattle/) — 서버를 이름 붙여 키우는 애완동물처럼 손으로 돌보고 고쳐 쓸 것인가, 망가지면 미련 없이 버리고 똑같은 새 인스턴스로 갈아끼우는 가축 떼처럼 다룰 것인가. 한 번 띄운 서버는 두 번 다시 수정하지 않고 통째로 교체만 한다는 [Immutable infrastructure](https://martinfowler.com/bliki/ImmutableServer.html)가 정확히 이 논쟁의 한쪽이었고, 그쪽이 이겼다. 사람이 일일이 손본 서버는 아무도 그 상태를 재현하지 못하는 "눈송이(snowflake)"가 되어 더 위험하다는 게 결론이었다. AI는 그 다음 레이어이고, 코드라고 다를 이유가 없다.

**넷째, "읽기로 잡을 수 있다"는 버그는 읽기로도 못 잡는다.** 가장 흔한 반론 — 보안 취약점, 레이스 컨디션, 한참 뒤에야 드러나는 버그는 QA가 못 본다 — 에 대한 답이다. 그런 버그는 코드 리뷰로도 못 잡는다. 인간 코드 리뷰의 결함 검출을 다룬 [연구들](https://dl.acm.org/doi/10.5555/2486788.2486882)이 시사하는 건, 리뷰의 실제 산출이 결함 발견보다 가독성·지식 공유에 가깝고, 얕은 문제는 잡아도 동시성·보안 버그는 놓친다는 것이다. 이런 부류의 버그를 실제로 잡아내는 건 원래부터 읽기가 아니라 퍼저, 정적 분석, 속성 기반 테스트, 카나리, 관측성, 침투 테스트였다. 전부 돌려봐야 드러나는 도구들이다. 선택지는 "읽기 vs 무방비"가 아니라 "허술한 사람 눈 vs 검증 장치 강화"이고, 모두에게 코드 읽기를 가르치는 데 쓸 자원으로 그 장치를 강화하는 게 더 합리적이다.

**다섯째, 이해는 스케일하지 않고 검증과 책임은 스케일한다.** 코드 생산량은 폭증하는데 사람이 읽어낼 수 있는 양은 정해져 있다. 안전 전략이 "인간이 읽는다"에 의존하면, 코드량이 늘수록 안전은 계속 떨어지기만 한다. 바람직하냐를 떠나 지는 전략이다. 테스트와 모니터는 컴퓨트와 함께 스케일한다. 책임도 마찬가지다 — 규제 산업에서조차 감독 당국이 요구하는 설명 가능성은 엔지니어의 머릿속 이해가 아니라 감사 추적, 의사결정 로그, 재현 가능한 빌드, 문서화된 테스트 증거로 충족된다. 책임은 머릿속 이해의 문제가 아니라 계약의 문제다. 은행들은 이미 아무도 완전히 이해하지 못하는 COBOL을 수십 년째 돌리면서 프로세스 증거로 감사를 통과해왔다. 규모를 키울 수 있는 쪽에 거는 것이 공학적 선택이다.

여기까지가 찬성 측의 최선이다. 솔직히 꽤 강하다. 특히 첫째와 다섯째는 정면으로 반박하기 어렵다. 그런데 이 논증 전체에는 구조적 결함이 하나 있고, 그 결함이 결정적이다.

## 그러나: 조건문의 전제가 순환이다

원래 질문으로 돌아가자. "스펙을 만족하고 버그를 고칠 수 있다면." 이 조건문을 뜯어보면 다섯 군데에서 무너진다.

### 1. "스펙을 만족한다"를 누가 어떻게 아는가

코드를 읽지 못하는 사람이 알 수 있는 것은 "테스트가 통과한다"이지 "스펙을 만족한다"가 아니다. 이 둘은 정확히 비싼 지점에서 갈라진다. 테스트는 작성자가 생각해낸 케이스만 검증하고, 실무에서 터지는 버그의 상당수는 스펙 위반이 아니라 **스펙의 공백**이다. 레이스 컨디션, 경계값, 보안 취약점, 며칠 뒤에 드러나는 데이터 정합성 깨짐.

더 근본적으로, QA와 고객은 **일어난 일**만 관측할 수 있고 **일어나지 않아야 할 일**은 관측할 수 없다. "PII가 로그에 남지 않는다", "재시도 시 중복 결제가 발생하지 않는다" 같은, 일어나면 안 되는 일은 수용 테스트에 보이지 않는다. 고객은 인젝션 취약점이 없다는 사실을 "OK"할 수 없다. 보이지 않기 때문이다.

즉 "스펙을 만족한다면"이라는 그 전제가 참인지 확인하는 일 자체가 시스템 이해를 요구한다. 질문이 답을 미리 끼워 넣고 있는 셈이다.

### 2. 수리는 외주할 수 있어도 탐지는 외주할 수 없다

"버그를 고칠 수 있다"는 "버그가 있음을 알아챘다"를 은근슬쩍 깔고 있다. 고치는 일은 AI에 넘길 수 있다. 그러나 무언가 잘못됐다는 알아챔 — 특히 테스트가 전부 통과하는데도 뭔가 어긋났다고 느끼는 것 — 은 시스템 이해 없이는 생기지 않는다. 병목은 수리가 아니라 탐지이고, 조건문은 정확히 그 병목을 건너뛰고 있다.

이런 버그의 전형이 Koppel이 짚은 '숨겨진 커플링'이다. 멀리 떨어져 서로 무관해 보이는 두 코드가 실은 엮여 있어서, 컴파일 에러도 테스트 실패도 없이 숨어 있다가 엉뚱한 변경에서 터진다. 코드를 읽을 줄 모르면 이런 버그는 고치기 이전에 존재조차 알 수 없다.

### 3. 선례들이 성립했던 조건이 여기엔 없다

찬성 측의 가장 강한 무기였던 선례 논증 — 컴파일러, node_modules, AWS — 을 다시 보자. 그 선례들에는 둘 중 하나가 항상 있었다.

- **입력의 뜻이 그대로 보존된다.** 컴파일러는 내가 이해한 입력(소스 코드)의 의미를 고스란히 지킨다는, 수십 년간 검증된 보장이 있다. 컴파일러가 틀리면 뉴스가 된다.
- **이해를 보유한 책임 있는 반대 당사자.** npm 패키지가 깨지면 메인테이너가 고치거나, 내가 이해를 갖고 포크한다. SaaS가 깨지면 벤더가 SLA를 진다.

AI 생성 코드는 인류가 처음으로 **둘 다 없이** 의존하는 코드다. 입력은 뜻이 다 담기지 못하는 자연어이고, 그 뜻이 그대로 지켜진다는 보장도 없다. 맞은편에는 책임지는 사람이 없고, 그때그때 다르게 답하는 기계가 있을 뿐이다. 토르발스의 컴파일러 비유가 수사적으로 강력하지만 절반만 맞는 이유가 이것이다. 컴파일러는 같은 입력에 늘 같은 출력을 내고 그 정확성이 보장되지만, LLM은 그렇지 않다. "둘 다 추상화 도구"라는 프레임은 이 검증 비용의 차이를 가려버린다. 선례는 적용되지 않는다.

그래서 규제가 있는 도메인에서는 이 논쟁이 애초에 닫혀 있다. Anthropic이 최근 공개한 [Zero Trust for AI Agents](https://claude.com/blog/zero-trust-for-ai-agents) 가이드조차 금융·건강·개인 데이터를 다루는 산업에서 모든 에이전트 행동을 트리거 입력까지 역추적하고 설명하는 능력은 선택이 아니라고 못박는다. 찬성 측이 들었던 "책임은 계약적"이라는 논리는 맞지만, 그 계약을 충족하는 감사 추적과 설명을 _생산하려면_ 누군가는 시스템을 이해하고 있어야 한다. 감독 당국 앞에서 "테스트는 통과했는데 코드는 아무도 모릅니다"는 답변이 되지 않는다.

### 4. 검증은 시점이고 소유는 지속이다

QA·기획·고객의 OK는 특정 시점, 테스트된 경로, 지금의 부하에서 그 순간을 찍은 사진 한 장이다. 소프트웨어 소유는 그 게이트 **이후에** 도착하는 것들에 대한 지속 의무다. 보안 사고, 트래픽 10배, 다음 기능의 변경 비용.

기획이 OK한 것은 지금 기능이지 다음 기능의 수정 비용이 아니다. 그 비용은 기획이 볼 수 없는 코드 구조가 결정한다. 모든 수용 게이트를 통과하면서 동시에 수정 불가능해져가는 코드베이스는 얼마든지 가능하다. 게이트 이후에 응답할 주체가 없는 구도에서 "OK 받았으니 끝"은 검증의 완성이 아니라 책임의 공백이다.

### 5. 재생성 루프는 이해를 제거하지 않고 이동시킨다

찬성 측의 "재생성이 수리를 대체한다"는 논리는 결국 스펙으로 되돌아온다. 실패 케이스를 스펙에 추가하고 재생성하려면, 무엇이 실패했고 무엇을 스펙에 박아야 하는지 알아야 한다. 그게 시스템 이해다.

그리고 이해 없이 수리와 재생성을 반복하면 경험적으로 무슨 일이 벌어지는지 Collinsworth가 묘사했다. 읽지 않은 패치가 쌓이고, 코드베이스 복잡도가 오르고, 복잡도가 오를수록 LLM의 효율 자체가 떨어진다. Koppel도 같은 관찰을 했다. 자사 계약자가 코드 품질이 낮은 회사로 옮기자 Claude Code의 효율이 급격히 떨어졌다는 것이다. 앞서 본 METR의 결과 — 느려졌는데 빨라졌다고 느낀다 — 가 이 루프를 위험하게 만드는 정확한 이유다. 효율이 떨어지는 와중에도 본인은 빨라졌다고 믿으므로, 멈춰야 할 신호를 스스로 받지 못한다. 루프가 영원히 돈다는 보장은 어디에도 없다. 오히려 루프 자체가 자기 효율을 갉아먹는 구조다.

한 문장으로 압축하면 이렇다.

**그 조건문이 참인지 확인하는 데 필요한 능력이, 바로 그 조건문이 불필요하다고 주장하는 능력이다.**

## 이해는 사라지지 않고 형태를 바꾼다: 검증 레이어

그럼 반대 측의 승리인가. 그렇게 단순하지 않다. 찬성 측의 첫째, 셋째, 다섯째 논증 — 우리는 이미 99%를 안 읽고, 공학의 역사는 레이어를 버려온 과정이고, 이해는 스케일하지 않는다 — 은 여전히 유효하다. 코드를 매일 한 줄씩 읽는 일이 줄어드는 흐름 자체는 부정할 수 없다.

내 결론은 이렇다. 방향은 찬성이 맞고, 시점과 형태는 반대가 맞다. 이해는 제거되는 것이 아니라 "코드를 일상적으로 읽는 형태"에서 "무엇을 검증해야 하는지 아는 형태"로 이동한다. 그리고 후자를 가진 사람은 필요할 때 전자도 할 수 있다. 같은 근육이기 때문이다.

이 이동의 도착지를 구체적으로 그려보면, 생성은 AI가 하는 파이프라인에서 **"이 출력이 맞다/틀리다를 판정하는 장치 전체"를 설계하고 소유하는 역할**이 된다. 나는 이걸 검증 레이어라고 부르고 있다.

의도 → 스펙 → **[생성: AI]** → 정적 게이트 → 테스트 게이트 → 선별적 인간 리뷰 → 카나리 → 런타임 모니터 → 장애 대응

생성 단계 하나만 AI의 것이고, 나머지 전부가 검증 레이어다. 구체적으로 여섯 가지 일로 분해된다.

**1. 스펙을 검증 가능하게 쓰는 일.** 핵심은 "무엇을 해야 하는가"가 아니라 "무엇이 일어나면 안 되는가"다. "주문 API는 멱등해야 한다", "재시도 시 중복 결제가 발생하면 안 된다". AI는 시키는 것을 만들지, 시키지 않은 것을 안 한다는 보장은 못 한다. 무엇이 일어나면 안 되는지를 아는 것이 시스템 이해이고, 이게 스펙에 박혀야 "테스트 통과 ≈ 정확함"이 성립한다.

**2. 테스트 전략 설계.** 테스트 코드 작성이 아니다. 그건 AI가 한다. 문제는 AI가 자기 코드에 맞춰 테스트를 쓰면 순환 검증이라는 것이다. 자기가 낸 답안으로 자기를 채점하는 구조. 검증 레이어의 일은 이 순환을 깨는 설계다. 늘 지켜져야 하는 규칙엔 속성 기반 테스트, 경계엔 컨트랙트 테스트, 테스트 자체의 품질엔 뮤테이션 테스팅. 어떤 종류의 실패에 어떤 검증 도구를 붙일지 정하는 일이고, 이 짝이 틀리면 테스트가 1만 개 있어도 구멍이 난다.

**3. 읽기의 선별적 배치(triage).** 전부 읽는 게 아니라 어디를 읽을지 결정하는 능력이다. 인증, 돈이 흐르는 경로, 동시성, 데이터 마이그레이션, 의존성 변경 — 영향 범위가 큰 5%에 인간의 눈을 배치하고 나머지는 자동 게이트에 맡긴다. 이 위험 분류 자체가 시스템 이해를 요구한다. 어떤 코드를 안 읽어도 되는지 판단하려면 읽을 줄 알아야 한다는 역설이, 여기서 직무가 된다.

**4. 런타임 검증 설계.** 머지에서 검증이 끝나지 않는다. 카나리 배포, 동작이 지켜야 할 규칙이 깨지면 울리는 알림, 그리고 이상이 생긴 순간부터 알아채기까지 걸린 시간과 울린 알림 중 실제로 조사된 비율의 측정. 정적 검증이 못 잡는 실패를 운영 단계에서 잡는 그물을 짜는 일이다.

**5. 검증기 자체의 검증.** AI 워크플로우에 들어간 에이전트들 — 리뷰 에이전트, 테스트 생성 에이전트 — 도 검증 대상이다. 인간 리뷰어와의 일치율, 오탐률, 그리고 실패 시 철수 기준. 내가 만들고 있는 리뷰 에이전트에도 8주짜리 판정 기준을 걸어뒀다. 효과를 수치로 입증하지 못하면 내린다.

**6. 최후의 보루.** 위 다섯이 전부 뚫렸을 때, 직접 코드로 내려가 읽고 디버깅할 수 있는 능력이다. 평소엔 안 쓴다. 하지만 이게 있어야 나머지 전부가 믿을 만해진다. 이게 없으면 1~5번은 검증이 아니라 그냥 프로세스 관리다. 로봇 수술 시대에 외과의사의 집도 횟수는 줄지만, 수술 못 하는 사람이 로봇을 감독하면 그건 의사가 아니라 행정가이고, 합병증이 터지는 순간 환자가 죽는다.

### 그리고 이해해야 할 시스템이 하나 늘었다

검증 레이어가 AI 이전의 시니어 역할과 다른 점이 하나 있다. 이해해야 할 시스템이 두 개가 됐다는 것이다. **소프트웨어 시스템(산출물)과, 그 소프트웨어를 생산하는 시스템(생성기).**

AI 이전에는 코드를 만드는 게 사람이었고, 사람이 어떻게 실수하는지는 감으로 알았다. 피곤하면 실수하고, 티켓을 잘못 읽고, 귀찮으면 테스트를 대충 쓴다. 리뷰어의 직관은 이 실패 모델 위에 서 있었다. 지금 만드는 쪽은 같은 걸 물어도 매번 답이 달라지는 기계이고, 실수하는 방식이 사람과는 딴판이다. 자신 있게 지어내고, 시키는 건 만들지만 시키지 않은 '하면 안 되는 것'은 모르고, 학습 데이터에서 가장 흔한 평범한 설계로 쏠리고, 자기 코드에 맞춰 테스트를 써서 제 답으로 제 답을 채점하고, 숨겨진 커플링에 구조적으로 약하다.

앞서 말한 그 사건이 전형적이다. 특정 개발 환경에서만 로그가 수십 배로 누적되는 문제였고, 에이전트에게 원인을 찾게 했다. 에이전트는 토큰을 한참 태우면서 IntersectionObserver, fetch 등 "중복 이벤트의 흔한 용의자들"을 차례로 헛짚었다. 실제 원인은 그런 게 아니었다. Next.js는 설정 함수의 첫 인자로 `PHASE_DEVELOPMENT_SERVER` 같은 phase 값을 넘겨주는데, 이 phase 비교 하나가 잘못되어 해당 환경에서만 의도와 다른 설정 분기를 타고 있었던 것뿐이다. 결국 직접 코드를 읽고서야 찾았다.

이 사건이 보여주는 건 모델의 실패 방식이다. 모델은 인과를 추적한 게 아니라, 학습 데이터에서 "로그 중복"과 자주 함께 등장한 패턴들을 순회했다. 그럴듯한 용의자 목록은 길게 뽑지만, 지루한 조건문 한 줄이 범인인 사건은 풀지 못한다. 그리고 그 과정 내내 에이전트는 대단히 생산적으로 _보였다_. 계속 무언가를 조사하고 있었으니까. Collinsworth가 말한 인식과 실제의 격차가 디버깅에서는 이런 모습으로 나타난다.

비슷한 사례가 하나 더 있다. Next.js 서비스의 성능을 개선해달라고, 별다른 지침 없이 코드베이스를 통째로 맡겨봤다. 에이전트는 서버와 클라이언트 코드를 부지런히 뒤지며 memo 추가, dynamic import, 불필요한 lazy initialization 같은 마이크로 최적화들을 찾아왔다. 틀린 건 아니었지만 본질이 아니었고, 에이전트 스스로도 이 변경들의 영향은 미미할 거라며 "이미 성능이 잘 나오도록 설계된 프로젝트"라는 결론까지 내렸다. 실제 문제는 코드가 아니라 의존성 트리에 있었다. 중복된 패키지와 서로 일치하지 않는 버전들이 같은 라이브러리를 번들에 여러 벌 싣고 있었고, 전체 번들 사이즈를 키우는 주범은 그것이었다. [이전 글에서 다뤘듯](https://yceffort.kr/2026/05/pr-diff-vs-bundle) 번들 비용은 개별 파일 레벨에서는 보이지 않는다. 에이전트는 파일 단위로 코드를 읽지만, 번들이 어떻게 짜이는지는 의존성 그래프 전체를 봐야 드러나는 성질이라 어떤 파일에도 적혀 있지 않다. "잘 설계됐다"는 판정은 자기가 볼 수 있는 레이어 안에서만 참이었고, 모델은 자기 시야 밖에 레이어가 있다는 사실을 모른 채 자기 시야를 전체로 보고했다.

흥미로운 건, 같은 에이전트에게 lockfile을 주고 "중복 의존성을 찾아라"라고 시켰다면 아마 잘 찾았을 거라는 점이다. 문제는 능력이 아니라 조준이었다. "성능을 개선해줘"라는 모호한 목표 앞에서 모델은 자기가 볼 수 있는 단위, 즉 개별 코드에서 최적화 거리를 찾을 뿐, 문제가 어느 레이어에 사는지를 판단하지 못한다. 그 판단이 시스템 이해이고, 사람이 조준을 잡아주지 않으면 모델의 능력은 엉뚱한 곳에서 소진된다.

두 사례는 실패의 방향이 다르다. 첫 번째는 깊이의 실패다. 인과를 끝까지 추적하지 못하고 그럴듯한 패턴을 순회했다. 두 번째는 넓이의 실패다. 문제가 사는 레이어를 특정하지 못하고 보이는 단위에서만 팠다. 공통점은 하나다. 둘 다 사람이 시스템을 이해하고 있어야만 교정할 수 있었다.

여기서 예상되는 반박이 있다. "더 좋은 모델에 더 많은 토큰을 주고 오래 분석시켰다면 결국 찾았을 것 아닌가." 부분적으로 맞는 말이다. 더 나은 도구를 붙이고 — lockfile 접근, 번들 분석기, bisect — 충분히 돌리면 두 문제 모두 결국 찾았을 가능성이 높다. 그래서 분명히 해두자면, 이 사례들은 모델의 한계 고발이 아니다. 반년 뒤의 모델은 이 버그들을 찾아낼지도 모른다.

여기서 두 가지가 드러난다. 하나는 시스템을 알면 어디부터 봐야 할지가 단번에 좁혀진다는 것이다. Next.js 설정 구조를 아는 사람은 "특정 환경에서만 발생한다 → 환경을 가르는 분기 → phase"로 몇 분 만에 도달한다. 그 지식이 없으면 코드, 설정, 인프라, 의존성이 전부 후보로 남는다. 살펴봐야 할 곳이 폭발하고, 토큰은 그 모든 곳을 일일이 뒤지는 비용이다. 둘 다 정답에 도달하더라도 드는 비용이 다르다.

더 본질적인 건 종료와 수용의 문제다. 이건 토큰을 더 쏟는다고 풀리지 않는다. 실제 사건에서 모델은 "못 찾겠다"로 끝나지 않았다. "이미 잘 설계된 프로젝트"라는 자신 있는 오답으로 종료했다. 토큰을 10배 줘도 같은 종료 행동이면 더 자신 있는 오답이 나올 뿐이다. 그리고 "결국 찾았을 것"이라는 가정 자체가 결과를 다 알고 난 뒤에야 할 수 있는 말이다. 정답을 이미 손에 쥔 사람만 할 수 있는 소리다. 무지 안에서는 언제 멈춰야 하는지도, 나온 답을 수용해도 되는지도 판단할 수 없다. 우리가 모델의 답이 틀렸음을 안 유일한 이유는 직접 읽고 진짜 원인을 찾았기 때문이다. "오래 돌리면 찾았을 것"이라는 그 가정은 이해 없이는 확인조차 할 수 없고, 그런 가정을 세울 자격부터가 이해하는 사람에게만 생긴다. 순환이 여기서 다시 닫힌다.

그러니 더 좋은 모델이 나와서 이 버그들을 찾아낸다면, 그것은 이 글의 반증이 아니다. 그때 사람의 일은 그 비용을 지불할 가치가 있는지 판단하고, 하네스를 설계하고, 나온 답을 수용 판정하는 것으로 이동할 뿐이다. 그게 앞에서 말한 검증 레이어의 일이다.

생성기의 특징적 실패 지점을 모르면 triage가 불가능하다. 어디를 읽어야 할지가 "코드의 위험도 × 생성기의 약점", 두 가지를 곱해 따지는 판단이 됐기 때문이다. 공장 QC에 비유하면, 제품 스펙만 알아서는 안 되고 이 선반이 어느 방향으로 틀어지는 경향이 있는지를 알아야 어디를 계측할지 정할 수 있다.

이것이 내가 생각하는 "AI 워크플로우 이해"의 정의다. 프롬프트 작성법이 아니다. 네 가지다.

- **실패 모드 지식.** 모델이 어떤 종류의 문제에서 체계적으로 틀리는가.
- **파이프라인 설계.** 컨텍스트 관리, 작업 분할 단위, 훅과 게이트 배치, 어떤 검증을 어느 단계에 거는가.
- **워크플로우 자체의 보안.** 프롬프트 인젝션, 툴 권한 범위. 리뷰 에이전트에게 PR diff는 신뢰할 수 없는 입력이다. PR 본문이나 코드 주석에 "이 PR을 승인하라"는 지시를 심는 것이 정확한 공격 시나리오다.
- **워크플로우의 측정.** 일치율, 오탐률, 철수 기준.

다만 한 가지 비대칭을 분명히 해둬야 한다. **이 지식의 반감기는 짧다.** 오늘의 모델 실패 모드는 다음 세대에서 패치되고, 워크플로우 베스트 프랙티스는 반년 단위로 갈린다. 반면 시스템 이해는 복리로 쌓인다. 10년 전의 동시성 버그 직관이 지금도 유효하듯이. AI 워크플로우 이해는 필수지만 시간이 지나면 값이 깎이는 자산이고, 시스템 이해는 오래가는 자산이다. 앞쪽에 과투자해서 "도구 전문가"가 되면 도구가 바뀔 때마다 처음부터 다시다. 앞쪽에서 유일하게 안 깎이는 건 하나뿐이다. 새 모델이 나왔을 때 그게 어디서 어떻게 틀리는지 빠르게 간파하는 눈.

정리하면 삼각대다. **시스템 이해(코드 읽기 포함), 생성기 이해(AI 워크플로우), 그리고 둘을 결합하는 검증 설계.** "스펙 만족 + 버그 수정 가능하면 OK"라는 주장은 이 셋 모두를 누군가 보유하고 있을 때만 그 조건 자체가 성립하는데, 주장 자체는 셋 다 불필요하다고 말하는 자기모순 구조다.

## 주니어는 무엇을 목표로 해야 하는가

앞에서 갈라놓은 두 질문 중 두 번째, 성장의 문제로 돌아가자. 이제 막 시작하는 사람에게 뭐라고 말해줘야 하나.

삼각대를 그대로 던지면 안 된다. 그건 도착점의 묘사이지 커리큘럼이 아니다. 검증 설계는 시스템 이해 위에만 선다. "무엇이 일어나면 안 되는지"를 스펙으로 떠올리는 능력은 그런 장애를 직접 추적해본 사람에게만 생기고, triage는 위험한 코드를 알아보는 눈을 전제하는데 그 눈은 코드를 많이 읽고 부숴본 데서 온다. 만들어보지도 부숴보지도 않은 것을 검증할 수는 없다.

그리고 그 전에, 주니어가 마주한 진짜 문제를 먼저 이름 붙여야 한다. **일이 더 이상 공짜로 훈련시켜주지 않는다.** AI 이전에는 업무 수행이 곧 실력 축적이었다. 에이전트와 일하는 지금은 업무를 잘 수행할수록 배우는 게 없을 수 있다. Collinsworth가 던진 "주니어가 3년간 아무것도 못 배우면 시니어는 어디서 나오나"가 정확히 이 문제다. 예전에는 일이 훈련이었는데, 이제 훈련을 따로 설계해야 한다.

목표를 한 문장으로 준다면 이것이다.

**AI보다 빨리 쓰는 사람이 아니라, AI가 틀렸음을 가장 빨리 알아채는 사람이 되어라.**

생성 속도는 모두에게 평등하게 주어졌으니 차별화가 아니고, 틀림을 감지하는 능력은 훈련 없이는 안 생기니 차별화다. 이걸 행동 규칙으로 분해하면 순서가 있다.

**1. 설명할 수 없는 코드를 머지하지 않는다.** 단 하나의 규칙만 남긴다면 이것이다. 모든 PR에 대해 "왜 이렇게 했고, 뭐가 잘못될 수 있는지"를 리뷰어 앞에서 설명할 수 있어야 한다. 이 규칙의 장점은 강제력이 자연스럽다는 것이다. AI 사용을 금지하지 않으면서, 읽기가 필요한 지점에서만 정확히 읽기를 강제한다. "PR을 열었지만 방어할 수 없었다"는 상태를 구조적으로 차단한다.

**2. 디버깅에 자원한다.** 장애와 근본 원인 분석은 AI 시대에 남은 마지막 자연 훈련장이다. 디버깅은 읽기를 강제하고, 가설 수립을 강제하고, 시스템 이해를 강제한다. 그리고 아직 외주가 안 된다. 장애가 터지면 구경하지 말고 들어가고, 포스트모템을 전부 읽어라. 무엇이 잘못될 수 있는지 아는 능력은 강의가 아니라 잘못된 것을 직접 추적해본 경험에서만 나온다.

**3. 작은 것이라도 유지보수까지 소유한다.** 만들고 버리는 사이드 프로젝트는 이제 훈련 가치가 거의 없다. 생성이 공짜이기 때문이다. 가치는 유지 단계에 있다. 6개월 이상 굴리면서 자기가 만든 것의 버그를 자기가 맞아보는 경험. 숨겨진 커플링과 스펙의 공백 같은 개념은 글로 배워지지 않고, 자기 코드가 부메랑으로 돌아올 때 체득된다. 열 개를 빨리 만드는 것보다 하나를 오래 운영하는 것이 나은 목표다.

**4. AI가 틀렸고 내가 잡은 사례를 기록한다.** 생성기 이해는 별도 학습이 거의 필요 없다. 매일 에이전트를 쓰면서 "이번 주에 모델이 자신 있게 틀린 것, 내가 어떻게 알아챘는지" 로그 하나를 유지하면 된다. 이것이 주니어 수준에서 당장 할 수 있는, AI를 의심하고 검증하는 훈련이고, 1번 규칙과 맞물려 자연스럽게 돌아간다. 틀림을 잡으려면 읽어야 하기 때문이다.

경고할 함정도 하나 있다. 주니어는 1번을 건너뛰고 워크플로우 숙련으로 직행하고 싶어할 것이다. 그쪽이 현대적이고 시장성 있어 보이기 때문이다. 더 나쁜 건 단기적으로는 시장이 그걸 보상한다는 것이다. 에이전트로 티켓을 빨리 쳐내면 생산적으로 보인다. 하지만 시스템 이해 없는 워크플로우 숙련은 최후의 보루 없는 프로세스 관리이고, 첫 대형 장애에서 정체가 드러난다. 그때는 이미 몇 년이 지나 있다.

마지막으로, 이건 주니어만의 숙제가 아니다. 예전에는 일이 이 순서를 자동으로 강제했는데 이제 아니므로, **순서를 강제하는 것은 시니어의 설계 책임이 됐다.** 리뷰에서 "이거 왜 이렇게 했어?"를 실제로 묻는 것, 장애 대응에 주니어를 의도적으로 투입하는 것, 머지 설명을 문화로 만드는 것. 주니어에게 목표를 주는 일의 절반은, 그 목표가 작동할 환경을 시니어가 만드는 일이다.

## 마치며

처음 질문에 답하자. 코드를 읽거나 설명할 줄 몰라도, 스펙을 만족하고 버그를 고칠 수 있다면 상관없을까.

정직하게 양보부터 하면, 상관없는 영역이 실존한다. 수명이 짧고, 영향 범위가 격리돼 있고, 실패가 즉시 보이고, 실패 비용이 낮은 소프트웨어. 일회성 스크립트, 프로토타입, 내부 도구. 이 영역에서 "그래도 이해해야 한다"고 우기는 건 낭만주의이고, 이 영역은 좁지 않으며 커지고 있다.

하지만 그 경계 바깥 — 오래 살고, 돈이 걸려 있고, 실패가 한참 뒤에야 드러나는 소프트웨어 — 에서는 조건문 자체가 성립하지 않는다. 스펙 만족을 확인하는 것도, 버그를 발견하는 것도, 어떤 코드에 이 논리를 적용해도 되는지 판단하는 것도 전부 이해를 요구하기 때문이다. "이 코드는 이해 안 해도 되는 코드다"라는, 어떤 코드인지 가려내는 판단부터가 이해 능력을 요구한다. 읽을 줄 모르는 사람은 자기 질문의 적용 범위조차 정할 수 없다.

그래서 최종 답은 이것이다.

**이해가 필요 없는 코드는 실존한다. 그러나 그 경계선은 이해할 줄 아는 사람만 그을 수 있다.**

읽기의 빈도는 줄어도 된다. 읽기의 능력은 줄면 안 된다.

> 이 질문을 코드 바깥으로 가져가면 어떻게 될까. 같은 논리를 기획·개발·디자인의 직군 경계에 적용한 다음 글 — [AI가 기획·개발·디자인의 경계를 지운다면, 무엇이 남는가](https://yceffort.kr/2026/06/when-job-titles-blur)로 이어진다.

## 참고 자료

- [Linus Torvalds Talks AI, Vibe Coding and Programmer Productivity](https://thenewstack.io/torvalds-ai-programming-productivity/) - The New Stack
- [Software Design in the Age of AI](https://self-service.mirdin.com/software-design-in-the-age-of-ai) - Jimmy Koppel
- [Is AI Actually Making Developers More Productive?](https://joshcollinsworth.com/blog/productivity) - Josh Collinsworth
- [Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity](https://arxiv.org/abs/2507.09089) - METR
- [Expectations, Outcomes, and Challenges of Modern Code Review](https://dl.acm.org/doi/10.5555/2486788.2486882) - Bacchelli & Bird (ICSE 2013)
- [Zero Trust for AI Agents](https://claude.com/blog/zero-trust-for-ai-agents) - Anthropic
