← 전체 글
앱 개발 개발자 게시됨 · · 작성자 ObjectStack Team

AI가 앱을 쓴 뒤: 그 diff를 리뷰하고 Merge할 수 있는가

AI는 돌아가는 앱을 빠르게 생성하고 CI도 통과할 수 있다. 진짜 문제는 아무도 전체를 이해하지 못하는 큰 PR에 누가 책임지고 Merge할 수 있느냐다.

AI가 앱을 쓴 뒤: 그 diff를 리뷰하고 Merge할 수 있는가
  • AI 코드 작성
  • 코드 리뷰
  • 메타데이터
  • 거버넌스
  • Vibe Coding
  • 트렌드 관점

결론부터 말한다: AI가 어떤 코드든 짜낼 수 있게 된 세상에서 ‘빨리 쓰는 것’은 더 이상 강점이 아니다 — 누구나 빠르니까. 진짜로 희소한 것은 그 Merge 버튼을 누를 배짱이 있느냐다. 그리고 그 배짱은 AI가 당신에게 건넨 것이 당신이 검토하고, 다스리고, 책임질 수 있는 물건이냐에 달려 있다.

이미 매일같이 벌어지고 있는 한 장면부터 보자.

한 엔지니어가 코딩 에이전트에게 “고객지원 환불을 처리하는 작은 앱을 하나 만들어 줘”라고 시켰다. 30분 뒤, 돌아가는 앱이 나왔다. 프런트엔드, API, 데이터베이스 마이그레이션, 테스트까지 빠짐없이 갖춰졌고 CI도 전부 초록불이었다. 그가 PR을 열자 한 줄이 눈에 들어왔다. +8,142 −0.

그리고 거기서 멈췄다.

이 8천 줄은 그가 쓴 것이 아니다. 단 한 줄도 읽어보지 못했다. 환불 금액 상한 검증은 어느 파일에 있지? 이 API가 남의 환불 기록까지 돌려주지는 않을까? 이걸 고치면 대사(정산) 처리까지 줄줄이 영향을 받지는 않을까? 알 수 없다 — 아무도 모르니까. CI가 초록불이라는 것은 ‘코드가 그 자체로 일관되게 돌아간다’를 증명할 뿐, ‘그것이 옳은 일을 하고, 허락된 일만 한다’를 증명하지는 않는다.

그에게는 두 가지 선택지가 있는데 둘 다 형편없다. 하나는 검토한 척하고 이를 악물며 Merge를 누르는 것 — 아무도 이해하지 못하는 블랙박스를 프로덕션에 밀어 넣는 일이다. 다른 하나는 정말로 이 8천 줄을 한 줄씩 읽는 것 — 그럴 거면 차라리 직접 짜는 게 낫다. 이것이 바로 AI 시대의 진짜 새로운 병목이다. 코드를 쓰는 것이 아니라, Merge를 누르는 것.

코드 작성은 상품화됐지만, ‘신뢰’는 그렇지 않다

지난 10년간 엔지니어의 희소 능력은 ‘그것을 짜낼 수 있다’였다. 이 능력은 AI에 의해 빠르고 철저하게 평준화되고 있다. 앱 하나를 생성하는 한계 비용이 0에 수렴하면 ‘빠름’은 더 이상 누구의 해자도 아니다 — 당신의 경쟁자가 부리는 에이전트도 똑같이 빠르니까.

그 대신 전면으로 떠밀려 나오는 것은, 줄곧 있었지만 코드 작성 비용에 가려져 있던 또 다른 일이다. 누군가는 이 코드에 책임을 져야 한다는 것. “이게 어떤 데이터를 읽었고, 어떤 동작을 할 수 있으며, 잘못되면 누구 탓이고, 감사로 추적은 되는가”에 답할 수 있는 사람이 있어야 한다. AI가 ‘쓰기’의 비용을 0으로 깎아낸 뒤로 ‘검토와 거버넌스’는 전체 과정에서 가장 비싸고도 가장 핵심적인 단계가 됐다. 검토 가능성, 그것이 AI 코딩 시대의 새로운 해자다 — 누가 더 많이 생성하느냐가 아니라, 누가 생성한 것을 자신 있게 출시할 수 있느냐다.

