코드의 죽음 보고서는 크게 과장되었다
Steve Krouse, Sophie Alpert, Joel Spolsky, Bret Victor, Dan Shipper의 글을 중심으로
AI 시대의 코드, 추상화, 복잡성, 그리고 인간 전문성에 관한 심층 해설
원문 출처
- Steve Krouse, “Reports of code’s death are greatly exaggerated” (2026년 3월 21일) — stevekrouse.com/precision
- Sophie Alpert, “Everyone is wrong about that Slack flowchart” (2024년 10월 30일) — sophiebits.com
- Joel Spolsky, “The Law of Leaky Abstractions” (2002년 11월 11일) — joelonsoftware.com
- Bret Victor, “Up and Down the Ladder of Abstraction” — worrydream.com
- Dan Shipper, “When Your Vibe Coded App Goes Viral—And Then Goes Down” (2026년 3월 20일) — every.to
목차
- 글의 배경과 전체 맥락
- CommitStrip 만화가 던지는 핵심 질문
- 영어 명세서의 함정: 정밀도의 환상
- 바이브 코딩(Vibe Coding)이란 무엇인가
- Dan Shipper의 실제 사례: 바이럴 앱과 장애 — 상세 분석
- Slack 알림 플로우차트: 복잡성의 극단적 사례
- Sophie Alpert의 반론: 모두가 잘못 보고 있다
- 추상화(Abstraction): 복잡성을 지배하는 유일한 도구
- Joel Spolsky의 누수하는 추상화의 법칙 — 심층 분석
- Bret Victor의 추상화의 사다리 — 시스템을 이해하는 방법론
- AGI 시대에도 코드는 죽지 않는다
- Val Town과 vtrr 프레임워크: 추상화의 실제 승리
- 코딩은 죽지 않았다: 인쇄기와 스토리텔링의 비유
- 공식 언어에 관한 명언들
- 다섯 글의 핵심 메시지 종합
1. 글의 배경과 전체 맥락
2026년 현재, 인공지능(AI)의 급속한 발전으로 인해 소프트웨어 업계 안팎에서 “코드가 곧 죽을 것”이라는 이야기가 끊임없이 나오고 있다. ChatGPT, Copilot, Cursor, Codex 같은 AI 도구들이 자연어로 설명하면 코드를 자동으로 생성해주기 때문에, 많은 사람들이 머지않아 프로그래머가 필요 없는 세상이 올 것이라고 주장한다. 팟캐스터 Sam Harris 같은 저명인사조차 “모두가 코딩은 끝났다는 데 동의한다, 이제 누구도 코딩을 배울 필요가 없다”고 자신 있게 말하기에 이르렀다.
이러한 흐름 속에서 Steve Krouse는 2026년 3월 21일 자신의 블로그에 “코드의 죽음 보고서는 크게 과장되었다(Reports of code’s death are greatly exaggerated)” 라는 제목의 에세이를 발표했다. 제목 자체는 마크 트웨인의 유명한 말 “내 죽음에 관한 보도는 크게 과장되었다”를 패러디한 것으로, 코딩의 종말론에 강하게 반박하는 글이다.
Steve Krouse는 Val Town이라는 플랫폼의 창업자로, 풀스택 JavaScript 개발자이자 프로그래밍의 미래에 관심이 많은 사상가이다. 그는 단순히 “코드는 중요하다”는 식의 방어적 주장에 머물지 않고, 정밀도(precision), 추상화(abstraction), 인간 인지의 한계, 그리고 AGI와의 관계를 연결지어 훨씬 더 깊고 풍부한 논증을 펼친다.
한편 Sophie Alpert의 글은 2024년 10월 작성된 것으로, Krouse의 글보다 1년 반 앞서 쓰였지만 Krouse가 자신의 에세이에서 핵심 사례로 직접 인용한다. Sophie Alpert는 전 React 핵심 팀원이자 엔지니어로서, 복잡성을 어떻게 다루어야 하는지를 Slack의 알림 플로우차트를 통해 구체적으로 보여준다.
이 두 글을 더 깊이 이해하기 위해서는 Krouse가 직접 언급하거나 논지의 뿌리를 이루는 세 편의 글을 함께 살펴보는 것이 필수적이다. Joel Spolsky가 2002년 발표한 “누수하는 추상화의 법칙(The Law of Leaky Abstractions)”, Bret Victor의 인터랙티브 에세이 “추상화의 사다리(Up and Down the Ladder of Abstraction)”, 그리고 Dan Shipper가 2026년 3월 직접 경험한 바이브 코딩의 실패와 교훈을 담은 글 “바이브 코딩 앱이 바이럴되고 다운됐을 때(When Your Vibe Coded App Goes Viral—And Then Goes Down)”가 그것이다. 이 다섯 편의 글은 독립적으로 쓰였지만 하나의 일관된 주제, 즉 “복잡성은 피할 수 없지만 좋은 추상화로 정복할 수 있으며, 그 과정에서 인간의 전문성은 대체되지 않는다”는 메시지로 연결된다.
2. CommitStrip 만화가 던지는 핵심 질문
Steve Krouse의 에세이는 CommitStrip.com의 4컷 만화를 인용하며 시작된다. 이 만화의 내용은 다음과 같다.
두 명의 개발자가 카페에서 대화를 나누고 있다. 한 명이 말한다: “언젠가는 코더가 필요 없어질 거야. 그냥 사양(specification)을 작성하면 프로그램이 스스로 만들어지겠지.” 다른 이가 열정적으로 맞장구를 친다: “맞아! 포괄적이고 정밀한 사양을 작성하면 프로그래머가 필요 없어질 거야!” 첫 번째 개발자가 다시 묻는다: “그런데 프로그램을 생성할 수 있을 만큼 포괄적이고 정밀한 프로젝트 사양을 업계에서 뭐라고 부르는지 알아?” 마지막 컷에서 그 답은 단 하나의 단어다: “코드(Code)”.
이 만화는 AI 코딩 논쟁의 핵심 역설을 아주 짧고 명쾌하게 포착한다. 자연어로 작성한 사양(specification)이 충분히 상세하고 정밀해진다면, 그 사양 자체가 이미 코드라는 것이다. 다시 말해, “코드 없이 프로그램을 만들겠다”는 꿈은 실제로는 코드를 다른 형태로 쓰는 것에 불과하다는 역설이다.
마지막 컷에서 사양이 결국 코드라는 말을 들은 개발자의 표정은 당혹스러움과 어색한 깨달음을 동시에 담고 있는데, Krouse는 바로 이 표정 하나가 이 만화의 모든 것을 담고 있다고 말한다. 우리가 자연어로 무언가를 설명할 때는 스스로 매우 정확하게 말하고 있다고 느끼지만, 그것을 실제로 구현 가능한 수준으로 정밀하게 만들려고 하면 그 느낌이 얼마나 착각이었는지를 깨닫게 된다는 것이다.
3. 영어 명세서의 함정: 정밀도의 환상
Krouse는 이 만화에 대해 버트런드 러셀(Bertrand Russell)의 말을 인용한다.
“모든 것은 당신이 정밀하게 만들려고 시도하기 전까지는 깨닫지 못하는 정도까지 모호하다.” — 버트런드 러셀
이것은 단순히 철학적 관찰이 아니다. 소프트웨어 개발 현장에서 수십 년간 반복되어온 실제 경험이다. 비즈니스 요구사항을 영어(또는 한국어 등 자연어)로 작성하면 처음에는 매우 명확해 보인다. 그러나 개발자가 그것을 실제 코드로 구현하려고 할 때, 사양에는 수십 개의 모호한 지점, 처리되지 않은 엣지 케이스, 상충되는 요구사항들이 드러난다.
예를 들어 “사용자가 메시지를 보내면 알림을 받아야 한다”는 명세는 직관적으로는 완벽해 보인다. 그러나 실제로 구현하려면 즉각 수십 가지 질문이 생긴다. 사용자가 이미 해당 채널을 보고 있을 때도 알림을 보내야 하는가? 방해금지 모드일 때는? 스레드 메시지는? @channel 멘션과 @here 멘션은 다르게 처리해야 하는가? 이미 모바일에서 알림을 봤으면 데스크톱에서는 생략해야 하는가? 이런 것들이 모두 사양서에 나오지 않은 채 개발자가 일일이 결정해야 하는 문제들이다.
프로그래밍은 글쓰기와 비슷하게, 하면서 점점 더 자신이 하려는 것을 명확하게 다듬어가는 반복적인 활동이다. Krouse 자신도 이 에세이를 무수히 많은 초안 수정을 거쳐 완성했다고 고백한다. 코드를 짜는 행위 자체가 요구사항을 더 잘 이해하게 만드는 인식론적 과정이라는 점에서, 코드는 단순히 목적을 달성하는 수단이 아니라 사고의 도구이기도 하다.
4. 바이브 코딩(Vibe Coding)이란 무엇인가
Krouse는 AI가 이 과정을 어떻게 변화시켰는지를 설명하면서 “바이브 코딩(Vibe Coding)”이라는 개념을 소개한다. 이 개념은 AI 연구자 Andrej Karpathy가 대중화시킨 것으로, 코드의 구체적인 구현을 AI에게 맡기고 개발자는 자연어 수준의 “느낌(vibe)”으로만 방향을 잡아가는 개발 방식을 말한다.
AI가 영어를 실행 가능한 코드로 점점 더 빠르고 정확하게 변환해주기 때문에, 개발자는 “버튼을 여기로 옮겨줘”, “색깔을 좀 더 파랗게 해줘” 같은 자연어 지시로 반응하면서 원하는 것을 점점 더 명확하게 구체화할 수 있다. AI가 만들어낸 결과물에 반응하면서 생각을 날카롭게 다듬어가는 이 방식은 매우 효과적이고 강력하다. 실제로 많은 비개발자들이 AI를 통해 처음으로 작동하는 앱을 만드는 데 성공하고 있다.
“바이브 코딩”이라는 표현이 완벽한 이유는, 이 방식이 코더를 자신의 영어 수준의 ‘바이브(느낌)’로 작동하게 해주면서도, AI가 만들어낸 아티팩트가 그 생각을 더 선명하게 만들어주는 피드백 루프를 제공하기 때문이다.
그러나 Krouse는 여기서 바이브 코딩의 근본적인 함정을 지적한다. 바이브 코딩은 자신의 바이브가 정밀한 추상화라는 착각을 준다는 것이다. 이 착각은 기능을 충분히 많이 추가하거나 규모가 충분히 커질 때까지는 드러나지 않는다. 그리고 어느 순간 이해하지 못한 하위 추상화 레이어에서 예상치 못한 버그가 등장하여 모든 것을 망쳐버린다. 이것이 Joel Spolsky가 말한 “누수하는 추상화의 법칙(The Law of Leaky Abstractions)”이 설명하는 현상이다. 이해하지 못한 채로 쌓아올린 추상화는 언제든 새어나온다.
5. Dan Shipper의 실제 사례: 바이럴 앱과 장애 — 상세 분석
5.1 Proof 앱과 바이럴의 역설
Dan Shipper의 경험은 바이브 코딩의 가능성과 한계를 동시에 극명하게 보여주는 가장 생생한 실제 사례다. Dan Shipper는 AI 글쓰기 플랫폼 Every.to의 공동창업자이자 CEO로, AI 도구에 열정적인 개발자다. 그는 AI를 적극 활용해 “Proof”라는 에이전트 네이티브 협업 문서 에디터를 개발했다.
Proof 개발 과정 자체가 이미 놀랍다. 그는 2026년 1월 초 처음 코드를 커밋했고, 최초에는 macOS 앱이었다. 그리고 출시 약 2주 반 전에 웹 전용으로 피벗했다. 최종 출시된 버전은 완성 후 단 10일 된 것이었다. 그럼에도 불구하고 그 기간 동안 Every.to의 핵심 내부 도구가 될 만큼 안정적인 앱을 만들었고, 소수의 열정적인 구독자들도 사용하고 있었다.
결과물은 인상적이다. 레포지토리에는 총 1,600개의 커밋, 600개 이상의 풀 리퀘스트, 약 14만 줄의 코드가 쌓였다. 비교를 위해, 2020년부터 2024년까지 풀타임 개발자 한 명은 연간 평균 417번의 커밋을 했다. Shipper는 압도적인 속도로 개발한 것이다.
그리고 앱이 출시되자 바이럴되었다. 출시 이후 4,000개 이상의 문서가 생성되었다.
그러나 바이럴되는 바로 그 순간, 서버가 내려가기 시작했다. 앱은 하루 종일 신비롭게 계속 크래시되었다. 사용자들은 중요한 문서에 접근하지 못했고, Shipper는 망신을 당했다. 출시 다음 날 새벽 4시, 그는 24시간 가까이 잠을 자지 못한 채 Codex 에이전트가 또 한 번 서버를 되살리려 시도하는 것을 지켜봐야 했다. 트레일 믹스를 초조하게 씹으며 자신이 이해하지 못하는 코드베이스 깊숙이 묻혀있는 버그를 Codex가 파고드는 것을 바라보는 그 경험을 그는 이렇게 묘사했다: “프로그래밍이라기보다 수학 올림피아드에서 가장 멍청한 참가자가 된 느낌.”
5.2 바이브 코딩의 새로운 병목지점들
Shipper는 이 경험을 통해 AI 코딩 모델이 어디서 한계를 보이는지를 구체적으로 파악했다.
첫째, 코딩 모델은 격리된 상태에서 문제를 고치려 할 때 엉망진창을 만든다. 코딩 모델은 먼저 뒤로 물러서서 근본 원인을 파악하는 대신 로컬한 문제를 즉각 고치려는 경향이 있다. 당신의 안내 없이는 코드베이스가 더 많은 문제를 야기하는 핫픽스들의 누더기가 될 위험이 있다.
둘째, 코딩 모델이 항상 최선의 실천법을 알고 있는 것은 아니다. Proof는 라이브 협업 문서 에디터를 구축하기 위한 오픈소스 라이브러리인 Yjs와 Hocus Pocus를 기반으로 만들어졌다. 앱의 최신 버전 작업을 시작한 지 일주일이 되자, Yjs에 대한 최선의 실천법이 GPT-5.4의 학습 데이터에 들어있지 않다는 것을 깨달았다. 이는 일부 명백한 아키텍처적 결함을 잡아내지 못하고, 특정 문제들에 대해 최적이 아닌 해결책을 추구한다는 것을 의미했다. 빌드를 시작하기 전에 모델에게 광범위한 웹 리서치를 하도록 요청하는 것이 대체로 문제를 해결했다. 하지만 이는 최선의 실천법이 웹에 존재해야 한다는 것을 전제로 하는데, 기업 소프트웨어를 다루거나 비공개 회사 라이브러리를 사용하는 경우에는 항상 그렇지 않다.
셋째, 코딩 모델은 결국 올바른 답을 찾아내겠지만, 시간이 걸린다. 위의 문제들이 있더라도 Codex는 결국 대부분의 문제를 해결했을 것이다. 그러나 올바른 답에 도달하려면 피드백 루프가 필요하다. Codex나 어떤 코딩 모델이든, 수정을 작성하고 나면 코드를 검토하고, 로컬에서 테스트하고, 스테이징 환경에서 테스트하고, 프로덕션 앱에 코드를 배포하고, 수정이 작동하는지 모니터링해야 한다. 작은 코드베이스에서 이 루프는 빠르다. 크고 복잡한 것에서는 몇 시간이 걸릴 수 있다.
5.3 인간 엔지니어가 사라지지 않는 이유
Shipper의 결론은 명쾌하다. 모든 버그 수정은 하나의 과학적 실험이다. 코딩 모델은 이 사이클을 단축할 방법이 없다. 수정을 가설로 세우고, 코딩하고, 배포하고, 모니터링하고, 수정이 작동하지 않으면 새로운 가설을 세우는 과정을 계속 반복할 수밖에 없다. 이 실험을 실행하고 기다리는 것만 할 수 있다. 비용은 앱의 복잡성이 커질수록 시간과 토큰 면에서 증가한다.
모델을 사용하는 경험 많은 엔지니어는 더 적은 실험을 진행한다. 그들은 망가진 시스템을 보고, 수년간의 자신의 실패한 실험들을 바탕으로 빠르게 가능성을 좁혀나간다. “아마도 X일 거야.” 이런 직감이 항상 맞는 것은 아니지만, 즉각적으로 안정적인 앱과 에이전트가 며칠 동안 문제를 추적하는 동안 계속 다운된 앱의 차이를 만들 만큼 충분히 자주 맞는다.
이것이 바로 소위 “할당 경제(allocation economy)”의 핵심이다. 희소한 자원은 지능을 어디에 집중시킬지를 아는 것이다. 전문성이란 점점 더 올바른 첫 번째 질문을 물을 수 있는 것, 가설을 좁히는 것, 더 적은 사이클을 낭비하는 것을 의미한다.
Shipper의 결론은 Krouse의 논지와 완벽하게 일치한다: “만약 바이브 코딩할 수 있다면, 바이브로 고칠 수도 있다. 다만 빠르게 고치지 못할 수도 있다.” 이는 중요한 뉘앙스다. AI는 코딩을 대체하는 것이 아니라, 코딩을 더 접근 가능하게 만들면서 동시에 진짜 전문성의 가치를 더 명확하게 드러낸다.
2026년 3월 17일, 모델들만으로 문제가 해결되지 않자 Shipper는 결국 트위터에 도움을 구하는 글을 올렸다.
“누가 Proof의 성능 문제를 몇 가지 찾아서 고치는 것을 도와주고 싶은 분 있나요? 이상적으로는 AI에 매우 긍정적인 분, yjs / hocus pocus 경험이 있는 분, 하루 이틀 같이 작업하고 싶은 분. DM 주세요.”
누군가 “왜 AI 에이전트 대신 사람을 찾느냐, 모델들이 충분히 스마트하지 않냐”고 물었고, Dan은 이렇게 답했다.
“라이브 협업은 그냥 미칠 듯이 어렵고 엣지 케이스가 엄청나게 많아요. 코드베이스가 이제 거대해져서 AI의 루프가 꽤 길어요. 이전 경험에서 어디를 건드려야 하는지 아는 사람이 훨씬 빠르게 움직일 수 있어요.”
또 다른 개발자인 WildPinesAI는 yjs의 잘 알려진 문제를 짚어주었다.
“yjs에서 교묘한 문제는 문서 크기 팽창입니다. CRDT는 모든 삭제에 대해 툼스톤(tombstone)을 유지하기 때문에 오래된 문서는 빠르게 무거워집니다. GC + 주기적 스냅샷이 많은 도움이 됩니다.”
Dan의 대답은 간단했다: “맞아요, CRDT가 정말 어렵더라고요!”
이 에피소드는 바이브 코딩의 한계를 완벽하게 보여준다. “라이브 협업”이라는 기능은 우리가 Google Docs나 Notion을 매일 쓰기 때문에 당연히 잘 아는 것처럼 느껴지고, 따라서 그 사양은 완벽하게 명확하게 느껴진다. 그러나 그것을 실제로 구현하는 것은 전혀 다른 문제다. CRDT(Conflict-free Replicated Data Type), 툼스톤 관리, 가비지 컬렉션, 분산 합의 알고리즘 등 일반적인 개발자가 결코 직관적으로 알 수 없는 깊은 하위 레이어의 복잡성이 있다.
Krouse 자신도 10년 전 협업 텍스트 에디터를 구현하려다 예상치 못한 복잡성의 악몽을 겪었다고 고백한다. 그리고 더 무서운 것은, 그게 뭐가 어려웠는지 지금은 기억조차 나지 않는다는 것이다. 이것이 복잡성의 또 다른 특징이다. 복잡성은 지루하고 불쾌하고 디테일과 엣지 케이스들을 기억하기 어렵게 만든다.
6. Slack 알림 플로우차트: 복잡성의 극단적 사례
복잡성이 얼마나 깊숙하게 숨어있는지를 보여주는 상징적인 예시로 Krouse는 Slack의 악명 높은 알림 결정 플로우차트를 소개한다.
이 플로우차트는 Slack 엔지니어링 팀이 2017년 3월 발표한 것으로, “이 사용자에게 알림을 보내야 하는가?”라는 단 하나의 질문에 답하기 위한 로직을 시각화한 것이다. 첫눈에 보기에 이 다이어그램은 충격적이다. 수십 개의 박스와 화살표가 서로 얽혀있고, 심지어 순환(cycle)하는 부분도 있다. 채널 알림 설정과 전역 알림 설정이 따로 처리되고, 스레드 여부, 하이라이트 단어 여부, 사용자의 현재 상태(DnD, 모바일, 데스크톱) 등이 복잡하게 교차한다.
“알림을 언제 보낼지 결정하는 것”은 직관적으로 매우 간단해 보인다. 그러나 실제 시스템에서 이 로직은 수십 가지 변수를 고려해야 한다.
- 채널이 음소거(mute)되어 있는가?
- 사용자가 방해금지(Do Not Disturb) 모드인가? DnD 오버라이드가 있는가?
- @channel, @everyone, @here 멘션인가? @channel 멘션이 억제(suppressed)되어 있는가?
- 스레드 메시지인가? 사용자가 해당 스레드를 구독하고 있는가? threads_everything 설정이 켜져 있는가?
- 사용자의 채널별 알림 설정은 무엇인가? (없음/전체/멘션/기본값)
- 기본값인 경우 전역 알림 설정은 무엇인가? (전체/멘션/DM만/하이라이트 단어만/없음)
- 메시지에 @mention이 포함되어 있는가? 하이라이트 단어가 포함되어 있는가? 사용자가 소유한 파일에 대한 댓글인가?
- 모바일 기기인가? 마지막 모바일 푸시 타이밍 임계값을 지났는가?
이것이 “알림 보내기”의 실제 복잡성이다. 우리가 일상에서 당연하게 느끼는 기능 하나가 실제 코드로 구현될 때 얼마나 많은 결정과 예외 처리를 담고 있는지, 이 플로우차트는 그것을 날것으로 드러낸다.
전직 Slack 직원들에 따르면 이 알림 로직은 Slack 코드베이스에서 가장 복잡한 부분 중 하나라고 한다.
7. Sophie Alpert의 반론: 모두가 잘못 보고 있다
Sophie Alpert는 2024년 10월 30일 “그 Slack 플로우차트에 대해 모두가 틀렸다” 라는 제목의 글을 발표한다. 그녀는 원본 플로우차트가 복잡하다는 것에는 동의하지만, 사람들이 이 다이어그램을 보고 “Slack의 알림 로직은 본질적으로 복잡하다”는 결론을 내리는 것은 잘못된 것이라고 주장한다. 정확히 말하면, 그 복잡성의 상당 부분은 다이어그램 자체가 나쁘게 설계된 데서 비롯된다는 것이다.
Sophie가 분석한 원본 다이어그램의 문제점은 크게 두 가지다.
첫째, 채널 알림 설정과 전역 알림 설정 질문이 완전히 별개의 경로로 분리되어 있다는 점이다. 두 설정은 옵션이 거의 동일하게 대응되는데, 이를 따로 처리하면 로직이 중복되고 다이어그램이 불필요하게 커진다.
둘째, 스레드 여부 확인과 하이라이트 단어 확인이 다이어그램 여러 곳에서 반복 등장한다. 각각 서너 번씩 등장하는 이 중복된 확인들은 다이어그램을 실제보다 훨씬 복잡하게 보이게 만든다.
Sophie는 이 다이어그램을 “리팩토링”하여 단 6개의 박스만으로 된 훨씬 단순한 버전을 제시한다. 이 새로운 다이어그램의 특징은 다음과 같다.
전체 흐름이 거의 선형(linear)으로 이루어진다. 각 체크 포인트에서 Yes 또는 No 결과가 즉각 최종 결론(알림 보내기 또는 보내지 않기)으로 연결된다. 채널 알림 설정이 없으면 전역 설정을 확인하는 방식으로 두 가지 설정을 하나의 박스에서 통합 처리한다. &&와 || 논리 연산자를 활용하여 별개였던 여러 박스를 하나의 조건으로 통합한다.
Sophie는 자신의 버전이 원본과 100% 동일하지는 않다고 솔직하게 인정한다. 예를 들어 원본 다이어그램은 @channel 멘션이 억제된 경우 어떤 상황에서도 알림을 보내지 않는다고 되어 있지만, 실제 Slack의 동작은 사용자 멘션이나 하이라이트 단어가 있으면 여전히 알림을 보낸다. 즉, 그녀의 목표는 원본 다이어그램에 버그-대-버그(bug-for-bug)로 호환되는 버전을 만드는 것이 아니라, 2017년 Slack의 실제 동작을 가장 정확하게 표현하는 다이어그램을 만드는 것이었다.
Sophie가 이 글에서 말하는 핵심 메시지는 이것이다: 복잡한 문제에 복잡한 해결책을 만드는 것은 쉽다. 복잡한 문제에 단순한 해결책을 만드는 것이 어렵다. 우리가 시스템을 어떻게 생각하고 어떻게 표현하느냐가 그 시스템이 얼마나 이해하기 쉬운가에 엄청난 영향을 미친다. 적절한 렌즈를 찾아내면 까다로운 문제가 딱 맞아떨어지면서 두 번째 다이어그램처럼 이해하기 쉬운 모습이 된다.
코드에서도 마찬가지다. 복잡한 로직을 잘 정의된 함수들로 분리하면, 각 함수는 독립적으로 검토하고 테스트할 수 있다. 다이어그램에서 하나의 박스가 몇 줄의 코드에 대응될 수 있고, 그 코드가 여러 데이터 소스를 불러와야 할 수도 있다. 하지만 개념적으로 같은 확인에 해당하는 것들은 하나의 박스로 묶어서 전체 의도를 이해하기 쉽게 만드는 것이 더 중요하다.
Sophie는 또한 자신의 다이어그램이 커버하지 못하는 복잡성도 존재함을 인정한다. 예를 들어, 방해금지 모드를 오버라이드하고 “어쨌든 알림 보내기”를 선택하는 경우는 어느 상황에 나타나야 하는가? 푸시 알림이 폰에 전송되었지만 데스크톱에서 읽거나 메시지가 삭제된 경우, 알림을 철회해야 하는가? 이런 문제들도 있으며 Slack의 알림 로직이 단순하다고 말하는 것은 아니다. 다만, 그것을 표현하는 방식을 개선할 여지가 크다는 것이다.
8. 추상화(Abstraction): 복잡성을 지배하는 유일한 도구
Krouse는 복잡성의 문제를 제시한 후, 인류가 이를 해결하는 핵심 도구인 추상화(Abstraction) 에 대해 논한다.
인간의 뇌에는 근본적인 한계가 있다. 인지심리학자 조지 밀러(George Miller)의 연구에 따르면 인간은 한 번에 7개(±2개) 정도의 것들밖에 생각할 수 없다. 그렇다면 어떻게 현대 소프트웨어처럼 수백만 줄의 코드로 이루어진 시스템을 이해하고 설계할 수 있을까? 답은 여러 개의 것을 하나로 압축하는 것, 즉 추상화다. 그리고 이것을 재귀적으로, 무한히 반복할 수 있기 때문에 인간은 무한한 복잡성을 정복할 수 있다.
Krouse는 Edsger Dijkstra의 말을 인용한다.
“추상화의 목적은 모호해지는 것이 아니라, 절대적으로 정밀해질 수 있는 새로운 의미론적 레벨을 만드는 것이다.” — Edsger Dijkstra
이것이 핵심이다. 좋은 추상화는 복잡성을 숨기는 것이 아니라, 그 복잡성을 이해하기 쉬운 단위로 재구성하여 새로운 레벨에서 정밀하게 다룰 수 있게 한다.
Sophie Alpert의 개선된 플로우차트가 바로 이 추상화의 승리다. 그녀는 채널 알림 설정과 전역 알림 설정을 하나의 단계로 통합하고, 반복되는 스레드/하이라이트 체크를 논리 연산자로 압축함으로써 전혀 다른 수준의 명확성을 달성했다. 로직이 더 단순해진 것이 아니다. 그것을 바라보는 프레임을 바꾼 것이다.
Krouse가 가장 좋아하는 추상화의 사례는 함수형 프로그래밍(functional programming), 특히 함수형 리액티브 프로그래밍(Functional Reactive Programming, FRP)이다. ReactJS와 TailwindCSS가 각자의 영역에서 이루어낸 것처럼, 좋은 추상화는 그 분야를 완전히 바꿔놓는다. 협업 텍스트 에디터는 근본적으로 복잡하지만, 그것은 ReactJS가 등장하기 전의 UI 개발이 복잡했던 것과 같다. 더 나은 추상화를 찾는 것이 항상 가능하고, 그것이 프로그래밍의 가장 아름다운 부분이다.
9. Joel Spolsky의 누수하는 추상화의 법칙 — 심층 분석
9.1 배경과 맥락
2002년 11월, 조엘 온 소프트웨어(Joel on Software) 블로그에 소프트웨어 공학사에서 가장 많이 인용되는 글 중 하나가 등재되었다. Joel Spolsky가 쓴 “누수하는 추상화의 법칙(The Law of Leaky Abstractions)” 이다. Krouse가 바이브 코딩의 위험성을 설명하며 직접 링크로 인용한 이 글은, 추상화의 본질적 한계를 다루는 가장 명쾌한 텍스트 중 하나다. 이 글은 20년이 지난 지금, AI 코딩 도구의 시대에 오히려 더 중요해졌다.
9.2 TCP/IP: 마법의 해부
Spolsky는 이 모든 논의의 출발점으로 인터넷의 근본 구성요소인 TCP 프로토콜을 선택한다.
TCP는 신뢰할 수 있는 데이터 전송 방식이다. 네트워크를 통해 TCP로 메시지를 보내면, 그것은 도착할 것이고 손상되거나 변형되지 않을 것이다. 그러나 TCP는 그 자체로는 신뢰할 수 없는 IP 프로토콜 위에 구축되어 있다. IP로 보낸 메시지 묶음들은 절반만 도착하거나, 다른 순서로 도착하거나, 손상된 채 도착할 수 있다.
Spolsky는 이를 설명하기 위해 재치 있는 비유를 사용한다. 브로드웨이 배우들을 자동차에 태워 할리우드로 보내는 방식을 상상해보라. 일부 차는 사고가 나고, 일부 배우는 술을 마시고 문신을 새기며, 도착 순서도 제각각이다. 이때 “Hollywood Express”라는 서비스가 등장해 배우들이 (a) 도착하고 (b) 순서대로 (c) 완벽한 상태로 배달된다고 보장한다. 그 마법은 바로 각 배우가 완벽한 상태로 도착했는지 확인하고, 그렇지 않으면 쌍둥이를 보내는 방식으로 이루어진다. 이것이 TCP의 마법이다.
이것이 컴퓨터 과학자들이 추상화(abstraction) 라고 부르는 것이다. 아래에서 일어나는 훨씬 더 복잡한 것에 대한 단순화다. 문자열 라이브러리는 컴퓨터가 숫자만큼 쉽게 문자열을 조작할 수 있는 척하는 방식이다. 파일 시스템은 하드 드라이브가 사실 특정 위치에 비트를 저장하는 회전하는 자기 원판들의 묶음이 아니라, 개별 파일들을 포함하는 폴더들의 계층 구조인 척하는 방식이다.
9.3 그러나 TCP도 누수한다
그런데 Spolsky는 한 가지 중요한 사실을 고백한다. 앞서 단순화를 위해 작은 거짓말을 했다는 것이다. TCP는 사실 메시지가 반드시 도착한다고 보장하지 않는다. 만약 반려동물 뱀이 컴퓨터로 연결되는 네트워크 케이블을 갉아먹어서 IP 패킷이 전혀 전달되지 못한다면, TCP는 아무것도 할 수 없다. 회사 시스템 관리자와 사이가 나빠져 과부하된 허브에 연결된다면, 일부 IP 패킷만 전달되고 TCP는 작동하지만 모든 것이 매우 느려질 것이다.
이것이 누수하는 추상화다. TCP는 신뢰할 수 없는 네트워크의 완전한 추상화를 제공하려 하지만, 때로는 네트워크가 추상화를 통해 새어 나오고 추상화가 완전히 보호해줄 수 없는 것들을 느끼게 된다. 이것이 Spolsky가 명명한 누수하는 추상화의 법칙이다.
모든 비자명한 추상화는, 어느 정도는, 누수한다.
9.4 누수하는 추상화의 실제 사례들
Spolsky는 이 법칙이 모든 곳에서 적용됨을 다양한 사례를 통해 보여준다.
배열 순회와 메모리: 2차원 배열을 대규모로 순회할 때, 가로로 하느냐 세로로 하느냐에 따라 성능이 급격히 달라질 수 있다. “나무결의 방향”에 따라 한쪽 방향은 다른 방향보다 훨씬 많은 페이지 폴트를 유발할 수 있고, 페이지 폴트는 느리다. 어셈블리 프로그래머도 큰 평면 주소 공간을 가진 것처럼 가장할 수 있어야 하지만, 가상 메모리는 그것이 사실 추상화일 뿐임을 의미한다. 그 추상화는 페이지 폴트가 발생할 때 누수하고, 특정 메모리 접근은 다른 것들보다 훨씬 더 많은 나노초를 소비한다.
SQL과 쿼리 최적화: SQL 언어는 데이터베이스를 쿼리하는 절차적 단계를 추상화하여, 원하는 것만 정의하고 데이터베이스가 절차적 단계를 알아서 처리하게 하려는 것이다. 그러나 어떤 경우에는 특정 SQL 쿼리들이 논리적으로 동등한 다른 쿼리들보다 수천 배 느리다. 유명한 예시로, 일부 SQL 서버들은 “where a=b and b=c”만 지정하는 것보다 “where a=b and b=c and a=c”를 지정하는 것이 극적으로 빠른데, 결과 집합은 동일함에도 불구하고 그렇다. 절차가 아닌 명세만 신경 써야 하는데, 때로는 추상화가 누수하여 끔찍한 성능을 유발하고 쿼리 플랜 분석기를 꺼내들어 무엇이 잘못되었는지 연구해야 한다.
NFS와 원격 파일 시스템: NFS나 SMB 같은 네트워크 라이브러리들은 원격 기계의 파일을 로컬인 것처럼 취급하게 해준다. 그러나 연결이 매우 느려지거나 끊어지면, 파일이 로컬처럼 동작하는 것을 멈추고 프로그래머는 이를 처리하는 코드를 작성해야 한다. “원격 파일은 로컬 파일과 같다”는 추상화가 누수하는 것이다.
C++ 문자열: C++ 문자열 클래스들은 문자열이 일급 데이터인 척할 수 있게 해주며, 문자열을 정수처럼 쉽게 다룰 수 있는 척하게 한다. 거의 모든 C++ 문자열 클래스들은 + 연산자를 오버로드하여 s + "bar"를 연결에 사용할 수 있게 한다. 그러나 세상 어떤 C++ 문자열 클래스도 "foo" + "bar"를 타이핑하게 해주지 않는다. C++에서 문자열 리터럴은 항상 char*이고 절대 string이 아니기 때문이다. 추상화에 언어가 막아주지 않는 누수가 생긴 것이다.
자동차와 날씨: 자동차에는 와이퍼, 헤드라이트, 지붕, 히터가 있어서 날씨 걱정을 추상화해주지만, 비가 올 때는 수막현상(hydroplaning)을 걱정해야 하고 비가 너무 강하면 앞이 잘 안 보여서 속도를 줄여야 한다. 날씨는 완전히 추상화될 수 없다.
9.5 법칙의 의미와 역설
누수하는 추상화의 법칙이 문제적인 이유는, 추상화가 우리의 삶을 원래 의도한 만큼 단순화해주지 않는다는 것을 의미하기 때문이다. C++ 프로그래머를 훈련시킬 때 char과 포인터 연산을 전혀 가르치지 않고 STL 문자열로 바로 넘어갈 수 있다면 좋겠지만, 언젠가 그들은 "foo" + "bar"를 작성할 것이고 정말 이상한 일들이 일어날 것이다. 그러면 결국 char에 대해 모두 가르쳐야 한다. ASP.NET 프로그래밍에서도 Visual Studio 마법사와 모든 코드 생성 기능들을 가르칠 수 있다면 좋겠지만, 뭔가 잘못되면 완전히 무슨 일이 일어났는지 이해하지 못할 것이다.
그리고 Spolsky는 역설적이지만 중요한 결론에 도달한다: 고수준 프로그래밍 도구와 더 나은 추상화들이 늘어날수록, 유능한 프로그래머가 되는 것은 점점 더 어려워진다. 모든 새로운 코드 생성 도구는 무언가를 추상화한다고 주장하지만, 추상화처럼 모두 누수한다. 누수를 유능하게 처리하는 유일한 방법은 추상화가 어떻게 작동하는지, 무엇을 추상화하는지를 배우는 것이다. 따라서 추상화들은 작업 시간은 절약해주지만, 학습 시간은 절약해주지 않는다.
이것이 바이브 코딩의 가장 근본적인 문제와 정확히 연결된다. AI는 코드를 생성하는 시간을 절약해준다. 그러나 그 코드 아래에 있는 추상화들을 이해하는 시간을 절약해주지는 않는다. Dan Shipper의 경험이 이를 완벽하게 증명한다. Yjs와 Hocus Pocus라는 추상화 위에 앱을 올렸지만, 그 추상화가 누수했을 때(CRDT의 툼스톤 문제가 터졌을 때) 대처하는 데 며칠이 걸렸다. CRDT가 어떻게 작동하는지 알고 있었다면, 또는 그 경험이 있었다면 훨씬 빠르게 해결했을 것이다.
10. Bret Victor의 추상화의 사다리 — 시스템을 이해하는 방법론
10.1 이론과 미지의 경계에서 설계하기
컴퓨터 인터페이스 및 인터랙션 연구자 Bret Victor는 “추상화의 사다리를 오르내리며(Up and Down the Ladder of Abstraction)” 라는 제목의 인터랙티브 에세이에서 시스템 설계의 근본적인 도전을 다루는 방법론을 제시한다. 이 에세이는 단순히 읽는 것이 아니라 직접 조작하고 탐험하는 경험을 제공한다는 점에서 독특하다.
Bret Victor는 에세이를 리처드 해밍(Richard Hamming)의 인용으로 시작한다.
“과학에서, 자신이 무엇을 하고 있는지 알고 있다면 그것을 해서는 안 된다. 공학에서, 자신이 무엇을 하고 있는지 모른다면 그것을 해서는 안 된다. 물론, 순수한 상태 중 어느 하나도 거의, 또는 전혀 볼 수 없다.” — 리처드 해밍, 과학과 공학을 하는 예술
이 인용은 실제 시스템 설계의 본질적 긴장을 포착한다. 완전히 이론으로만 설명될 수 없는 영역에서 우리는 어떻게 설계하는가? 바로 이 질문에 Victor는 답한다.
가장 흥미로운 엔지니어링 과제들은 이론과 미지의 경계에 놓여있다. 완전히 이론으로 예측할 수 있을 만큼 알려져 있지는 않지만, 희망이 없을 만큼 알려지지 않은 것도 아닌 그 경계에서 많은 시스템들이 창발적 행동(emergent behavior) 에 의존한다. 높은 수준의 효과가 낮은 수준의 상호작용들에서 간접적으로 생겨나는 것이다. 이런 경계에서 설계할 때, 도전은 시스템을 구축하는 것이 아니라 그것을 이해하는 것이다. 이론이 없는 상황에서 우리는 결정을 안내할 직관을 개발해야 한다. 따라서 설계 과정은 탐험과 발견의 과정이다.
10.2 추상화 레벨들 사이를 이동하기
Victor는 도시에 새로 이사했을 때 영역을 배우는 비유를 든다. 직접 걸어다니면서 배울 수도 있고, 지도를 보면서 배울 수도 있다. 그러나 둘 다 함께 사용하는 것이 훨씬 효과적이다. 거리 수준의 경험과 더 높은 수준의 안내가 함께하는 것이다.
마찬가지로, 시스템에 대한 통찰을 얻는 가장 강력한 방법은 추상화 레벨들 사이를 이동하는 것이다. 많은 설계자들이 이를 본능적으로 한다. 그러나 구체적인 시스템을 경험하면서 높은 수준의 관점이 없는 “땅 위에” 머무르기 쉽다. 반대로 추상적인 방정식이나 집계 통계로만 작업하면서 “구름 속에” 머무르기도 쉽다.
Victor의 에세이는 추상화의 사다리(ladder of abstraction) 를 제시한다. 이것은 이런 레벨들에 대해 명시적으로 생각하기 위한 기법으로, 설계자가 그 사이를 의식적이고 자신있게 이동할 수 있게 해준다.
10.3 구체적 시스템에서 시작하기: 자동차 제어 시스템 예시
Victor는 단순한 자동차 시뮬레이션의 제어 시스템을 설계하는 예시를 통해 이 방법론을 설명한다. 자동차에는 세 가지 상태만 감지하는 단순한 센서가 있다: 자동차가 도로 위에 있거나, 도로 왼쪽에 있거나, 도로 오른쪽에 있다.
가장 단순한 규칙부터 시작한다: 도로 왼쪽에 있으면 오른쪽으로 틀고, 도로 오른쪽에 있으면 왼쪽으로 튼다. 그러나 2°씩 틀어야 한다는 것을 어떻게 아는가? 모른다. 야생적인 추측일 뿐이다. 야생적인 추측은 괜찮다, 어딘가에서 시작해야 한다. 하지만 그 추측을 쉽게 조정하고, 결과를 보고, 그것이 동작에 어떤 영향을 미치는지에 대한 감각을 개발하는 방법도 필요하다.
10.4 시간과 파라미터 제어하기
Victor가 강조하는 첫 번째 원칙은 직접적이고 인터랙티브한 제어다. 우리는 시스템의 독립 변수들에 대한 직접적이고 인터랙티브한 제어권을 가져야 한다. 실시간의 노예가 되어서는 안 된다.
시스템을 이해하려면 그것을 탐험할 수 있어야 한다. 탐험하려면 우리 자신의 통제 하에 자유롭게 이동할 수 있어야 한다. 실시간 뷰는 시스템의 행동에 대한 직접적인 감각을 얻는 데 유용하지만, 매우 제한적이다. 매번 편집할 때마다 처음부터 전체 영화를 봐야 하고 멈추거나 되감기도 할 수 없는 영화 편집자를 상상해보라. 그것은 터무니없는 일이다. 하지만 우리의 대부분 인터랙티브 시스템들이 이렇게 설계되어 있다.
10.5 시간에 대한 추상화: 한 단계 위로
직접적인 제어는 우리가 관심 있는 시간들을 인터랙티브하게 탐험할 수 있게 한다. 그러나 다음 단계는 더 광범위한 관점을 위해 시간을 추상화(abstract over time) 하는 것이다.
실시간 뷰는 어느 순간에도 특정 시간에서의 시스템만을 묘사한다. 그러나 한 단계 위로 올라가서, 시스템을 모든 시간에 걸쳐 정적으로 묘사하는 표현을 고안할 수 있다. 차 자체를 보여주는 대신 차의 전체 궤적을 보여주는 것이다. 이것이 추상화의 사다리에서 한 단계 위로 올라가는 것이다.
높은 수준에서는 더 광범위한 행동 관점을 얻고 높은 수준의 패턴을 발견할 수 있다. 예를 들어, 회전율이 1°에서 2° 사이일 때 심각한 진동이 나타나고, 그 진동이 파라미터가 2°에 접근함에 따라 도로 주변으로 “조여드는” 것처럼 보인다는 패턴을 발견할 수 있다. 이 패턴은 땅에서 알아채기 어렵다.
그러나 이 이점에는 비용이 따른다. 더 이상 차를 볼 수 없다! 차의 움직임을 직접 경험하고, 그것에 상식을 적용하는 것을 잃어버린다.
10.6 다시 내려오기: 추상화와 구체성의 춤
Victor가 강조하는 핵심은 내려오는 것이 올라가는 것만큼 중요하다는 것이다. 현실에서, 위로만 올라가는 사다리를 사용하지 않을 것이다. 마찬가지로, 추상화를 만들 때 내려오는 것은 올라가는 것만큼 중요하다.
추상화 위에 구체적 표현을 겹쳐놓는 것이 일반적이고 강력한 기법이다. 추상화 위의 모든 지점은 일반적으로 특정 구체적 상태에 대응된다. 추상화를 직접 가리켜 더 구체적인 표현으로 내려오는 것은 관심 있는 영역들을 빠르게 탐험하게 해준다.
이 과정에서 생겨나는 가장 깊은 통찰은 어느 한 추상화 레벨에 있는 것이 아니라, 그것들 사이의 전환에 있다. 높은 수준의 패턴을 보기 위해 한 레벨 위로 올라가고, 그 패턴의 설명을 발견하기 위해 내려온다. 이 춤이 바로 가장 깊은 통찰이 탄생하는 곳이다.
10.7 시스템을 이해하는 세 가지 차원
Victor는 모든 시스템이 세 가지 일반적인 해부학적 구조를 공유한다고 설명한다.
독립 변수(Independent Variable), 보통 시간이다. 이것은 인과관계에 대해 생각하는 방식이다. 시스템의 상태는 시간 상의 이전 상태들에 의존한다. “시간”은 꼭 실시간일 필요가 없다. 자동차 예시처럼 이산적인 단위 없는 단계들일 수도 있고, 산업 공정의 단계들이나 통신 시스템의 메시지 시퀀스일 수도 있다.
구조(Structure), 시스템이 따르는 규칙들의 집합이다. 보드 게임이나 법률 시스템에서는 산문으로 된 규칙들이고, 소프트웨어에서는 알고리즘을 형성한다. 구조는 우리가 통제하는 것이다. 일반적으로 두 가지 수준의 통제가 있다. 구조를 재배열하거나(코드 줄을 추가하거나, 두 트랜지스터를 연결하는 것), 구조 내의 값들을 조정할 수 있다(자동차의 회전율이나 저항의 값처럼). 값 변경들은 인터랙티브 제어와 추상화에 더 쉽게 적합하다. 하지만 구조적 변화들은 보통 더 큰 영향을 미친다.
데이터(Data), 규칙들에 공급되는 것이다. 시스템을 설계하는 것은 입력 데이터에 대한 모델을 설계하는 것을 필요로 한다. 이것은 구조 자체를 설계하는 것만큼이나 예술이고 도전일 수 있다. 동작이 어떻게 행동에 영향을 미치는지 이해하고 싶다면, 그것을 제어할 수 있어야 한다. 도로의 굽은 각도처럼, “더 많이”와 “더 적게”를 시도할 수 있는 차원들이 필요하다.
10.8 추상화의 사다리와 바이브 코딩의 관계
Bret Victor의 방법론은 바이브 코딩과 정확히 반대 방향에 서있다. 바이브 코딩은 가장 높은 추상화 레벨(자연어, 직관, “느낌”)에서만 작동하고 아래로 내려오지 않는다. Victor는 시스템을 진정으로 이해하려면 모든 레벨들 사이를 자유롭게 이동해야 한다고 말한다.
Dan Shipper의 Proof 앱이 크래시되었을 때의 문제가 바로 이것이다. 그는 “협업 텍스트 에디터”라는 높은 추상화 레벨에서만 작동했다. Yjs가 내부적으로 어떻게 작동하는지, CRDT가 어떤 방식으로 데이터를 관리하는지, 툼스톤이 무엇인지 — 이 낮은 레벨들로 내려갈 수 없었기 때문에, 추상화가 누수했을 때 어디서 무엇이 잘못되었는지 파악하지 못했다.
Victor가 말한 것처럼, 완전히 구체적인 시스템으로 가끔씩 내려가서 현실을 확인할 수 있어야 한다. “현실과의 접촉을 잃지 않아야 한다(stay grounded).” 이것이 바이브 코딩의 핵심 약점이고, 동시에 인간 엔지니어의 전문성이 여전히 중요한 이유다.
11. AGI 시대에도 코드는 죽지 않는다
이제 Krouse의 논증은 가장 대담한 지점으로 향한다. 많은 사람들이 AGI(Artificial General Intelligence, 인공일반지능)가 도래하면 코드가 진정으로 필요 없어질 것이라고 생각한다. AGI가 실현되면 개인도 매달 $1,000에 100명의 Andrej Karpathy 수준 천재를 고용할 수 있는 것과 마찬가지가 된다. 그러면 왜 복잡한 세부 사항을 직접 걱정해야 하는가? 그냥 AI 군단에게 맡기면 되지 않는가?
Krouse는 이 논리를 “완전히 웃긴 이야기”라고 일축한다. 이런 생각은 이 기술이 등장하기 전, 추상적으로만 생각할 때나 할 수 있는 것이라고 말한다.
그가 제시하는 핵심 반론은 이것이다: 코드는 그것이 만들어내는 소프트웨어만을 위한 것이 아니다. 코드 자체가 중요한 아티팩트다. 잘 만들어진 코드는 시(詩)다. 이것은 단순히 낭만적인 표현이 아니다. 코드는 복잡성을 정복하기 위한 인간의 사고 도구이며, 그 자체로 아름다운 지적 구조물이다.
그는 글쓰기와의 유추를 통해 이를 더 명확히 한다. 아무도 “바이브 라이팅(vibe writing)”에 대해 이야기하지 않는다는 점이 시사하는 바가 크다. ChatGPT가 위대한 소설가나 저널리스트의 일자리를 빼앗을 것이라고 주장하는 사람은 없다. 우리 모두 그것이 말이 안 된다는 것을 안다. 문법적으로 올바른 문장을 만드는 것이 신비롭게 느껴지지 않기 때문이다.
코딩도 정확히 마찬가지 상황이다. AI가 만들어내는 코드의 품질이 점점 나아지고 있지만, 지금 당장은 여전히 품질 문제가 있다. 우리는 그것을 알면서도 나쁜 코드에도 불구하고 AI를 사용한다. Simon Willison이 말하듯, AI는 우리가 더 좋은 코드를 만들도록 도와야 한다.
AGI가 도래하면, 우리가 그것을 가장 먼저 사용할 곳은 우리의 가장 어려운 추상화 문제들이 될 것이다. 우리는 AGI를 활용하여 더 나은 추상화를 만들고, 복잡성을 더 잘 이해하고 정복할 것이다. AGI가 더 스마트해질수록 좋은 코드의 필요성이 사라지는 것이 아니라, 오히려 우리는 그것을 사용하여 더 나은 협업 텍스트 에디터 라이브러리, 더 나은 프레임워크, 더 나은 추상화를 만들어낼 것이다. ChatGPT로 더 많은 슬롭(slop, 형편없는 콘텐츠)을 생산하는 데 쓰는 것은 AGI의 낭비다.
12. Val Town과 vtrr 프레임워크: 추상화의 실제 승리
Krouse는 자신이 경험한 AI와 추상화의 결합의 성공 사례를 공유한다. 그것은 Claude Opus 4.6을 활용하여 자신의 꿈의 풀스택 React 프레임워크인 vtrr를 만든 것이다.
Val Town은 Krouse가 만든 플랫폼으로, 브라우저에서 바로 서버리스 JavaScript/TypeScript 함수를 작성하고 실행할 수 있는 서비스다. 일종의 “클라우드 REPL” 또는 “소셜 코딩 플랫폼”이라고 볼 수 있다. 그는 이 플랫폼에서 React Router 7을 풀스택으로 작동시키는 방법에 대해 오랫동안 해결하지 못한 문제들의 목록이 있었다.
Opus 4.6은 이 문제들을 한 번에(one-shot) 해결해주었다. 그 결과물이 vtrr 프레임워크이며, Krouse가 특히 자랑스러워하는 것은 단 하나의 파일, 50줄의 코드로 완전한 풀스택 React 앱을 구현한 데모다.
이 하나의 파일에는 다음 모든 것이 포함되어 있다.
- React 컴포넌트 정의 (
Home함수) - 서버 로더(
loader) — 서버 시간 등 데이터를 서버에서 가져옴 - 서버 액션(
action) — POST 요청 처리 - 라우트 정의(
defineRoutes) — URL 경로와 컴포넌트/로더/액션 연결 - SSR(Server-Side Rendering) 지원
- 클라이언트와 서버의 시간을 동시에 표시
- 클릭 카운터 (
useState사용) - 폼 제출을 통한 서버 시간 갱신 (
fetcher.Form사용)
이 단일 파일 코드는 클라이언트 사이드 렌더링, 서버 사이드 렌더링, 데이터 로딩, 폼 액션, 상태 관리를 모두 하나의 응집된 단위에서 처리한다. 이것이 바로 Dijkstra가 말한 “절대적으로 정밀해질 수 있는 새로운 의미론적 레벨”이다. 50줄의 코드가 수천 줄의 보일러플레이트를 대체하면서도 모든 기능을 명확하게 표현한다.
Krouse는 “이 모든 복잡성을 이처럼 아름답게 정복하는 다른 코드를 알고 있다면 보여달라”고 자신 있게 말한다.
이것은 Bret Victor의 “추상화의 사다리”와도 연결된다. AI(Opus 4.6)는 높은 추상화 레벨에서 Krouse의 요구사항을 이해하고, 낮은 레벨의 구현 세부사항을 처리하며, 다시 높은 레벨의 아름다운 단일 파일 인터페이스로 표현했다. 이것이 Krouse가 말하는 “AI를 활용한 더 나은 추상화 만들기”의 실제 모습이다.
13. 코딩은 죽지 않았다: 인쇄기와 스토리텔링의 비유
Krouse의 결론은 단호하다. 사회의 99%가 코드가 죽었다는 데 동의한 것처럼 보이지만, 이것은 인쇄기가 발명되었을 때 스토리텔링이 죽을 것이라고 생각한 것과 같은 오류라고 그는 주장한다.
인쇄기가 발명되었을 때 이야기꾼들이 사라졌는가? 오히려 인쇄기는 스토리텔링을 더 넓고 깊게 꽃피웠다. AI가 코딩에 미치는 영향도 마찬가지일 것이다. AI는 코딩의 적이 아니라 코딩의 가장 강력한 동맹이다.
코드는 이제 막 시작하고 있다. AI는 코딩에 엄청난 혜택을 줄 것이다. 더 많은 사람이 코딩에 접근할 수 있게 되고, 더 좋은 추상화가 만들어지고, 더 어려운 문제들이 해결될 것이다.
Joel Spolsky의 법칙이 말해주듯, 추상화는 언제나 누수한다. 그리고 그 누수를 처리하려면 그 아래에 무엇이 있는지 이해해야 한다. Bret Victor가 보여주듯, 시스템을 진정으로 이해하려면 추상화의 사다리를 자유롭게 오르내릴 수 있어야 한다. Dan Shipper의 경험이 증명하듯, AI가 아무리 강력해도 낮은 레벨의 추상화를 이해하는 인간의 전문성은 대체되지 않는다. 그리고 Steve Krouse의 비전이 제시하듯, AI와 인간 전문성이 결합될 때 우리는 더 나은 추상화, 더 아름다운 코드, 더 깊은 이해에 도달할 수 있다.
14. 공식 언어에 관한 명언들
Krouse는 에세이를 형식적 언어(formalism)에 관한 세 가지 명언으로 마무리한다. 이 명언들은 코드, 추상화, 정밀도에 관한 그의 논증을 심화시킨다.
Edsger W. Dijkstra — 자연어 프로그래밍의 어리석음에 관하여
“공식 기호를 사용해야 하는 의무를 부담으로 여기는 대신, 그것을 사용하는 편의를 특권으로 여겨야 한다. 그 덕분에 학생들은 과거에 천재만이 달성할 수 있었던 것을 배울 수 있게 되었다. 결국 우리가 모국어를 ‘자연스럽게’ 사용한다는 것은, 그 말도 안 됨이 명백하지 않은 진술을 만드는 데 사용하기 쉽다는 것으로 귀결된다.”
이 인용문은 자연어의 한계를 날카롭게 지적한다. 자연어는 말도 안 되는 것을 명확해 보이게 포장하기 쉬운 반면, 공식 기호(코드)는 정확성을 강제하고 그 덕분에 훨씬 더 강력한 표현력을 갖는다.
Tony Hoare — 소프트웨어 설계의 두 가지 방법
“소프트웨어 설계를 구성하는 방법에는 두 가지가 있다. 하나는 결함이 명백하게 없도록 만들 만큼 단순하게 만드는 것이고, 다른 하나는 명백한 결함이 없을 만큼 복잡하게 만드는 것이다.”
이것은 Sophie Alpert의 논지를 정확하게 표현한다. Slack의 원본 플로우차트는 “명백한 결함이 없을 만큼 복잡”한 설계의 예시였고, Sophie의 개선된 버전은 “결함이 명백하게 없도록 단순하게” 만든 설계였다.
Charles Babbage — 대수적 기호의 압축력
“대수적 기호가 작은 공간에 압축하는 의미의 양은, 우리가 그것의 도움으로 수행하는 데 익숙한 추론을 촉진하는 또 다른 상황이다.”
코드가 가진 압축적 표현력의 가치를 말한다. 50줄의 코드가 수천 줄의 산문보다 더 많은 의미를 더 정확하게 전달할 수 있다.
15. 다섯 글의 핵심 메시지 종합
다섯 편의 글은 서로 다른 시대, 다른 맥락에서 쓰였지만, 하나의 일관된 지적 흐름 위에 놓인다.
복잡성은 피할 수 없다
라이브 협업, 알림 로직, 분산 시스템 등 많은 것들이 직관적으로는 단순해 보이지만 실제로는 깊은 복잡성을 담고 있다. 이 복잡성은 종종 지루하고 기억하기 어렵지만, 그렇다고 존재하지 않는 것은 아니다. “협업 텍스트 에디터”는 기능 명세서로는 단 세 단어지만, 실제 구현에서는 CRDT, 툼스톤 관리, 분산 합의 알고리즘으로 이어진다.
추상화는 복잡성을 정복하는 유일한 도구다
Dijkstra가 말했듯, 추상화의 목적은 새로운 레벨에서 절대적으로 정밀해질 수 있게 만드는 것이다. Sophie의 개선된 플로우차트, ReactJS, TailwindCSS, Krouse의 vtrr 프레임워크가 모두 그 예시다. 좋은 추상화는 복잡성을 숨기는 것이 아니라 더 잘 이해할 수 있게 재구성한다.
그러나 추상화는 언제나 누수한다
Joel Spolsky의 법칙은 근본적 진실을 담고 있다. 이해하지 못한 채로 쌓아올린 추상화는 언제든 새어나온다. TCP도 누수하고, SQL도 누수하고, Yjs도 누수한다. 누수를 처리하는 유일한 방법은 추상화가 무엇을 감추고 있는지 이해하는 것이다. 추상화는 작업 시간은 절약해주지만 학습 시간은 절약해주지 않는다.
시스템을 이해하려면 추상화의 사다리를 오르내려야 한다
Bret Victor가 보여주듯, 진정한 이해는 어느 한 추상화 레벨에 머무르는 것이 아니라 레벨들 사이를 자유롭게 이동하는 데서 온다. 가장 깊은 통찰은 추상에서 구체로, 구체에서 추상으로 이동하는 전환의 순간에 탄생한다. 바이브 코딩은 항상 높은 추상화 레벨에 머무르기 때문에, 추상화가 누수할 때 아래로 내려갈 수 없다.
바이브 코딩은 강력하지만 한계가 있다
Dan Shipper의 경험이 생생하게 증명하듯, AI를 통한 고속 개발은 실제로 가능하다. 14만 줄의 코드, 1,600개의 커밋, 10일 만에 만든 앱. 그러나 그 앱이 바이럴되는 순간 크래시되었고, AI 에이전트 혼자서는 빠르게 해결할 수 없었다. 인간의 전문성—어디를 건드려야 하는지 아는 것, 올바른 첫 번째 질문을 하는 것, 가설을 좁히는 것—이 결정적인 차이를 만든다.
AI는 더 나쁜 코드가 아니라 더 좋은 코드를 위한 도구다
Krouse가 제시한 vtrr 프레임워크의 50줄짜리 풀스택 React 앱은 AI와 추상화가 결합했을 때 어떤 아름다움이 가능한지를 보여준다. AGI가 오더라도, 우리는 그것을 슬롭을 더 많이 만드는 데 쓰는 것이 아니라 더 나은 추상화, 더 아름다운 코드를 만드는 데 쓸 것이다.
코드는 죽지 않았다
인쇄기가 스토리텔링을 죽이지 않았듯, AI는 코딩을 죽이지 않는다. 형식적 언어로서의 코드가 가진 정밀성과 표현력은 자연어가 결코 완전히 대체할 수 없는 고유한 가치를 가진다. Dijkstra가 말했듯, 공식 기호를 사용하는 것은 특권이다. Babbage가 말했듯, 기호들이 작은 공간에 압축하는 의미의 양이 강력한 추론을 가능하게 한다. 코드는 이제 막 시작하고 있다.
이 문서는 다음 다섯 편의 글을 바탕으로 작성되었습니다.
- Steve Krouse, stevekrouse.com/precision (2026년 3월 21일)
- Sophie Alpert, sophiebits.com/2024/10/30/everyone-is-wrong-about-that-slack-flowchart (2024년 10월 30일)
- Joel Spolsky, joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions (2002년 11월 11일)
- Bret Victor, worrydream.com/LadderOfAbstraction
- Dan Shipper, every.to/chain-of-thought/when-your-vibe-coded-app-goes-viral-and-then-goes-down (2026년 3월 20일)