이 글은 시간이 지나도 여전히 핵심을 잘 짚고 있음. 에이전트 개발을 자연어 프로그래밍이라고 부르기도 하지만, 실제로 프로그래밍하는 주체는 에이전트이며 결과물은 여전히 Rust, Python, TypeScript 같은 결정적인 언어로 작성됨. 앞으로 달라질 수도 있지만, 내게는 그 반대가 재앙처럼 느껴짐.
가장 흥미로운 예외는 텍스트 어드벤처를 만드는 Inform 7임. 깊이 써보지는 않았지만, 자연어와 프로그래밍을 독특하고 우아하게 결합한 듯하며 팬도 많음. 자연어 프로그래밍에 관심 있는 언어 애호가라면 꼭 살펴볼 만함. https://ganelson.github.io/inform-website/
용도의 90%는 LLM에게 코드를 만들게 하는 접근이 적절하다고 봄. LLM이 실행 중에 즉석으로 무언가를 처리하게 하는 흐름과는 다름. 코드는 결정성을 만들어 주지만 LLM은 그렇지 않음.
자연어를 기계어로 컴파일할 날이 얼마 남지 않았다는 말을 기술 애호가들에게 자주 듣는데, 실제로 가능한 방향인지 신뢰할 만한 견해가 있나? 떠오르는 가장 가까운 형태는 Haskell 쪽에서 관심을 갖는 것들을 훨씬 풍부하게 만든 도메인 특화 언어(DSL) 정도인데, 그것도 진짜 자연어로 된 프로그래밍 언어와는 거리가 멂.
영어가 기계어에서 이어지는 추상화 사슬의 다음 단계이자 고수준 프로그래밍 언어가 됐다고 말하는 사람들에게 이 글을 보내곤 함. 대개 “대부분의 개발자가 어셈블리를 보지 않듯 고수준 소스 코드를 보는 사람도 소수가 될 것”이라는 비유가 뒤따름.
Dijkstra의 논증으로도 생각이 잘 바뀌지 않는 것은 그 비유에 일부 진실이 있기 때문이라고 봄. AI로 자연어 프로그래밍이 가능해졌지만, AI 모델을 컴파일러로 보는 것은 잘못임. 모델은 컴파일러가 아니라 소프트웨어 개발자를 대체함. 개발자가 어셈블리를 거의 보지 않아도 되는 이유는 컴파일러와 에뮬레이터, 가상 머신이 원래 프로그램의 의미를 정확히 보존하기 때문임. 자연어 명세는 프로그램이 아니며, 같은 명세를 충족하는 프로그램은 여럿일 수 있음. 개발자와 AI는 명세를 코드로 바꾸지만 코드와 명세는 같지 않음. 이 비유는 컴퓨터의 동작을 형식적으로 기술하고, 인간이나 AI의 주의력에 맡겨서는 안 될 속성을 강제하는 프로그래밍 언어의 가치를 흐리게 함.
지인들이 생각을 바꾸지 않는 것은 논거가 약하기 때문임. 글과 댓글 모두 자연어로 상호작용하는 방식이 개발자의 의도를 아주 높은 수준에서 설명하는 것뿐이라고 가정함.
“계산기를 만들어 줘”와 “UI의 각 키에 대응하는 불리언 배열을 선언하고, 키를 누르면 해당 위치를 true로 설정해 줘”는 추상화 수준이 전혀 다름. 후자는 LLM을 컴파일러로 삼는 명령형 언어라고 불러도 타당하며, 내가 AI를 쓰는 방식도 이와 비슷함.
대체되는 것은 개발자가 아니라 컴퓨터에 원하는 동작을 정확히 기술해야 할 필요성임. 빈틈을 잘 메우는 장치가 그 자리를 대신하지만, 추측으로 갈 수 있는 데에는 한계가 있음.
영어에서 코드로 가는 단계는 확률적이고, 코드에서 어셈블리로 가는 단계는 그렇지 않다는 뜻인가? 인간도 확률적이므로 이런 성격은 AI 이전에도 존재했음. 두 엔지니어는 같은 명세를 서로 다른 코드로 구현하며, 그 편차는 에이전트보다 인간 사이에서 더 클 것이라고 봄.
LLM은 컴파일러를 대체하기보다 차세대 컴파일러에 도전 과제를 던짐. 소프트웨어 엔지니어도 대체하기보다 또 다른 메타시스템으로 옮겨 놓음.
일부 개발자에게는 “생각과 작업을 다른 누군가에게 맡겼다”보다 “더 높은 추상화 수준에서 작업한다”가 말하기 편한 듯함. LLM에 일을 맡기는 것은 괜찮지만, Jira 티켓을 Claude에 붙여 넣는 것은 추상화가 아님.
LLM 활용의 세밀함은 프로젝트 전체를 한 번에 맡기는 것부터 파일 하나의 변수명을 바꾸는 것까지 폭이 넓어서 논쟁이 복잡해짐. 프로그래밍에 가까운 활용도 있겠지만, 코드조차 보지 않는다면 다른 누군가가 일을 하는 것에 더 가깝다고 봄.
핵심은 순전히 기계적인 존재와 소통하느냐, 지적인 존재와 소통하느냐의 차이라고 봄. 프로그램은 형식 언어지만 교과서와 논문은 자연어와 형식 언어를 섞고, 필요할 만큼만 형식적인 표기법을 도입함. 지적인 독자는 행간을 읽고 빈틈을 메우며 연결 관계를 찾아냄. inter legere도 문자 그대로 사이를 읽는다는 뜻임.
실제로 핵심 아이디어를 설명할 때 EBNF나 Python, Prolog 등의 코드 조각을 적절히 섞는 방식이 매우 효과적임. LLM은 빈틈을 채우고 반형식적인 대화를 엄밀한 형식 언어로 변환하는 데 탁월함.
사람이 검토하고 LLM이 구현할 기술 제안을 작성하고 다듬는 데도 유용함. PEP-12와 PEP-1 같은 방식으로 자연어 설명과 반형식적·형식적 세부 사항을 섞고, 이를 작업 단위로 나눈 뒤 명세 주도 개발처럼 각 작업에 명세를 포함. 지금까지는 잘 작동하는 편임.
코딩 에이전트가 등장한 뒤로 같은 생각을 해왔음. LLM은 요약에 능해서 코드 이해에 주로 활용하지만, 코드베이스를 잘 알수록 에이전트에 더 까다로워짐. 반대로 잘 모를수록 알아서 하도록 맡기기 쉬움.
에이전트가 좋은 코드를 쓰는 것이 아니라, 내가 기대하는 바를 막연하게 이해해서 그렇게 느낀다는 사실을 깨달음. AI 코드를 들여다보면 작성 전에 고려했어야 할 미묘한 차이와 결정이 더 많이 보임.
명세면 충분하다고 할 수도 있지만, 개발자가 프로그램과 알고리즘을 비판적으로 사고하도록 Leslie Lamport가 만든 TLA+ 가 떠오름. 원하는 동작을 직접 형식적으로 작성하는 과정은 문제를 더 잘 이해하고 막연하지 않은 실제 해법을 찾는 데 도움이 됨.
자연어에는 뉘앙스와 암묵적인 문화적·분야별 함의가 가득함. LLM이 작동하는 것은 그런 숨은 의미 일부를 담은 방대한 자료로 훈련됐기 때문이며, 모든 의미를 익힌 것은 아님. 명세 주도 개발에서 요구사항을 정확히 구현하려면 프롬프트를 매우 상세하게 작성해야 함.
인간도 평균 15년 이상에 걸쳐 방대한 자료로 훈련받았기에 일할 수 있음. 요구한 결과를 정확히 내려면 인간에게도 회의 등을 통해, 때로는 매일 지시를 줘야 함.
LLM은 어떤 선택을 하든 신경 쓰지 않아도 되는 범위에서 잘 작동함. 데모나 시작용 템플릿에 좋은 이유도 여기에 있음. 하지만 성숙한 소프트웨어에서는 결국 모든 세부 사항이 중요해짐.
이 글을 읽으니 궁금해짐. 훈련 데이터에서 프로그램 코드를 제외했다면, LLM은 프로그래밍에 얼마나 유용했을까?
자연어로 프로그래밍하는 기계는 만들기도 사용하기도 지독히 어려울 것이라는 대목은 여전히 맞는 듯함. 나는 대체로 소스 관리에서 추적하는 언어를 그 기계의 프로그래밍 언어로 봄. Git 저장소가 Java의 변경 사항을 추적한다면, LLM의 도움으로 생성했더라도 Java로 프로그래밍한 것임.
대다수 저장소가 소프트웨어의 동작을 규정하는 주된 산출물로 프로그래밍 언어 대신 자연어를 추적하기 시작해야 이 글의 논지가 반박됐다고 볼 수 있겠음.
다른 일회성 코드 생성기의 출력물처럼 다뤄야 하며, 비결정성과 향후 모델 이용 불가 가능성이라는 위험도 추가됨. 후자는 특히 서비스형 LLM에 해당함.
따라서 손으로 작성한 코드만큼 유지보수성이 중요함. 한 번 쓰고 버리는 코드도 충분히 정당한 용도가 있지만, “AI니까” 저품질 코드를 저장소에 넣어도 비용이 들지 않는다고 가정해서는 안 됨.
자연어의 불안정성 때문에 오늘의 자연어 프로그램이 내일은 작동하지 않을 수 있음. 의미가 자연스럽게 변하는 것뿐 아니라, 일부 클라우드 모델의 오웰식 제한으로 프로그램이 금지될 수도 있음. 주제나 단어 조합 때문에 표시되고, 머지않아 정보기관에 신고될 가능성도 우려됨.
RMS라면 자연어 프로그램의 컴파일러를 처음부터 직접 만들 수 있는가를 물을 것임. 매우 비싼 로컬 모델이 있다는 것은 알지만, GPU 작동에도 온라인 구독과 감시 장치가 붙게 될 가능성을 경계해야 함.
William R. Cook은 AppleScript를 다룬 HOPL IV에서 영어와 일본어 같은 자연어를 닮은 언어를 설계하려던 실험은 성공하지 못했다고 했음. 지금의 LLM은 자연어를 닮은 언어가 아니라 실제 자연어를 사용한다는 차이가 있지만, 이 결과는 Dijkstra의 이론적 논증과 비교할 만한 실증 자료가 됨. 자연어의 이점은 초반에, 단점은 장기적으로 나타나는 경향이 있어 양날의 검임. LLM의 역할도 둘로 나눠 봐야 함. 자연어로 모호하게 표현할 수 있게 해주는 것과, 원하는 것을 기존보다 훨씬 높은 수준에서 지정할 수 있게 해주는 것은 서로 다른 역할임. 현재는 둘이 묶여 있지만, 모호함과 고수준 명세를 분리할 수 있다면 훨씬 가치 있을 것임. https://dl.acm.org/doi/10.1145/1238844.1238845
오늘날에도 매우 밀접하게 들어맞으며, 인지적 위임도 생각하게 함. 기계의 구조화된 인터페이스와 수학의 체계적인 방법론은 추상적 직관을 표현할 수 있도록 인간의 사고를 구조화해 줬음. 기계가 자연어를 쓰기 시작하면서 인간이 생각을 정리하지 않게 되고, 결국 사고가 안개처럼 흐릿해질 수 있다는 우려도 무리는 아닌 듯함.
철학이야말로 자연어로 생각을 체계화할 수 있다는 최고의 예가 아닐까? 분석철학의 전통도 있지만, 철학의 압도적 다수는 과거에도 지금도 형식 언어로 작성되지 않음.
자연어 프로그래밍이 어리석게 느껴지는 이유는 기술보다 실용성에 있음. 가장 가치 있는 용도는 현업이 이미 작동하는 시스템의 동작 방식을 이해하고 싶을 때임. 자연어로 설정할 수 있게 해줘도, 원래 개발자가 완성된 출발점을 마련해 줄 때까지 입력창만 멍하니 바라보는 경우를 여러 번 봄. 유용한 기술 명세를 작성하는 역량이 없다면 언어가 자연스럽다는 사실만으로 큰 차이는 나지 않는다고 봄. 모두 관련 일을 30년 넘게 해왔어도 아주 기초적인 불 대수 문제부터 현업을 이끌어 줘야 할 때가 많음. 모두에게 Python을 쓰게 하면 더 나빠질 뿐임.
나는 자연어 표현 능력을 유지하려고 HN을 활용함. 여기서 자주 글을 쓰는 개발자와 한 달에 이메일 하나도 거의 쓰지 않는 개발자의 차이는 놀라울 정도임. 특정 도구로 복잡한 일을 하려면 꾸준히, 가능하면 매일 연습해야 함. 이를 대신할 방법은 앞으로도 없을 것임.