이것은 Vibe Coding 기술 부채AI Agent 파일럿이 프로덕션에 가지 못하는 이유 두 글에서 다룬 바로 그 이야기의 다른 한 면이다. vibe coding은 누구나 앱을 생성할 수 있게 만들었지만, 생성하고 나면 아무도 출시할 엄두를 못 낸다 — 아무도 검토할 수 없고, 아무도 보증할 수 없기 때문이다. 차이라면, 그 두 글은 기업과 의사결정자의 관점에서 본 것이고, 이 글은 당신 — Merge 버튼 위에 손가락을 올려둔 바로 그 사람 — 의 관점에서 본 것이라는 점뿐이다.

”다른 AI에게 검토를 맡기면 되지”가 고리를 닫지 못하는 이유

가장 자연스러운 반박은 이렇다. AI가 쓸 수 있으니, AI에게 리뷰를 맡기면 되지 않나? 코드 리뷰 에이전트, 자동 보안 스캔, 지금 다 있는데.

이 길은 일부는 막아주지만, 정작 치명적인 그 고리는 닫지 못한다.

다시 그 GET /api/refunds로 돌아가 보자. 그것은 모든 사람의 환불 기록을 돌려줬다 — 그런데도 거의 모든 자동 검사를 통과한다. 문법 오류 없고, 널 포인터 없고, 테스트도 있다(테스트 역시 같은 에이전트가 썼으니, 당연히 ‘환불을 조회할 수 있다’만 테스트했지, ‘남의 환불을 조회해도 되는가’는 테스트하지 않는다). AI 리뷰가 잘하는 것은 코드가 그 자체로 맞느냐다. 버그가 있는지, 알려진 취약점 패턴에 들어맞는지, 스타일이 일관적인지. 하지만 코드 바깥에 있는 세 가지 질문에는 답하지 못한다. 이 코드가 이 테이블을 읽어도 되는가? 이 동작이 이 돈을 건드려도 되는가? 이것이 우리가 원하는 비즈니스 규칙인가?

이 답들은 코드 안에 없다 — 권한 모델 안에, 승인 정책 안에, 비즈니스 의도 안에 있다. 두 AI가 서로 고개를 끄덕인다고 그게 거버넌스가 되지는 않는다. 감사인, 법무, 보안팀이 원하는 그 “누가 권한을 줬고, 누가 책임지는가”라는 답에는, 아무리 똑똑한 리뷰 모델이라도 서명할 수 없다. 그러니 “AI가 AI를 검토하게 하기”가 덜어주는 것은 사람이 코드를 읽는 체력일 뿐, 반드시 사람이 내려야 하는 ‘되는가/안 되는가’ 판단은 덜어주지 못한다. 문제는 다시 원점으로 돌아온다. 사람이 검토할 수 있어야 한다. 그런데 8천 줄은, 사람이 검토할 수 없다.

출구: AI가 당신에게 건넬 것을, 당신이 검토할 수 있는 크기로 줄여라

당신이 8천 줄을 검토하지 못하는 것과, 이 시스템이 반년 뒤에 썩어버리는 것은 같은 원인이다 — 그 한 덩어리의 구현을 아무도 진짜로 이해하지 못한다는 것(이것이 그 글에서 말한 “이해 부채”다).

그렇다면 AI가 내놓는 형태를 바꿔라. 구현을 생성하게 하지 말고, 선언을 생성하게 하라. 같은 환불 앱이라도 AI가 당신에게 건네야 할 것은 8천 줄의 코드가 아니라, 이런 메타데이터 diff다.

+ object: support_refund
+   amount: currency (min 0)
+ permission: support_agent
-   allowDelete: true        # 에이전트가 만든 초안은 권한을 너무 많이 줬다
+   allowDelete: false       # 검토 시 회수: 고객지원은 환불을 삭제할 수 없다
+ flow: refund_amount > 500 → 재무 승인 필요

이 십몇 줄은 당신이 한 줄씩 읽어 이해할 수 있고, 5분 안에 검토할 수 있고, 한 번에 롤백할 수 있다. 더 중요한 것은 마지막 몇 줄이다. 검토는 더 이상 “내가 이걸 다 읽을 수 있을까”가 아니라 **“이 권한이 맞는가, 이 승인 임계값이 합리적인가”**로 바뀐다 — 당신이 진짜로 판단할 수 있고, 또 당신이 판단해야 할 비즈니스 질문이다. 정보를 새게 만들던 그 GET /api/refunds는 여기서는 애초에 등장하지 않는다. support_refund의 읽기 권한은 “호출자의 권한에 따라”로 선언되고, 런타임이 이를 근거로 강제하니, 권한을 넘어서는 그 경로는 원천에서부터 막힌다.

