언어 설계에 대한 다섯 가지 질문
2001년 5월
(이 글은 2001년 5월 10일 MIT에서 열린 프로그래밍 언어 설계 패널 토론을 위해 작성한 메모입니다.)
1. 프로그래밍 언어는 사람을 위한 것입니다.
프로그래밍 언어는 사람들이 컴퓨터와 대화하는 방식입니다. 컴퓨터는 모호하지 않은 어떤 언어로든 기꺼이 소통할 것입니다. 우리가 고급 언어를 사용하는 이유는 사람들이 기계어를 다룰 수 없기 때문입니다. 프로그래밍 언어의 목적은 우리의 나약한 인간 두뇌가 엄청난 양의 세부 사항에 압도당하는 것을 막는 것입니다.
건축가들은 어떤 종류의 설계 문제는 다른 문제보다 더 인간적이라는 것을 압니다. 가장 깔끔하고 추상적인 설계 문제 중 하나는 다리를 설계하는 것입니다. 거기서 당신의 임무는 주로 최소한의 재료로 주어진 거리를 연결하는 것입니다. 스펙트럼의 다른 한쪽 끝은 의자를 설계하는 것입니다. 의자 디자이너는 인간의 엉덩이에 대해 생각하며 시간을 보내야 합니다.
소프트웨어 역시 마찬가지입니다. 네트워크를 통해 데이터를 라우팅하는 알고리즘을 설계하는 것은 다리를 설계하는 것과 같이 멋지고 추상적인 문제입니다. 반면 프로그래밍 언어를 설계하는 것은 의자를 설계하는 것과 같습니다. 즉, 인간의 약점을 다루는 것입니다.
우리 대부분은 이를 인정하기를 싫어합니다. 위대한 수학적 우아함을 지닌 시스템을 설계하는 것은 인간의 약점을 비위 맞추는 것보다 우리 대부분에게 훨씬 더 매력적으로 들립니다. 그리고 수학적 우아함의 역할은 있습니다. 어떤 종류의 우아함은 프로그램을 이해하기 쉽게 만듭니다. 그러나 우아함 자체가 목적은 아닙니다.
그리고 제가 언어가 인간의 약점에 맞춰 설계되어야 한다고 말할 때, 저는 언어가 나쁜 프로그래머를 위해 설계되어야 한다는 의미가 아닙니다. 사실 저는 최고의 프로그래머를 위해 설계해야 한다고 생각하지만, 최고의 프로그래머조차도 한계가 있습니다. 모든 변수가 정수 첨자가 붙은 문자 x인 언어로 프로그래밍하는 것을 좋아하는 사람은 아무도 없을 것이라고 생각합니다.
2. 자신과 친구들을 위해 설계하세요.
프로그래밍 언어의 역사를 보면, 최고의 언어 중 상당수는 저자 자신이 사용하기 위해 설계되었고, 최악의 언어 중 상당수는 다른 사람들이 사용하도록 설계되었습니다.
언어가 다른 사람들을 위해 설계될 때, 그것은 항상 특정 그룹의 다른 사람들, 즉 언어 설계자만큼 똑똑하지 않은 사람들을 위한 것입니다. 그래서 당신을 깔보는 듯한 언어를 얻게 됩니다. Cobol이 가장 극단적인 경우이지만, 많은 언어가 이러한 정신에 스며들어 있습니다.
이것은 언어가 얼마나 추상적인지와는 아무런 관련이 없습니다. C는 상당히 저수준이지만, 저자들이 사용하기 위해 설계되었고, 그래서 해커들이 좋아하는 것입니다.
나쁜 프로그래머를 위해 언어를 설계해야 한다는 주장은 좋은 프로그래머보다 나쁜 프로그래머가 더 많기 때문입니다. 그럴 수도 있습니다. 그러나 그 소수의 좋은 프로그래머들이 소프트웨어의 불균형적으로 큰 부분을 작성합니다.
저는 최고의 해커들이 좋아할 만한 언어를 어떻게 설계할 것인가라는 질문에 관심이 있습니다. 저는 이것이 좋은 프로그래밍 언어를 어떻게 설계할 것인가라는 질문과 동일하다고 생각하지만, 그렇지 않더라도 적어도 흥미로운 질문입니다.
3. 프로그래머에게 가능한 한 많은 통제권을 부여하세요.
많은 언어들(특히 다른 사람들을 위해 설계된 언어들)은 가정교사 같은 태도를 취합니다. 즉, 그들이 당신에게 좋지 않다고 생각하는 일을 막으려 합니다. 저는 그 반대 접근 방식을 좋아합니다. 프로그래머에게 가능한 한 많은 통제권을 부여하는 것입니다.
제가 Lisp를 처음 배웠을 때 가장 좋았던 점은 Lisp가 저를 동등한 파트너로 여겼다는 것입니다. 그때까지 제가 배웠던 다른 언어들에서는 언어와 그 언어로 작성된 제 프로그램이 있었고, 이 둘은 매우 분리되어 있었습니다. 그러나 Lisp에서는 제가 작성한 함수와 매크로가 언어 자체를 구성하는 것들과 똑같았습니다. 원한다면 언어를 다시 작성할 수도 있었습니다. 그것은 오픈 소스 소프트웨어와 같은 매력을 지녔습니다.
4. 간결함을 목표로 하세요.
간결함은 과소평가되고 심지어 경멸당하기도 합니다. 그러나 해커들의 마음을 들여다보면 그들이 간결함을 정말 사랑한다는 것을 알 수 있습니다. APL 같은 언어에서 단 몇 줄의 코드로 놀라운 일을 할 수 있었다고 해커들이 얼마나 자주 즐겁게 이야기하는 것을 들어보셨습니까? 저는 정말 똑똑한 사람들이 정말 좋아하는 것은 무엇이든 주목할 가치가 있다고 생각합니다.
저는 프로그램을 더 짧게 만들 수 있는 거의 모든 것이 좋다고 생각합니다. 많은 라이브러리 함수가 있어야 하고, 암시될 수 있는 것은 모두 암시되어야 하며, 구문은 지나칠 정도로 간결해야 하고, 심지어 이름도 짧아야 합니다.
짧아야 하는 것은 프로그램뿐만이 아닙니다. 매뉴얼도 얇아야 합니다. 매뉴얼의 상당 부분은 설명, 유보 사항, 경고 및 특수 사례로 채워져 있습니다. 매뉴얼을 줄이도록 스스로를 강제한다면, 가장 좋은 경우 언어에서 너무 많은 설명을 필요로 했던 부분을 고쳐서 그렇게 할 수 있습니다.
5. 해킹이 무엇인지 인정하세요.
많은 사람들이 해킹이 수학이거나 적어도 자연 과학과 같은 것이기를 바랍니다. 저는 해킹이 건축과 더 비슷하다고 생각합니다. 건축은 건축가들이 무너지지 않는 건물을 설계해야 한다는 점에서 물리학과 관련이 있지만, 건축가들의 실제 목표는 훌륭한 건물을 만드는 것이지 정역학에 대한 발견을 하는 것이 아닙니다.
해커들이 좋아하는 것은 훌륭한 프로그램을 만드는 것입니다. 그리고 저는 적어도 우리 마음속으로는, 이 작업이 연구 논문이라는 통상적인 지적 통화로 쉽게 번역되지 않더라도 훌륭한 프로그램을 작성하는 것이 칭찬할 만한 일이라는 것을 기억해야 한다고 생각합니다. 지적으로는, 프로그래머들이 좋아할 만한 언어를 설계하는 것이 논문으로 발표할 수 있는 어떤 아이디어를 구현한 끔찍한 언어를 설계하는 것만큼이나 가치 있는 일입니다.
1. 대규모 라이브러리를 어떻게 조직할까요?
라이브러리는 프로그래밍 언어의 점점 더 중요한 구성 요소가 되고 있습니다. 또한 점점 더 커지고 있으며, 이는 위험할 수 있습니다. 원하는 라이브러리 함수를 찾는 데 직접 작성하는 것보다 시간이 더 오래 걸린다면, 그 모든 코드는 매뉴얼을 두껍게 만드는 것 외에는 아무것도 하지 않는 것입니다. (Symbolics 매뉴얼이 좋은 예였습니다.) 그래서 저는 라이브러리를 조직하는 방법에 대해 연구해야 한다고 생각합니다. 이상적인 것은 프로그래머가 어떤 라이브러리 호출이 올바른 일을 할지 추측할 수 있도록 설계하는 것입니다.
2. 사람들이 정말 접두사 구문을 두려워할까요?
이것은 제가 수년 동안 궁금해했지만 여전히 답을 모르는 미해결 문제입니다. 접두사 구문은 수학을 제외하고는 저에게 완벽하게 자연스럽게 느껴집니다. 그러나 Lisp의 많은 비인기는 단순히 익숙하지 않은 구문 때문일 수도 있습니다. 만약 그렇다면, 그것에 대해 무엇을 해야 할지는 또 다른 문제입니다.
3. 서버 기반 소프트웨어에 무엇이 필요할까요?
저는 향후 20년 동안 작성될 가장 흥미로운 새로운 애플리케이션 중 상당수가 웹 기반 애플리케이션, 즉 서버에 상주하며 웹 브라우저를 통해 사용자와 소통하는 프로그램이 될 것이라고 생각합니다. 그리고 이러한 종류의 프로그램을 작성하려면 몇 가지 새로운 것이 필요할 수 있습니다.
우리가 필요로 할 한 가지는 서버 기반 앱이 출시되는 새로운 방식에 대한 지원입니다. 데스크톱 소프트웨어처럼 1년에 한두 번의 대규모 릴리스를 하는 대신, 서버 기반 앱은 일련의 작은 변경 사항으로 출시됩니다. 하루에 5번 또는 10번의 릴리스가 있을 수도 있습니다. 그리고 일반적으로 모든 사람이 항상 최신 버전을 사용할 것입니다.
프로그램을 디버깅 가능하도록 설계하는 방법을 아시죠? 마찬가지로 서버 기반 소프트웨어는 변경 가능하도록 설계되어야 합니다. 쉽게 변경할 수 있어야 하며, 적어도 무엇이 작은 변경이고 무엇이 중대한 변경인지 알아야 합니다.
서버 기반 소프트웨어에 유용할 수 있는 또 다른 놀라운 것은 바로 연속(continuations)입니다. 웹 기반 소프트웨어에서는 연속 전달 스타일(continuation-passing style)과 같은 것을 사용하여 웹 세션의 본질적으로 무상태(stateless) 환경에서 서브루틴의 효과를 얻을 수 있습니다. 너무 비싸지 않다면 실제 연속을 갖는 것이 가치 있을 수도 있습니다.
4. 어떤 새로운 추상화가 발견될 여지가 남아 있을까요?
이것이 얼마나 합리적인 희망인지는 모르겠지만, 개인적으로 정말 하고 싶은 한 가지는 새로운 추상화를 발견하는 것입니다. 일급 함수(first class functions)나 재귀(recursion) 또는 심지어 키워드 매개변수(keyword parameters)를 갖는 것만큼 큰 차이를 만들 수 있는 어떤 것입니다. 이것은 불가능한 꿈일 수도 있습니다. 이런 것들은 그렇게 자주 발견되지 않습니다. 하지만 저는 항상 찾고 있습니다.
1. 원하는 어떤 언어든 사용할 수 있습니다.
애플리케이션 프로그램을 작성하는 것은 한때 데스크톱 소프트웨어를 작성하는 것을 의미했습니다. 그리고 데스크톱 소프트웨어에서는 운영 체제와 동일한 언어로 애플리케이션을 작성하는 경향이 강했습니다. 그래서 10년 전에는 소프트웨어를 작성하는 것이 거의 C로 소프트웨어를 작성하는 것을 의미했습니다. 결국 애플리케이션 프로그램은 특이한 언어로 작성되어서는 안 된다는 전통이 생겨났습니다. 그리고 이 전통은 너무 오랫동안 발전하여 관리자나 벤처 캐피탈리스트와 같은 비기술적인 사람들도 이를 알게 되었습니다.
서버 기반 소프트웨어는 이 모든 모델을 날려버립니다. 서버 기반 소프트웨어로는 원하는 어떤 언어든 사용할 수 있습니다. 아직 거의 아무도 이것을 이해하지 못합니다(특히 관리자와 벤처 캐피탈리스트는 더욱 그렇습니다). 소수의 해커들만이 이를 이해하고 있으며, 그래서 우리는 Perl과 Python 같은 새로운 독립적인 언어에 대해 듣게 되는 것입니다. 사람들이 이 언어들을 사용하여 Windows 앱을 작성하기 때문에 Perl과 Python에 대해 듣는 것이 아닙니다.
이것이 프로그래밍 언어 설계에 관심 있는 우리에게 의미하는 바는, 이제 잠재적으로 우리의 작업에 대한 실제 청중이 생겼다는 것입니다.
2. 속도는 프로파일러에서 나옵니다.
언어 설계자들, 또는 적어도 언어 구현자들은 빠른 코드를 생성하는 컴파일러를 작성하는 것을 좋아합니다. 그러나 저는 이것이 사용자에게 언어를 빠르게 만드는 것이라고 생각하지 않습니다. Knuth는 오래전에 속도는 몇몇 중요한 병목 현상에서만 중요하다고 지적했습니다. 그리고 시도해 본 사람이라면 누구나 이러한 병목 현상이 어디에 있는지 추측할 수 없다는 것을 압니다. 프로파일러가 해답입니다.
언어 설계자들은 잘못된 문제를 해결하고 있습니다. 사용자들은 벤치마크가 빠르게 실행될 필요가 없습니다. 그들이 필요한 것은 자신의 프로그램 중 어떤 부분이 다시 작성되어야 하는지 보여줄 수 있는 언어입니다. 실제 속도는 거기서 나옵니다. 따라서 언어 구현자들이 컴파일러 최적화에 들였을 시간의 절반을 좋은 프로파일러를 작성하는 데 사용한다면 순이익이 될 수도 있습니다.
3. 언어 설계를 이끌 애플리케이션이 필요합니다.
이것이 절대적인 규칙은 아닐 수 있지만, 최고의 언어들은 모두 작성하는 데 사용된 어떤 애플리케이션과 함께 발전한 것처럼 보입니다. C는 시스템 프로그래밍에 필요했던 사람들에 의해 작성되었습니다. Lisp는 부분적으로 기호 미분(symbolic differentiation)을 수행하기 위해 개발되었으며, McCarthy는 너무나 시작하고 싶어서 1960년 Lisp에 대한 첫 논문에서도 미분 프로그램을 작성했습니다.
특히 당신의 애플리케이션이 어떤 새로운 문제를 해결한다면 좋습니다. 그것은 당신의 언어가 프로그래머에게 필요한 새로운 기능을 갖도록 이끌 것입니다. 저는 개인적으로 서버 기반 애플리케이션을 작성하는 데 좋은 언어를 작성하는 데 관심이 있습니다.
[패널 토론 중, Guy Steele도 이 점을 언급하며, 당신의 언어가 컴파일러 작성을 위한 것이 아니라면 애플리케이션이 당신의 언어 컴파일러를 작성하는 것으로 구성되어서는 안 된다는 추가적인 제안을 했습니다.]
4. 언어는 일회용 프로그램을 작성하는 데 좋아야 합니다.
일회용 프로그램이 무엇인지 아실 겁니다. 어떤 제한된 작업을 위해 빠르게 작성하는 것입니다. 저는 주변을 둘러보면 많은 크고 진지한 프로그램들이 일회용 프로그램으로 시작되었다는 것을 알게 될 것이라고 생각합니다. 대부분의 프로그램이 일회용 프로그램으로 시작되었다고 해도 놀라지 않을 것입니다. 따라서 일반적으로 소프트웨어를 작성하는 데 좋은 언어를 만들고 싶다면, 일회용 프로그램을 작성하는 데 좋아야 합니다. 왜냐하면 그것이 대부분의 소프트웨어의 유충 단계이기 때문입니다.
5. 구문은 의미와 연결되어 있습니다.
구문(syntax)과 의미(semantics)를 완전히 분리된 것으로 생각하는 것이 전통적입니다. 이것은 충격적으로 들릴 수 있지만, 그렇지 않을 수도 있습니다. 저는 당신의 언어에서 원하는 것이 그것을 어떻게 표현하는지와 관련이 있을 수 있다고 생각합니다.
최근 Robert Morris와 이야기했는데, 그는 연산자 오버로딩(operator overloading)이 중위 구문(infix syntax)을 가진 언어에서 더 큰 이점이라고 지적했습니다. 접두사 구문(prefix syntax)을 가진 언어에서는 당신이 정의하는 모든 함수가 사실상 연산자입니다. 만약 당신이 만든 새로운 숫자 타입에 대한 덧셈을 정의하고 싶다면, 단순히 그것들을 더하는 새로운 함수를 정의하면 됩니다. 중위 구문 언어에서 그렇게 한다면, 오버로드된 연산자의 사용과 함수 호출 사이에는 외관상 큰 차이가 있습니다.
1. 새로운 프로그래밍 언어.
1970년대에는 새로운 프로그래밍 언어를 설계하는 것이 유행이었습니다. 최근에는 그렇지 않았습니다. 그러나 저는 서버 기반 소프트웨어가 새로운 언어를 다시 유행시킬 것이라고 생각합니다. 서버 기반 소프트웨어로는 원하는 어떤 언어든 사용할 수 있으므로, 누군가가 실제로 사용 가능한 다른 언어보다 더 나아 보이는 언어를 설계한다면, 위험을 감수하고 그것을 사용할 사람들이 있을 것입니다.
2. 시분할.
Richard Kelsey는 지난 패널에서 이것을 다시 때가 온 아이디어로 제시했고, 저는 그에게 전적으로 동의합니다. 제 추측(그리고 Microsoft의 추측인 듯합니다)은 많은 컴퓨팅이 데스크톱에서 원격 서버로 이동할 것이라는 것입니다. 다시 말해, 시분할(time-sharing)이 돌아왔습니다. 그리고 저는 언어 수준에서 이에 대한 지원이 필요할 것이라고 생각합니다. 예를 들어, Richard와 Jonathan Rees가 Scheme 48 내에서 프로세스 스케줄링(process scheduling)을 구현하는 데 많은 작업을 했다는 것을 알고 있습니다.
3. 효율성.
최근에는 컴퓨터가 마침내 충분히 빨라진 것처럼 보이기 시작했습니다. 점점 더 바이트 코드(byte code)에 대해 듣기 시작했는데, 이는 적어도 저에게는 우리가 여유 사이클(cycles to spare)을 가지고 있다고 느끼는 것을 의미합니다. 그러나 서버 기반 소프트웨어에서는 그렇지 않을 것이라고 생각합니다. 누군가는 소프트웨어가 실행되는 서버 비용을 지불해야 할 것이고, 기계당 지원할 수 있는 사용자 수가 자본 비용의 제수(divisor)가 될 것입니다.
그래서 저는 효율성이 중요할 것이라고 생각합니다. 적어도 계산 병목 현상에서는 말입니다. 서버 기반 애플리케이션은 많은 입출력(i/o)을 수행하기 때문에 입출력을 빠르게 하는 것이 특히 중요할 것입니다.
결국 바이트 코드가 승리하지 못할 수도 있습니다. Sun과 Microsoft는 현재 일종의 바이트 코드 전쟁을 벌이고 있는 것처럼 보입니다. 그러나 그들이 그렇게 하는 것은 바이트 코드가 프로세스에 자신들을 삽입하기에 편리한 장소이기 때문이지, 바이트 코드 자체가 좋은 아이디어이기 때문이 아닙니다. 이 전체 전장이 우회될 수도 있습니다. 그것은 다소 재미있을 것입니다.
1. 클라이언트.
이것은 단지 추측이지만, 제 추측으로는 대부분의 애플리케이션에서 승리하는 모델은 순수하게 서버 기반이 될 것입니다. 모든 사람이 당신의 클라이언트를 가질 것이라는 가정하에 소프트웨어를 설계하는 것은 모든 사람이 정직할 것이라는 가정하에 사회를 설계하는 것과 같습니다. 물론 편리하겠지만, 그런 일은 결코 일어나지 않을 것이라고 가정해야 합니다.
저는 어떤 종류의 웹 접근 기능을 가진 장치들이 확산될 것이라고 생각하며, 그 장치들에 대해 가정할 수 있는 것은 간단한 HTML과 폼을 지원할 수 있다는 것뿐입니다. 휴대폰에 브라우저가 있을까요? 팜 파일럿에 전화기가 있을까요? 블랙베리가 더 큰 화면을 가질까요? 게임보이로 웹을 탐색할 수 있을까요? 시계로요? 저는 모릅니다. 그리고 모든 것이 서버에만 있다고 가정한다면 알 필요도 없습니다. 모든 두뇌를 서버에 두는 것이 훨씬 더 견고합니다.
2. 객체 지향 프로그래밍.
이것이 논란의 여지가 있다는 것을 알지만, 저는 객체 지향 프로그래밍(object-oriented programming)이 그렇게 대단한 것이라고 생각하지 않습니다. 저는 그것이 윈도우 시스템, 시뮬레이션, CAD 프로그램과 같이 특정 종류의 데이터 구조가 필요한 특정 애플리케이션에는 훌륭한 모델이라고 생각합니다. 그러나 왜 그것이 모든 프로그래밍의 모델이 되어야 하는지는 모르겠습니다.
저는 대기업 사람들이 객체 지향 프로그래밍을 좋아하는 이유 중 하나는 그것이 많은 '일'처럼 보이는 것을 만들어내기 때문이라고 생각합니다. 예를 들어, 자연스럽게 정수 목록으로 표현될 수 있는 것이 이제는 온갖 비계(scaffolding)와 번잡함(hustle and bustle)을 가진 클래스로 표현될 수 있습니다.
객체 지향 프로그래밍의 또 다른 매력은 메서드(methods)가 일급 함수(first class functions)의 일부 효과를 제공한다는 것입니다. 그러나 이것은 Lisp 프로그래머들에게는 오래된 소식입니다. 실제 일급 함수를 가지고 있다면, 모든 것을 클래스와 메서드의 틀에 강제로 넣는 대신, 당면한 작업에 적합한 어떤 방식으로든 그것들을 사용할 수 있습니다.
이것이 언어 설계에 의미하는 바는, 객체 지향 프로그래밍을 너무 깊이 내장해서는 안 된다는 것입니다. 아마도 해답은 더 일반적이고 근본적인 것을 제공하고, 사람들이 원하는 객체 시스템을 라이브러리로 설계하도록 하는 것일 겁니다.
3. 위원회에 의한 설계.
언어를 위원회에서 설계하게 하는 것은 큰 함정이며, 모두가 아는 이유 때문만은 아닙니다. 위원회가 울퉁불퉁하고 일관성 없는 설계를 내놓는 경향이 있다는 것은 모두가 압니다. 그러나 저는 더 큰 위험은 그들이 위험을 감수하지 않을 것이라는 점이라고 생각합니다. 한 사람이 책임자일 때는 위원회가 결코 동의하지 않을 위험을 감수할 수 있습니다.
그렇다면 좋은 언어를 설계하기 위해 위험을 감수하는 것이 필수적일까요? 많은 사람들은 언어 설계가 통념에 상당히 가깝게 따라야 하는 것이라고 의심할 수 있습니다. 저는 이것이 사실이 아니라고 확신합니다. 사람들이 하는 다른 모든 일에서 보상은 위험에 비례합니다. 언어 설계가 왜 달라야 할까요?