요약
데이크스트라는 1978년에 모국어로 기계를 부리면 프로그래밍이 쉬워진다는 기대를 정면으로 반박했습니다.
컴퓨터 과학자 에츠허르 데이크스트라가 남긴 짧은 메모 EWD 667입니다. 형식 기호(규칙이 엄밀하게 정해진 수식이나 코드 같은 표기)를 다루는 데 드는 주의를 결함으로 여기고, 사람 말을 알아듣는 기계를 바라는 이들에게 답한 글입니다.
왜 중요한가
- 사람의 부담을 기계로 넘기면 편해진다는 직관에, 주고받는 소통 비용까지 따져야 한다는 기준을 세웁니다.
- 형식 언어의 엄격함을 없앨 불편이 아니라 실수를 걸러 내는 장치로 다시 보게 합니다.
- LLM(대규모 언어 모델) 덕분에 영어가 새 프로그래밍 언어가 된다는 주장에 맞서는 근거로 HN에서 다시 읽히고 있습니다.
핵심 내용
- 인터페이스를 바꾸는 일은 정해진 일을 나누는 것이 아니어서, 소통 비용이 더해져 양쪽 일이 모두 늘 수 있다고 했습니다.
- 형식 기호는 단순한 규칙 몇 개만으로 모국어에서는 피하기 힘든 헛소리를 걸러 준다고 봤습니다.
- 그리스 수학은 말과 그림에 머물러 막혔고, 비에트·데카르트·라이프니츠·불의 기호가 근대를 열었다고 짚었습니다.
- 기호 덕분에 학생도 예전에는 천재만 하던 일을 해내니, 형식 기호는 짐이 아니라 특권이라고 했습니다.
- 모국어의 '자연스러움'은 헛소리를 티 나지 않게 말하기 쉽다는 뜻일 뿐이라고 꼬집었습니다.
HN 반응
- 여러 이용자는 LLM이 컴파일러가 아니라 개발자를 대신할 뿐이며, 동작을 확정하려면 여전히 코드가 필요하다고 봤습니다.
- 자연어도 세세하게 지시하면 LLM이 컴파일러 구실을 한다는 반론에는, 글의 요지가 형식과 비형식의 차이라는 재반론이 나왔습니다.
저는 영어가 이제 고수준 프로그래밍 언어라고, 기계어에서 <자기가 좋아하는 언어>로 올라오는 사슬의 다음 추상화 단계라고 말하는 사람에게 이 글을 보내 줍니다. 이 비유 뒤에는 보통 “대부분의 프로그래머가 어셈블리 코드를 안 보는 것처럼, 고수준 소스 코드를 들여다보는 것도 소수만 하는 일이 될 것이다”라는 말이 따라붙습니다.
다익스트라의 논증이 사람들의 생각을 바꾸는 경우는 드뭅니다. 이 비유가 먹히는 건 거기에 진실의 알맹이가 있기 때문이라고 봅니다. AI 모델이 이제 자연어로 프로그래밍하는 마법 같은 능력을 주는 건 맞지만, AI 모델이 일종의 컴파일러라는 함의는 심각하게 잘못됐습니다. AI 모델은 컴파일러를 대체하는 게 아니라 소프트웨어 개발자를 대체합니다. 소프트웨어 개발자가 어셈블리 코드를 거의 안 보는 이유는, 컴파일러(그리고 에뮬레이터와 VM)가 원래 프로그램의 의미를 정확하게 보존해 주기 때문입니다.
자연어 명세는 프로그램이 아니고, 그 명세를 만족하는 프로그램은 수없이 많습니다. 소프트웨어 엔지니어와 AI 모델은 명세를 코드로 바꾸지만, 코드가 곧 명세는 아닙니다. 이 비유는 컴퓨터가 무엇을 해야 하는지 형식적으로 기술하고, 사람에게도 AI 모델에게도 맡겨서는 안 되는 프로그램의 속성을 강제하는 도구로서 프로그래밍 언어가 갖는 가치를 흐린다고 생각합니다.
지인분들이 생각을 안 바꾸는 건 논거가 약하기 때문입니다. 글도, 당신의 댓글도 자연어로 하는 상호작용의 유일한 방식이 프로그래머의 의도를 아주 높은 수준에서 기술하는 것이라고 가정하고 있습니다.
AI에게 “계산기 만들어 줘”라고 할 수도 있고, “이제 UI의 각 키에 대응하는 불리언 배열을 선언하고, 키가 눌리면 해당 배열 위치를 true로 설정해”라고 할 수도 있습니다.
이 명령들은 추상화 수준이 너무 달라서 같은 범주로 묶기 어려운 자연어입니다. 뒤쪽은 LLM이 컴파일러 역할을 하는 명령형 언어라고 불러도 공정하다고 봅니다. 제가 AI를 쓰는 방식이 그것과 아주 비슷합니다.
아니요, 글은 차이가 형식 언어와 비형식 언어에 있다고 명시적으로 말합니다.
프로그래밍 언어는 (적어도 그 일부에 대해서는) 연산적 의미론을 정의할 수 있습니다. 엉성한 언어라 해도 어차피 아주 작고 제한적이니까요. 의미 보존 정리를 형식적으로 증명할 수도 있고, 비슷한 방식으로 비형식적으로 추론할 수도 있습니다.
자연어에서는 그게 어느 정도 사라집니다. 모델이 확률적이라는 점은 건드리지도 않았는데 말이죠.
AI가 자연어 프로그래밍이라면 1978년에도 이미 있었다는 얘기가 됩니다. AI는 사실 “프로그래머에게 코드를 써 달라고 부탁하는 것”이니까요. 심지어 추상화 수준을 달리해서 부탁할 수도 있고요!
“자연어 벽돌 쌓기”랑 똑같아요. 돈 주고 고용한 벽돌공에게 말로 지시해서 벽을 세우는 거죠.
지능의 마법 같은 비결은 맥락 인식입니다. 프롬프트가 다소 포괄적이라면(“계산기 만들어 줘”) AI는 질문을 하거나, 합리적인 가정을 하거나, 둘 다 해야 합니다.
제 경험상 LLM은 대체로 합리적인 가정을 하지만, 가끔 그러지 않아서 되돌아가 “아니, 내 말은 이거였어…”라고 말해야 합니다.
과정이 잘 풀리면 거의 마법 같습니다. LLM이 당신의 필요를 제대로 예측해서, 당신이 직접 했을 때보다 훨씬 충실하게 요청을 구현해 주니까요.
그렇지 않으면 당신이 치워야 할 난장판이 생깁니다.
그래도 대체로 최고 수준의 LLM이 짧은 설명만 듣고도 시키지 않은 유용하고 올바른 세부 사항까지 알아서 채워 넣으며 Do The Thing 하는 걸 보면 인상적입니다.
컴파일러는 그렇게 동작하지 않습니다. 컴파일러는 번역기이지, 독립적인 주체성을 가진 (신입급) 발명가가 아닙니다.
어떤 컴파일러는 그럴 수 있지만 아주 통제된 방식으로만 가능합니다. 예를 들어 Haskell의 deriving이나 타입클래스에서 호출할 올바른 메서드를 추론하는 것이 그렇습니다. Prolog/Datalog/SQL도 답에 도달하는 방법의 세부 사항을 상당 부분 알아서 채워 넣습니다.
그건 "I"만 해당하는 얘기죠. 인공(Artificial)의 "A"가 빠졌으니까요. 자연적으로 만들어진 사람에게 부탁한 거잖아요.
그리고 1978년에 "I"가 없었다고 주장한 사람은 아무도 없는데, 그래서 이 논거가 뭘 증명하려는 건지 모르겠네요.
제 추측으로는, 자연어를 해석하는 데 임의의 수준의 지능이 필요하다면 “자연어 프로그래밍”이 가능한 것이냐를 따질 때 1978년과 지금 사이에 달라진 게 없다는 걸 보여 주려는 것 같습니다. 지능이 이제 인공이라고 해서 답이 달라지지는 않는다는 거죠.
답이 달라지는 정도가 아니라, 그게 바로 질문 전체입니다. 사람들이 “자연어 프로그래밍”의 가능성이나 불가능성을 이야기할 때는 언제나 "자연어 지시를 기계가 실행 가능한 코드로 번역해 준다"는 뜻이었습니다.
굳이 말로 풀어 쓸 필요가 없었던 건, 자연어 지시를 받은 사람 프로그래머가 코드를 짤 수 있다는 걸 아무도 의심하지 않았기 때문입니다. 그건 ENIAC 시절부터, 아니 에이다 러브레이스 때부터 이미 있던 일이니까요.
지금 우리가 가진 게 바로 그것이고, “자연어 프로그래밍”이 가능하냐를 따질 때 1978년과 지금 사이에 달라진 것도 바로 그 점입니다.
이 두 문장은 서로 다릅니다.
자연어로 프로그래밍할 수 있다.
AI에게 자연어로 할 일을 말하면, AI가 요구 사항을 수집하고, 설계를 스케치하고, 코드를 쓰고, 오류 메시지를 웹에서 검색하고, 프로그램이 돌아갈 때까지 반복해서 고친다.
사람들이 신경 쓰는 어떤 측면에서는 둘이 같습니다(컴퓨터에 원하는 걸 말하면 프로그램이 튀어나오니까요). 하지만 다른 측면에서는 전혀 다릅니다(자연어는 기계 명령어로 결정론적으로 대응되지 않으니까요).
수십 년 전에 사람들이 자연어 프로그래밍을 이야기할 때는 자연어를 기계어로 컴파일하는 시스템을 말한 겁니다. 요구 사항을 자율적으로 수집하고, 어떤 프레임워크를 쓸지 정하고, 오류 메시지를 웹에서 찾아보고, 아이디어를 반복해서 다듬는 시스템 같은 건 말하지 않았어요. 이런 것들은 “자연어가 기계어로 대응된다”는 것과 너무 달라서, “컴퓨터에 원하는 걸 말한다”는 것만 따져 볼 가치가 있는 측면이라고 생각하신다면 유익한 대화가 되기 어렵다고 봅니다.
이것도 두 가지를 여전히 혼동하고 계십니다.
하나는 AI를 통해 자연어를 기계어로 바꾸고 싶어 한 사람들입니다. 다만 그 AI가 당시에 달성 가능하다고 생각한 방식(기호주의 AI)으로 구현됐을 뿐이죠.
다른 하나는 나중의 AppleScript나 일부 4GL 언어 같은, 자연어 스타일의 프로그래밍 언어를 원한 사람들입니다.
자연어 프로그래밍, 당시 표현으로는 자연어 처리는 처음부터 앞의 것, 그리고 당시의 AI 연구와 연결돼 있었습니다.
https://en.wikipedia.org/wiki/Natural_language_processing
그러니까 LLM은 없었지만, 그런 프로그램 또는 “컴파일러”가 제대로 동작하려면 세상에 대한 사실과 자연어를 이해해야 한다는 건 꽤 잘 알고 있었던 겁니다.
제 댓글을 오해하셨네요. 제 말은, 프로그래머에게 뭔가를 프로그래밍하라고 지시하는 것이 “자연어 프로그래밍”(에이전트 방식 AI 코딩이 하는 일)이라면 1978년에도 “자연어 프로그래밍”이 있었다는 뜻이었습니다. 1978년에 AI가 있었다고 말한 게 아닙니다.
뒤쪽은 계산기를 명세하는 것과도 거리가 한참 멉니다. 그리고 "Show HN" 프로젝트들을 보면, 평범한 사람이 AI로 소프트웨어를 만드는 일반적인 과정과도 한참 멀고요.
아니요, AI 모델이 대체하는 건 컴퓨터가 할 일을 정밀하게 기술해야 하는 필요성이고, 빈틈을 메우는 데 정말 능한 메커니즘으로 그걸 대신하는 겁니다. 하지만 짐작만으로는 갈 수 있는 데까지가 한계가 있습니다.
그게 소프트웨어 엔지니어가 하는 일 아닌가요?
최근에 애플리케이션 하나를 완전히 바이브 코딩으로 만들어서 사용자들과 테스트해 봤습니다. 기능 요구 사항은 전부 들어 있었어요.
뭐가 빠졌을까요?
비기능 요구 사항입니다.
또 하나, 제 앱은 LLM 분류를 해야 했습니다. 그런데 코딩 어시스턴트가 가끔 LLM API 호출 대신 분류용 정규식을 써 놓았습니다. 정규식으로 분류하지 말라고 분명히 말해 뒀는데도요.
비기술직 사람들은 정규식이 뭔지 모릅니다. 보통 비기능 요구 사항에 대해서도 충분히 알지 못하고요.
물론 이 모든 게 시간이 지나면 나아질 수 있습니다. 하지만 지금으로서는 (SWE를 대체한다는 점에서는) 인상적이지 않습니다.
비기능 요구 사항은 왜 바이브 코딩으로 안 하셨어요?
아직 필요하지 않았습니다. 먼저 UX를 확보해서, 우리가 만들고 싶은 걸 만들 수 있는지부터 봐야 했거든요.
“프로그래머를 대체하지 못한 건 우리가 그렇게 시키지 않아서다”라니, 참 희한한 논리네요.
그럼 테스트해서 어떤 비기능 요구 사항이 충족되지 않는지 확인하고, AI에게 그걸 포함하도록 코드를 바꾸라고 시키면 되죠. 마음에 들 때까지 반복하면 됩니다.
네, 그러고 나면 처음에 비기능 요구 사항에 포함되지 않았던 탓에 프로덕션에서 뭔가 터지는 무용담이 생기겠죠. 이런 무용담이 충분히 쌓이면 사실상 소프트웨어 엔지니어가 되는 겁니다. 코딩을 한 번도 해 본 적 없는 소프트웨어 엔지니어이긴 하지만, 프로덕션 문제를 이해하는 사람인 건 분명하죠.
저는 수십 년간 사람이 프로그래밍하면서도 그런 건 차고 넘치게 겪었는데요, 뭐.
오늘 배웠네요. 최종 사용자와 프로그래머의 차이는 jira에 접근할 수 있느냐였다는 걸.
맞습니다. 하지만 소프트웨어 엔지니어는 문제를 훨씬 폭넓게 이해하고, 질문도 합니다. 그리고 훌륭한 엔지니어라면 올바른 질문을 하죠. LLM이 여전히 어려워하는 부분입니다.
LLM은 못 하지만 제가 할 수 있었던 일을 개인적인 사례로 들어 보겠습니다. 다른 파일들을 바탕으로 몇몇 파일의 버전 번호를 갱신하는 스크립트를 만들었습니다. 단순한 일이었고, 동료 한 명이 “AI한테 시켜, 5분이면 돼”라고 하더군요. 하지만 안 됩니다. 파일들이 서로 다른 머신에 있어서, 한 머신에서 파일을 꺼내 결과를 다른 머신에 넣으려면 인프라에 대한 지식이 필요하거든요. 이것도 단순한 일이지만 AI는 그걸 모르고, 우리 네트워크에서 AI를 멋대로 돌아다니게 둘 수도 없습니다. 저는 팀원들과 이야기하고, 회의에 참석하고, 조심스럽게 조금씩 살펴봤기 때문에 이 모든 걸 압니다. 저는 AI와 달리 업무를 위한 자원을 믿고 맡겨 받는데, 제가 자원을 잘못 쓰면 책임을 질 수 있기 때문이 가장 크다고 확신합니다.
그렇긴 하지만 LLM도 이미 질문을 하긴 하고, 어떤 질문을 해야 하는지 알아보는 능력이 계속 좋아지지 않을 이유는 없습니다.
사람도 이걸 잘 못 하는 경우가 많고, 자기에게 요청된 게 실제로 무엇인지 이해하는 데 형편없는 개발자를 겪어 본 경험은 다들 있을 겁니다.
누군가 요청을 할 때 실제로 하려는 게 무엇인지 알아내는 능력에서 LLM이 숙련된 개발자만큼 좋아지는 일은 어쩌면 없을지도 모릅니다. 하지만 LLM이 더 나아질 건 확실하고, 결국 최고의 사람만큼 좋아질 수 없다고 믿을 만한 이유는 현재로서는 없습니다.
말하자면 명세가 실제로 의도한 바를 짐작하는 일을 자동화하는 겁니다. 그 짐작의 품질을 높여 주는 건 아니고요.
영어에서 코드로 가는 층은 확률적이고, 코드에서 어셈블리로 가는 층은 그렇지 않다는 말씀인가요?
이런 확률적 성질은 AI 이전에도 있었습니다. 사람도 확률적이에요. 엔지니어 두 명이 명세를 코드로 바꾸면 서로 다른 방식으로 바꿉니다. 저는 그 분포가 에이전트보다 사람 사이에서 더 넓다고 주장하고 싶습니다.
제가 말했듯이 “AI 모델은 컴파일러를 대체하는 게 아니라 소프트웨어 개발자를 대체합니다”이니, AI 모델이 사람과 비슷하다는 데는 동의합니다.
LLM과 사람 모두 100% 결정론적이지 않다는 건 흥미로운 부분이 아니라고 봅니다. C 프로그램을 구현하는 어셈블리 프로그램이 여러 개 있다는 것도, 자연어 명세를 올바르게 구현하는 유효한 프로그램이(어떤 프로그래밍 언어로든) 여러 개 있다는 것도 둘 다 맞습니다. 하지만 두 종류의 번역 사이에는 질적으로 큰 차이가 있고, 그건 번역이 확률적이든 아니든 마찬가지일 겁니다.
우리가 답글을 달고 있는 그 문장은 스타트업 1000개를 출범시킬 겁니다(이미 출범시켰나요?).
명세와 그것을 구현했다고 주장하는 소프트웨어 사이의 “거리”를 정하는 건전한 측정 방법을 제시해 보는 것도 흥미로울 것 같습니다.