그럼 구현은 어디로 갔나? 구현은 반복해서 감사받고, 모든 앱이 공유하는 하나의 런타임(ObjectOS)에 속한다. 앱마다 한 벌씩 새로 생성되는 것이 아니다. ‘해도 되는가’ — 읽어도 되는가, 삭제해도 되는가, 승인이 필요한가 — 는 8천 줄 속에 묻혀 운에 맡겨지는 것이 아니라, 런타임이 실행 시점에 강제한다.

진짜로 닫히는 고리

이것을 흐름으로 그리면, 사람이 늘 그 자리에 있되 코드 양에 파묻히지는 않는 닫힌 고리가 된다.

AI가 쓰고, 사람이 작은 diff를 검토하고, 런타임이 거버넌스하고, 에이전트가 경계 안에서 실행하는 닫힌 고리

④단계에 주목하라. 비즈니스 정의 자체가 객체와 권한을 선언하고 있으니, 런타임은 그것을 한 묶음의 거버넌스되는 도구로 투영한다 — 그래서 같은 에이전트가 이 앱을 ‘쓰기’만 한 것이 아니라, 이후 동일한 권한 경계 안에서 그 앱을 조작할 수도 있다(환불 조회, 환불 발행). 매 단계마다 신원이 붙고, 흔적이 남는다. 쓰기와 쓰임이, 하나의 거버넌스를 공유한다.

먼저 찬물부터 한 바가지

이 방식에는 경계가 있고, 그건 분명히 해둬야 한다.

첫째, 모든 것을 메타데이터로 바꿀 수 있는 것은 아니다. 완전히 새로운 실시간 알고리즘, 독자적인 렌더링 파이프라인은 여전히 진짜 코드가 필요하고, 여전히 누군가가 이를 악물고 그 부분을 리뷰해야 한다 — 메타데이터는 거기서 당신을 도와주지 못하며, 억지로 끼워 맞추면 오히려 일을 그르친다. 이 방식이 잘하는 것은 기업에서 90%를 차지하는, 반복해서 다시 만들어지는 비즈니스 시스템이다.

둘째, 신뢰는 옮겨졌을 뿐, 사라진 게 아니다. 당신은 더 이상 앱마다 그 구현을 일일이 리뷰하지 않지만, 그 신뢰를 그 런타임에 걸어 둔 것이다 — 그것은 한 번 제대로 감사받아야 하고, 지속적으로 유지보수되어야 한다. 그러나 계산을 해보자. 전통적인 방식에서는 AI가 앱을 하나 생성할 때마다 새로운 코드 덩어리를 다시 신뢰해야 한다. 메타데이터 방식에서는 런타임을 한 번 검토하면, 거기서 파생되는 모든 앱이 검증된 동일한 권한과 감사를 자동으로 물려받는다. 한 번 검토하는 것이 천 번 검토하는 것을 이긴다. 훨씬 수지맞는 거래지만, 어쨌든 거래이지 마법은 아니다.

맺으며

AI가 코드를 쓴다는 사실은 엔지니어를 실업으로 내몰지는 않겠지만, 엔지니어가 가장 지켜야 할 관문을 바꿔놓는다. “내가 짜낼 수 있는가”에서 “AI가 짜낸 것에 내가 서명할 배짱이 있는가”로.

그리고 당신이 서명할 배짱이 있느냐는, 거의 전적으로 AI가 당신 앞에 무엇을 내놓았느냐에 달려 있다 — 당신이 다 읽지도 못할 8천 줄의 구현이냐, 아니면 당신이 검토할 수 있고 런타임이 다스릴 수 있는 수십 줄의 선언이냐. 당신의 에이전트에게 코드를 잔뜩 쓰게 하지 말고, 당신이 검토할 수 있고 런타임이 떠받칠 수 있는 목표를 생성하게 하라.

npm i -g @objectstack/cli && os start

당신의 코딩 에이전트에게 “CRUD 하나 짜 줘” 한마디 대신 선언적이고 거버넌스 가능한 목표를 가리켜라 — 그러고 나서 다음 PR의 diff가 드디어 당신이 Merge를 누를 만큼 작아졌는지 보라.