# 리치 히키(Rich Hickey) Q & A
by Michael Fogus
# 프로그래밍에 매료된 계기
Java 가상 머신에서 실행되는 Lisp인 Clojure의 발명가로 가장 잘 알려져 있으며, Scheme과 Common Lisp 이후 처음으로 널리 관심을 끌게 된 Lisp 계열의 새로운 멤버인 Rich Hickey는 20년 동안 소프트웨어 개발자 및 컨설턴트로 활동해 왔습니다.
Clojure 작업을 시작하기 전에 그는 Lisp를 Java 또는 Microsoft의 공용 언어 런타임과 결합하려는 시도를 네 차례에 걸쳐 시도했는데, jfli, Foil, Lisplets 및 DotLisp가 가장 먼저 큰 주목을 받았습니다. 지금까지 인터뷰어인 Michael Fogus의 The Joy of Clojure를 포함하여 Clojure에 관한 책이 네 권이나 출판되었습니다. 2010년에 개최된 첫 번째 클로저 컨퍼런스인 ClojureConj에는 200명 이상의 참가자가 모였습니다. 그리고 이 글을 쓰는 현재, 2007년에 시작된 이후 46,000개 이상의 메시지를 게시한 4,880명의 회원을 보유한 Clojure Google 그룹이 있습니다.
과거에는 작곡을 전공하고 기타리스트로 활동했으며, 뉴욕대학교에서 고급 C++ 과정을 가르치기도 한 실력 있는 C++ 프로그래머였습니다. 이 인터뷰에서 마이클 포거스는 히키와 함께 복잡성, 추상화, 클로저의 과거, 현재, 미래에 대해 이야기합니다.
포거스: 프로그래밍에 매료된 계기는 무엇인가요?
히키: 녹음 스튜디오를 운영하던 중 컴퓨터를 구입하게 되었습니다. 미디가 비교적 초창기였던 시절이라 컴퓨터가 할 수 있는 일에 흥미를 느꼈고, 앞으로 할 수 있는 일의 가능성에 가득 차 있었습니다. 그래서 C와 어셈블리 언어를 배워 음악 소프트웨어를 만들기 시작했습니다. 바로 매료되었죠.
포거스: 기타를 치시죠?
히키: 네, 대학에서 작곡을 전공했어요.
포거스: 훌륭한 프로그래머는 숙련된 음악가라는 것을 종종 발견했습니다. 음악 예술이 프로그래밍 기술과 관련이 있다고 생각하시나요?
히키: 한 쪽에 유용한 기술이 다른 쪽에도 유용한 경우가 많다고 생각합니다. 코딩과 음악 연주는 연습을 보상하는 분야라는 점을 제외하면 상당히 다르지만 소프트웨어 디자인과 작곡은 많은 유사점을 가지고 있습니다. 둘 다 추상화를 조작하고 조정하며, 프로세스인 프로그램의 경우 시간이 지남에 따라 그 실현을 구상하는 과정을 포함합니다. 저는 확실히 소프트웨어 디자인이 작곡에서 추구하고자 했던 창의적 충동을 충족시켜주며, 작곡을 완전히 대체할 수 있다는 것을 알았습니다.
Best known as the inventor of Clojure, a Lisp that runs on the Java Virtual Machine and the first new member of the Lisp family to attract any widespread interest since Scheme and Common Lisp, Rich Hickey has been a software developer and consultant for two decades.
Prior to starting work on Clojure, he made four attempts to combine Lisp with either Java or Microsoft's Common Language Runtime: jfli, Foil, Lisplets, and DotLisp but Clojure was the first to draw significant attention. To date there have been four books published on Clojure, including The Joy of Clojure by interviewer Michael Fogus. The first Clojure conference, ClojureConj held in 2010, drew over two hundred attendees. And the Clojure Google group has, as of this writing, 4,880 members who have posted over 46,000 messages since it was started in 2007.
In past lives Hickey has been a music composition major, a guitarist, and a serious C++ programmer, even teaching an Advanced C++ course at New York University. In this interview, Michael Fogus talks with Hickey about complexity, abstraction, and the past, present, and future of Clojure.
Fogus: What drew you to programming?
Hickey: I was running a recording studio and got a computer for it. I was intrigued by what it could do—this was in the relatively early days of MIDI—and filled with the possibilities of what it might do. So I taught myself C and assembly language and started writing music software. I was immediately hooked.
Fogus: You play guitar, correct?
Hickey: Yes, I was a music composition major in college.
Fogus: I've often found that great programmers are skilled musicians. Do you think that musical art is related to the art of programming?
Hickey: I think the skills useful for one are often useful for the other. Coding and music performance are fairly different, other than being disciplines that reward practice, but software design and composition have a lot of similarities. Both involve manipulating and coordinating abstractions, and envisioning their realization, in the case of programs that are processes, in and over time. I've certainly found software design satisfies the creative urge I intended to pursue in composition, and has completely displaced it.
# 첫번째 프로그램
포거스: 가장 흥미로웠던 첫 번째 프로그램은 무엇인가요?
히키: 컴퓨팅의 가능성에 흥미를 느끼게 해준 초창기 프로그램은 간단한 진화 프로그램이었습니다. 벌레가 화면에서 먹이를 찾아 돌아다니며 무작위로 움직이면서 시작하는 프로그램이었죠. 잠자리에 들기 전에 이 프로그램을 실행하면 벌레들이 이리저리 움직이고, 잠에서 깨어나면 벌레들이 이렇게 유연하고 효율적인 이동 전략을 진화시킨 것을 발견하곤 했죠. 그때 시뮬레이션과 생성 프로그램을 통해 분석과 계산으로는 볼 수 없는 것을 보고 발견할 수 있다는 것을 깨달았습니다.
포거스: 프로그래머로서 기술을 향상하기 위해 무엇을 하나요? 특별히 연습하거나 애용하는 프로젝트가 있나요?
히키: 저는 끊임없이 책을 읽습니다. 컴퓨터가 유용한 일을 하도록 하기 위한 목적이 아닌 프로그래밍은 하지 않기 때문에 따로 연습을 하지 않습니다. 입력하는 시간보다 문제에 대해 생각하는 데 더 많은 시간을 할애하려고 노력합니다.
포거스: 독서 얘기가 나와서 말인데, 아마존에 클로저 책장 목록을 만들어서 큰 인기를 끌었던 적이 있습니다. 그 목록에 있는 책들 중에서 모든 프로그래머가 읽어야 한다고 생각하는 책이 있나요?
히키: 몇 권만 강조할 수는 없습니다. 각각 어떤 것은 조명하고 어떤 것은 무시합니다. 저는 다른 사람들이 해야 할 일을 옹호하는 것은 별로 편하지 않습니다. 개인적으로 저는 목록에 있는 책과 같은 책과 학계의 논문을 지속적으로 읽으려고 노력하는데, 대부분은 온라인에서 구할 수 있습니다. 그리고 함께 일하는 사람들의 배움에 대한 의지를 보고 싶습니다.
포거스: Clojure 책장 목록에서 선택한 몇 가지에 대해 이야기해 보겠습니다. 예를 들어, 겉으로 보기에 클로저는 루비와 매우 다른 것 같지만 Thomas, Fowler, Hunt의 Programming Ruby 1.9를 목록에 올려놓으셨어요. 그 책과 루비 전반이 클로저 디자인에 어떤 영향을 미쳤나요?
히키: 영향은 긍정적이거나 부정적일 수 있습니다. 파이썬과 루비를 보면서 또 다른 구문과 또 다른 객체 시스템을 만들고 싶지 않다는 결심을 하게 되었습니다. 반면에 파이썬과 루비는 간결함에 대한 높은 기준을 제시했습니다.
Fogus: What was the first interesting program that you wrote?
Hickey: An early program I wrote that got me excited about the possibilities of computing was a simple evolution program. Bugs moved around on the screen looking for food, with random movement to start. I would start it before bed, with the bugs shaking around, and awake to find they had evolved these fluid, efficient movement strategies. It was then that I realized that simulations and generative programs would allow us to see and discover things that analysis and calculation couldn't.
Fogus: What do you do to improve your skills as a programmer? Do you have certain exercises or pet projects that you use?
Hickey: I read relentlessly. I don't do any programming not directed at making the computer do something useful, so I don't do any exercises. I try to spend more time thinking about the problem than I do typing it in.
Fogus: Speaking of reading, you once created a Clojure Bookshelf list on Amazon that was very popular. Of those books listed, are there any you think every programmer should read?
Hickey: I couldn't highlight just a few. Each illuminates some things and ignores others. I'm not really comfortable advocating what others ought to do. Personally, I try to read, on an ongoing basis, books such as those on the list and papers from academia, many of which are available online. And I like to see a commitment to learning on the part of people with whom I work.
Fogus: Let's talk about some of your choices for the Clojure Bookshelf list. For example, on the surface Clojure seems to be very different from Ruby, yet you list Programming Ruby 1.9 by Thomas, Fowler, and Hunt. How did that book, and Ruby in general, influence the design of Clojure?
Hickey: Well, influences can be positive or negative. Looking at Python and Ruby left me resolute that I didn't want to create yet another syntax and yet another object system. On the other hand, they set a high bar for concision.
# 문제 복잡성의 해결
포거스: 루비나 파이썬이 알고리즘 파생 구문을 간결함의 한계까지 끌어올렸다고 생각하시나요?
히키: 잘 모르겠어요. 저는 간결함보다는 복잡성을 줄이는 데 더 관심이 많아요.
포거스: 조금 더 살펴봅시다. 문제의 복잡성에는 대부분 언어와 무관한 복잡성이 있고, 언어 자체에 의해 부과되는 부수적인 복잡성이 있습니다. 클로저는 이 중 마지막 복잡성인 부수적인 복잡성을 어떻게 완화하나요?
히키: 부수적인 복잡성을 줄이는 것이 클로저의 주요 초점이며, 모든 영역에서 클로저가 어떻게 복잡성을 줄이는지 자세히 살펴볼 수 있습니다. 예를 들어 가변 상태는 부수적인 복잡성입니다. 그 메커니즘은 단순하거나 적어도 친숙해 보이지만 실제로는 매우 복잡합니다. 제 생각에는 시스템에서 가장 큰 문제입니다. 그래서 클로저는 불변 데이터를 기본값으로 설정합니다.
구문에 대해 이야기 했으므로 클래식 Lisp를 살펴 보겠습니다. 가장 단순한 구문으로 보이며 모든 것이 괄호로 묶인 기호, 숫자 및 기타 몇 가지 목록입니다. 이보다 더 간단할 수 있을까요? 그러나 실제로는 가장 단순하지 않은데, 그 균일성을 달성하려면 목록의 의미에 상당한 과부하가 걸려야 하기 때문입니다. 함수 호출, 그룹화 구조체, 데이터 리터럴 등이 그 예가 될 수 있습니다. 그리고 어떤 것을 결정하려면 컨텍스트를 사용해야 하므로 코드를 스캔하여 그 의미를 평가할 때 인지 부하가 증가합니다. 클로저는 목록에 복합 데이터 리터럴을 몇 개 더 추가하고 구문에 사용합니다. 이렇게 하면 목록은 거의 항상 호출과 유사한 것이고, 벡터는 그룹화에 사용되며, 맵에는 고유한 리터럴이 있습니다. 하나의 데이터 구조에서 세 개의 데이터 구조로 이동하면 인지 부하가 크게 줄어듭니다.
프로그래머로서 우리는 많은 부수적인 복잡성에 익숙해졌지만, 그렇다고 해서 덜 복잡해지는 것이 아니라 복잡성을 극복하는 데 더 능숙해질 뿐입니다. 하지만 더 유용한 일을 해야 하지 않을까요?
바로 포거스입니다: 그렇다면 부수적인 복잡성을 줄인 다음에는 클로저가 당면한 문제를 해결하는 데 어떻게 도움이 될 수 있을까요? 예를 들어, 이상적인 객체 지향 패러다임은 재사용을 촉진하기 위한 것이지만 Clojure는 고전적인 객체 지향이 아닌데, 재사용을 위해 코드를 어떻게 구조화할 수 있을까요?
히키: 저는 OO와 재사용에 대해 논쟁을 벌이고 싶지만, 자동차를 만드는 대신 바퀴를 재발명하는 것이 아니기 때문에 재사용이 가능하면 당면한 문제가 더 간단해집니다. 그리고 클로저가 JVM에 탑재되어 있기 때문에 많은 휠(라이브러리)을 사용할 수 있습니다. 라이브러리를 재사용할 수 있는 이유는 무엇일까요? 라이브러리는 한 가지 또는 몇 가지 작업을 잘 수행하고, 비교적 자급자족하며, 클라이언트 코드에 대한 요구 사항이 거의 없어야 합니다. 모든 Java 라이브러리가 이 기준을 충족하는 것은 아니지만, 많은 라이브러리가 이 기준에 부합합니다.
알고리즘 수준으로 내려가면 OO가 재사용을 심각하게 방해할 수 있다고 생각합니다. 특히 단순한 정보 데이터를 표현하기 위해 객체를 사용하는 것은 관계형 대수처럼 훨씬 강력하고 선언적이며 일반적인 메서드에 비해 정보 조각별 마이크로 언어, 즉 클래스 메서드를 생성하는 데 있어 거의 범죄에 가깝습니다. 정보를 담을 수 있는 고유한 인터페이스를 가진 클래스를 발명하는 것은 모든 단편 소설을 쓰기 위해 새로운 언어를 발명하는 것과 같습니다. 이는 재사용을 방해하며, 일반적인 OO 애플리케이션에서 코드가 폭발적으로 증가하는 결과를 초래합니다. 클로저는 이를 피하고 대신 정보에 대한 간단한 연관 모델을 옹호합니다. 이를 통해 여러 정보 유형에 걸쳐 재사용할 수 있는 알고리즘을 작성할 수 있습니다.
이 연관 모델은 클로저와 함께 제공되는 여러 추상화 중 하나에 불과하며, 재사용에 대한 접근 방식의 진정한 토대는 추상화 함수입니다. 개방적이고 큰 함수 집합이 개방적이고 작은 확장 가능한 추상화 집합에서 작동하도록 하는 것이 알고리즘 재사용 및 라이브러리 상호 운용성의 핵심입니다. 대부분의 Clojure 함수는 이러한 추상화 측면에서 정의되며, 라이브러리 작성자는 입력 및 출력 형식도 이러한 추상화 측면에서 설계하여 독립적으로 개발된 라이브러리 간에 엄청난 상호 운용성을 실현합니다. 이는 OO에서 볼 수 있는 DOM과 다른 것들과는 완전히 대조적입니다. 물론 OO에서도 java.util 컬렉션과 같은 인터페이스를 사용하여 유사한 추상화를 수행할 수 있지만, java.io에서와 마찬가지로 쉽게 그렇지 않을 수 있습니다.
Fogus: Do you think Ruby or Python has taken the ALGOL-derived syntax to the limit of its concision?
Hickey: I don't know. I'm more interested in reducing complexity than I am in concision.
Fogus: Let's explore that a little. There are the complexities of the problem, which are mostly language independent, and then there are incidental complexities imposed by the language itself. How does Clojure alleviate the last of these—the incidental complexities?
Hickey: Reducing incidental complexity is a primary focus of Clojure, and you could dig into how it does that in every area. For example, mutable state is an incidental complexity. The mechanics of it seem simple, or at least familiar, but the reality is quite complex. In my opinion, it is clearly the number one problem in systems. So, Clojure makes immutable data the default.
Since we were talking about syntax, let's look at classic Lisp. It seems to be the simplest of syntax, everything is a parenthesized list of symbols, numbers, and a few other things. What could be simpler? But in reality, it is not the simplest, since to achieve that uniformity, there has to be substantial overloading of the meaning of lists. They might be function calls, grouping constructs, or data literals, etc. And determining which requires using context, increasing the cognitive load when scanning code to assess its meaning. Clojure adds a couple more composite data literals to lists, and uses them for syntax. In doing so, it means that lists are almost always call-like things, and vectors are used for grouping, and maps have their own literals. Moving from one data structure to three reduces the cognitive load substantially.
As programmers we've become quite familiar with many incidental complexities, but that doesn't make them less complex, it just makes us more adept at overcoming them. But shouldn't we be doing something more useful?
Fogus: So once incidental complexities have been reduced, how can Clojure help solve the problem at hand? For example, the idealized object-oriented paradigm is meant to foster reuse, but Clojure is not classically object-oriented—how can we structure our code for reuse?
Hickey: I would argue about OO and reuse, but certainly, being able to reuse things makes the problem at hand simpler, as you are not reinventing wheels instead of building cars. And Clojure being on the JVM makes a lot of wheels—libraries—available. What makes a library reusable? It should do one or a few things well, be relatively self-sufficient, and make few demands on client code. None of that falls out of OO, and not all Java libraries meet this criteria, but many do.
When we drop down to the algorithm level, I think OO can seriously thwart reuse. In particular, the use of objects to represent simple informational data is almost criminal in its generation of per-piece-of-information micro-languages, i.e. the class methods, versus far more powerful, declarative, and generic methods like relational algebra. Inventing a class with its own interface to hold a piece of information is like inventing a new language to write every short story. This is anti-reuse, and, I think, results in an explosion of code in typical OO applications. Clojure eschews this and instead advocates a simple associative model for information. With it, one can write algorithms that can be reused across information types.
This associative model is but one of several abstractions supplied with Clojure, and these are the true underpinnings of its approach to reuse: functions on abstractions. Having an open, and large, set of functions operate upon an open, and small, set of extensible abstractions is the key to algorithmic reuse and library interoperability. The vast majority of Clojure functions are defined in terms of these abstractions, and library authors design their input and output formats in terms of them as well, realizing tremendous interoperability between independently developed libraries. This is in stark contrast to the DOMs and other such things you see in OO. Of course, you can do similar abstraction in OO with interfaces, for instance, the java.util collections, but you can just as easily not, as in java.io.
# 추구하고자 하는 열린 질문
포거스: "정보에 대한 단순 연관 모델"의 의미를 좀 더 자세히 설명해 주시겠어요?
히키: 정보를 표현하는 데 사용되는 대부분의 클래스는 명명된 속성/속성과 값의 맞춤형 연관 맵에 불과합니다. 하지만 커스터마이징 과정에서 보통 일반 맵처럼 취급할 수 있는 기능을 잃게 됩니다. 이러한 코드에는 이름/키별로 속성에 액세스/수정/추가하고 속성을 열거하는 등의 기능이 필요하기 때문에 일반적인 정보 조작 코드를 작성할 수 없게 됩니다. 연관 정보 모델은 이러한 기능을 유지하고 강조합니다.
포거스: 이러한 추상화 중심 접근 방식이 적합하지 않은 도메인이 있나요?
히키: 일반적으로 이 접근 방식은 보편적인 매력을 가지고 있다고 생각합니다. 추상화, 그리고 클로저와 같은 동적 언어에 대한 압박은 성능에 대한 추구에서 비롯됩니다. 최고의 성능을 추구하는 사람들에게는 클로저가 적합하지 않을 수도 있습니다. 스택과 배열 모두에 복합 값 유형이 없는 Java가 적합하지 않다고 생각할 수도 있습니다.
하지만 이는 동적 언어 중에서는 이미 상당히 빠른 속도를 자랑하는 클로저에서 지속적으로 개선되고 있는 부분입니다. 선택적 유형 힌트를 사용하면 이미 Java만큼 빠르게 로컬 코드를 생성할 수 있으며, 원시 인수 및 반환에 대한 새로운 작업을 통해 더 넓은 범위에서 이러한 속도를 구현할 수 있습니다. 전체 유형 시스템의 경직성과 복잡성을 유발하지 않으면서 추상화 스택의 가장 높은 수준까지 이러한 속도를 구현할 수 있는지 여부는 제가 추구하고자 하는 열린 질문입니다.
포거스: 예전 논문인 "템플릿 함수를 사용한 C++의 콜백"에서 C++, OOP, 정적 타이핑에 대해 호의적인 글을 쓰셨죠. 생각을 바꾼 이유는 무엇인가요?
히키: 잘 모르겠습니다. 저는 C++가 유연하다고 말했고, 실제로도 유연하며, C++용 콜백 시스템을 구현할 때는 객체 지향과 정적 타이핑에 맞춰야 한다고 말했죠. 이 글을 다시 읽으면서 더 흥미로웠던 점은 15년 전 그때 제가 주장했던 것과 동일한 주장을 확장 메커니즘으로서의 믹스인과 파생에 대해 지금도 여전히 하고 있다는 점입니다.
그렇긴 하지만 당시에는 확실히 C++의 팬이었고, 5년을 더 사용하면서 그런 생각이 사라졌습니다. 그 복잡성은 놀라웠습니다. 제 생각에는 GC 부족으로 인해 라이브러리 언어로서 실패했고, 정적 타이핑은 대규모 OO 시스템이 비참한 진흙덩어리가 되는 것을 막는 데 실패했습니다. 변경 가능한 대형 객체 그래프가 골칫거리였고, 이를 해결하기에는 const가 부적절했습니다. C++의 성능 이점이 약화되거나 덜 중요해지면 왜 굳이 C++를 사용해야 하는지 의문이 들 수밖에 없었습니다. 지금은 아주 특별한 경우를 제외하고는 GC가 없는 언어로 작업하는 것을 상상할 수 없습니다.
그러던 중 훨씬 더 유연하고, 역동적이며, 간단하고, 빠른 Common Lisp를 발견했고, 이 언어로 프로그래밍하기로 결심했습니다. 그리고 마침내 Clojure를 사용하면서 그 꿈이 실현되고 실용화되었습니다.
Fogus: Can you expand on what you mean by "simple associative model for information"?
Hickey: Most classes used to represent information are just bespoke associative maps of named properties/attributes to values. But in the customization process we usually lose the ability to treat them like generic maps. This then precludes the writing of generic information manipulation code, since such code requires the capability to generically access/modify/add properties by name/key, enumerate properties, etc. An associative information model retains and emphasizes those capabilities.
Fogus: Are there any domains where this abstraction-oriented approach isn't suitable?
Hickey: I think the approach in general has universal appeal. The pressure on abstractions, and on dynamic languages like Clojure, comes from the quest for performance. People seeking the utmost performance might not find Clojure suitable. They might not even find Java suitable, with its lack of composite value types both on the stack and in arrays.
That said, this is an area of ongoing improvement in Clojure, which is already pretty fast, as dynamic languages go. With optional type hints, Clojure can already generate local code as fast as Java, and new work on primitive arguments and returns is enabling that speed across larger scopes. Whether that can be carried to the highest levels of the abstraction stack, without incurring the rigidity and complexity of a full-on type system, is an open question I intend to pursue.
Fogus: In an old paper of yours, "Callbacks in C++ Using Template Functors", you write favorably about C++, OOP, and static typing. Why did you change your mind?
Hickey: I'm not sure I did. I said C++ was flexible—it is—and that, when implementing a callback system for C++, one should remain aligned with its object orientation and static typing. More interesting to me, in rereading it, is that I am still now making the same arguments I made then, fifteen years ago, against mixins and derivation as extension mechanisms.
That said, I certainly was a fan of C++ in the day, and five more years of it cured me of that. The complexity is stunning. It failed as the library language it purported to be, due to lack of GC, in my opinion, and static typing failed to keep large OO systems from becoming wretched balls of mud. Large mutable object graphs are the sore point, and const is inadequate to address it. Once C++'s performance advantage eroded or became less important, you had to wonder—why bother? I can't imagine working in a language without GC today, except in very special circumstances.
Along the way, I discovered Common Lisp, which was much more flexible, dynamic, simpler, and fast enough, and decided that was how I wanted to program. Finally, with Clojure, that is becoming possible, and practical, for me.
# 다른 언어에 대하여
포거스: 이메일 교환에서 Lisp를 배우는 과정에서 제 책 제목의 동기가 된 기쁨을 경험했다고 언급하셨습니다. 그 느낌에 대해 자세히 설명해 주실 수 있나요? 그리고 왜 Lisp가 그런 느낌을 촉진하는 것 같은지 설명해 주시겠어요?
히키: 개념적 단순성, 방대한 라이브러리, 매크로의 사용자 지정 기능 사이에서 중요한 코드만 작성할 수 있는 지점에 도달할 수 있는 것이 Lisp입니다. 그리고 그 지점에 도달하면 바둑을 두거나 악기를 연주하거나 명상을 할 때와 같이 매우 높은 수준의 집중력을 발휘할 수 있습니다. 그리고 이러한 활동을 할 때와 마찬가지로 집중력이 높아진 정신 상태와 함께 희열을 느낄 수 있습니다.
포거스: 전문적으로 어떤 프로그래밍 언어를 사용하셨나요?
히키: 주로 C, C++, Java, C#, Common Lisp, Clojure를 사용했습니다.
Fogus: 두 번째로 좋아하는 프로그래밍 언어는 무엇인가요?
히키: 이들 중 하나라도 더 만족스러웠다면 Clojure를 작성하지 않았을 것입니다. Clojure가 아닌 다른 언어를 선택해야 한다면 좋은 Common Lisp와 그 소스 코드가 가장 만족스러울 것입니다. 여가 시간이 더 많다면 하스켈로 시간을 보내고 싶어요.
포거스: 저는 클로저에 대한 열기가 부분적으로는 폴 그레이엄의 오리지널 리스프 에세이와 파이썬과 루비의 인기로 인해 조성된 일반적인 개방성 때문이라고 생각합니다. 지금까지 클로저의 성공 요인은 무엇이라고 생각하시나요?
히키: 저도 그 이론에 동의합니다. 폴 그레이엄의 에세이가 큰 영향을 미쳤고, 사람들이 프로그래밍에 대해 Lisp와 같은 사고 방식과 기존의 통념을 거부하는 것의 중요성에 대해 관심을 갖게 되었다고 생각합니다. 또한 Python과 Ruby, PHP와 Javascript는 사람들이 Java/C#/C++ 이외의 언어로 성공을 거두면서 언어 다양성의 르네상스를 알리는 데 기여했습니다. 이 모든 것이 클로저를 위한 길을 열었습니다.
클로저는 다른 곳에서 찾을 수 없는 거의 모든 것을 제공하기 때문에 흥미롭습니다. 하지만 언어의 특징과 기능의 다차원적 공간에서 다른 언어가 차지하지 못했던 빈자리를 차지하고 있다고 생각합니다. 그렇지 않았다면 저는 이 책을 쓰지 않았을 것입니다. 제가 일하고 싶었던 곳이고, 다른 사람들도 충분히 그곳에 가고 싶어 할 것입니다.
포거스: 개인적으로 클로저 커뮤니티의 분위기를 조성하기 위해 많은 일을 하셨어요. 언어의 커뮤니티가 성공에 얼마나 기여한다고 생각하시나요?
히키: 큰 요소라고 생각합니다. 저는 클로저 커뮤니티에 매우 만족하고 자랑스럽게 생각합니다. 사람들은 서로 돕고, 존중하며, 긍정적입니다. 중요한 점은 사람들이 자신의 감정을 표출하거나 자신이 옳다는 것을 증명하는 것보다 커뮤니티의 질을 유지하는 것이 더 중요하다고 판단할 정도로 커뮤니티 자체를 소중히 여긴다는 점입니다.
포거스: Clojure를 만들기까지 진행된 Lisp 관련 프로젝트에 대해 간략히 말씀해 주시겠어요? 구체적으로 dotLisp, Foil, Lisplets의 목표는 무엇이었나요?
Hickey: 닷리스프는 리스프 인터프리터를 작성하기 위한 피할 수 없는 통과의례였습니다. 흥미로운 점은 Clojure와 마찬가지로 호스트에 호스팅되고 호스트(이 경우에는 CLR)에 편리하게 액세스할 수 있도록 설계되었다는 점입니다.
다음으로 Jfli가 나왔는데, 이는 커먼 리스프 프로세스 내에 JVM을 내장하여 Java에 대한 액세스를 제공하려는 시도였습니다. 이 방법도 괜찮게 작동했지만 여전히 우리끼리만 사용하는 것 같은 불만족스러운 느낌이 들었습니다.
Foil은 본질적으로 동일한 개념이었지만 프로세스에서 벗어났습니다. 동일한 섹스프루 와이어 프로토콜을 사용하여 Java와 CLR 상호 운용을 모두 지원했습니다. 여전히 우리와 그들 간의 관계이며 동일한 프로세스보다 느리지만 이론적으로는 덜 방해가 됩니다.
Lisplets는 훨씬 더 분리되어 있었으며, 단지 Java 서브렛 요청과 응답을 sexpr로 변환하여 Lisp에서 서브렛을 작성할 수 있도록 했습니다.
결국, 이들 중 어느 것도 실제로 Lisp를 더 전통적인 상점에 몰래 숨겨 넣을 수 있게 해주지 않았고, Lisp의 풍부한 Java 라이브러리에 만족스럽게 빠르게 액세스할 수 있게 해주지도 못했습니다.
Fogus: In an email exchange, you mentioned that during the process of learning Lisp, you experienced joy—a motivation for the title of my book, by the way. Can you elaborate on that feeling and why it seems that Lisp fosters such a feeling?
Hickey: You can reach a point with Lisp where, between the conceptual simplicity, the large libraries, and the customization of macros, you are able to write only code that matters. And, once there, you are able to achieve a very high degree of focus, such as you would when playing Go, or playing a musical instrument, or meditating. And then, as with those activities, there can be a feeling of elation that accompanies that mental state of focus.
Fogus: What programming languages have you used professionally?
Hickey: Mainly C, C++, Java, C#, Common Lisp, and Clojure.
Fogus: What is your second favorite programming language?
Hickey: If I had been more satisfied with any of those, I wouldn't have written Clojure. If I had to be stranded with something other than Clojure, I'd be happiest with a good Common Lisp and its source code. If I had more free time, I'd spend it with Haskell.
Fogus: I have a theory that the excitement surrounding Clojure is in part due to a general open-mindedness fostered by Paul Graham's original Lisp essays and the popularity of Python and Ruby. What do you attribute to Clojure's success thus far?
Hickey: I agree with your theory. I think Paul Graham's essays were hugely influential, and got people interested in Lisp, a Lisp-like way of thinking about programming, and the importance of rejecting conventional wisdom. And Python and Ruby—and PHP and Javascript—have helped herald a renaissance of language diversity, as people were obviously succeeding with languages other than Java/C#/C++. All of this paved the way for Clojure.
It's interesting, because Clojure provides almost nothing you can't find somewhere else. But I do think it occupies an otherwise empty spot in the multidimensional space of language features and capabilities. If it hadn't, I wouldn't have written it. That's the spot I wanted to work in, and enough other people must want to be there too.
Fogus: You've personally done a lot to set the tone in the Clojure community. How much does a language's community contribute to its success?
Hickey: I think it is a huge component. I am so happy with, and proud of, the Clojure community. People are helpful, and respectful, and positive. I think the key point is that the community values itself, such that people will decide it is more important to preserve the quality of the community than to vent their emotions or prove themselves right.
Fogus: Can you talk briefly about the Lisp-related projects leading up to the creation of Clojure? Specifically, what were the goals of dotLisp, Foil, and Lisplets?
Hickey: dotLisp was the inevitable rite of passage write-a-Lisp-interpreter thing. The only thing interesting about it was that, like Clojure, it was designed to be hosted and provide convenient access to the host, the CLR in this case.
Jfli was next, an attempt to provide access to Java by embedding a JVM inside a Common Lisp process. This worked okay, but still had a dissatisfying us-and-them feel.
Foil was essentially the same concept, but out of process. It used the same sexpr wire protocol to support both Java and CLR interop. Still us-and-them, and slower than same process, but theoretically less intrusive.
Lisplets was even more decoupled, merely translating Java servlet requests and responses to sexprs so you could write your servlets in Lisp.
In the end, none of these really let you sneak Lisp into a more traditional shop, nor did they provide satisfyingly fast access to the abundant Java libs from Lisp.
포거스: 클로저를 만들 때 이러한 실험을 통해 어떤 교훈을 얻었나요?
히키: 기존 OO에 액세스하기 위한 만족스러운 Lispy 구문을 만들 수 있었다는 점입니다. 호스트와 GC 등을 공유하면서 같은 편에 서고 싶다는 생각이 들었습니다. FFI의 '외국' 부분은 사라져야 합니다.
포거스: 클로저는 한때 JVM과 CLR에서 동시에 개발되었는데, 결국 전자를 집중하기로 결정한 이유는 무엇인가요?
히키: 모든 일을 두 번 하는 것에 지쳤고, 대신 두 배로 더 많은 일을 하고 싶었습니다.
Fogus: 영향력의 부정적인 측면에 대한 이전 언급을 다시 생각해보면, Ivan Bratko의 <인공지능을 위한 프롤로그 프로그래밍>을 책꽂이에 넣은 것도 이런 이유 때문인지 궁금해집니다. 프롤로그가 선언적이라는 일반적인 견해가 과장된 것이라고 다른 곳에서 언급하셨는데, 프롤로그가 클로저에 부정적인 영향을 미쳤다고 봐도 될까요?
히키: 과장되었다고 말하지 않았습니다. 컷/실패와 절 순서 의존성 때문에 생각보다 선언적이지 않다고 말한 것입니다. 반면에 클로저는 우리 대부분이 항상 사용하는 것보다 훨씬 더 선언적이며, 더 선언적인 접근 방식을 향한 영감의 역할을 합니다. Clojure의 초기 개발 단계에서 저는 Lisp 기반 프롤로그를 사용하여 프로토타입 술어 디스패치 시스템을 구축했습니다. Clojure의 일부가 되지는 못했지만, 저는 여전히 술어 디스패치뿐만 아니라 Clojure의 타입 시스템 대신 논리 시스템을 사용하는 데 관심이 있습니다. 아직은 다소 미흡하지만 확실히 긍정적인 영향을 미치고 있습니다.
Fogus: What lessons did you take away from those experiments when creating Clojure?
Hickey: That it was possible to create a satisfying Lispy syntax for accessing traditional OO stuff. That you really want to be on the same side of the fence, sharing GC, etc. with the host. The 'foreign' part of FFI has to go.
Fogus: Clojure was once in parallel development on both the JVM and the CLR, why did you eventually decide to focus in on the former?
Hickey: I got tired of doing everything twice, and wanted instead to do twice as much.
Fogus: Referring back to your previous comment regarding the negative aspect of influences, I'm led to wonder if the inclusion of Prolog Programming for Artificial Intelligence by Ivan Bratko to your Bookshelf was of this variety. You've mentioned elsewhere that the common view of Prolog as declarative is overblown—can I assume that Prolog negatively influenced Clojure?
Hickey: I didn't say overblown. I said it is less declarative than it might be, what with cut/fail and clause order dependence. On the other hand, it is much more declarative than what most of us are doing all the time, and serves as inspiration towards a more declarative approach. During the early development of Clojure, I built a prototype predicate dispatch system for it using a Lisp-based Prolog. It never became part of Clojure, but I am still interested in predicate dispatch, as well as using logic systems in place of a type system for Clojure. Definitely a positive influence, if somewhat under-delivered upon, as of yet.
# 클로저가 데이터 캡슐화를 사용하지 않는 이유
포거스: 저는 클로저 데이터로그 구현을 연구해봤는데 많이 노출되지 않아서 안타깝습니다. 그 '논리 시스템'의 기초로서 이 기술이나 파생 기술을 사용할 수 있는 곳이 있다고 생각하시나요?
히키: 네, 물론이죠. 저는 데이터로그를 매우 좋아합니다.
포거스: 프로그래머가 실수하거나 잘못된 코드를 작성하는 것을 방지하기 위해 프로그래밍 언어는 어느 정도까지 설계되어야 할까요?
히키: 언어마다 이에 대한 접근 방식이 다를 수 있기 때문에 "그래야 한다"고 말하기는 꺼려집니다. 저는 개인적으로 사람들이 잘못된 일을 하는 것을 막기보다는 올바른 일을 할 수 있도록 하는 데 초점을 맞추고 있습니다. 결국 사람들이 실수하거나 잘못된 코드를 작성하는 것을 막을 수 있는 것은 아무것도 없습니다.
포거스: 이러한 생각에 따라 일부 사람들은 클로저가 타입에 데이터를 숨기는 캡슐화를 사용하지 않는다는 사실에 놀라워합니다. 데이터 숨김을 포기하기로 결정한 이유는 무엇인가요?
히키: 분명히 말씀드리자면 Clojure는 추상화를 위한 프로그래밍을 강조합니다. 하지만 언젠가는 누군가는 데이터에 액세스할 수 있어야 합니다. 그리고 "비공개"라는 개념이 있다면 그에 상응하는 권한과 신뢰 개념이 필요합니다. 그러면 복잡성은 엄청나게 증가하고 가치는 거의 없어지며, 시스템에 경직성이 생기고, 종종 사물이 있어서는 안 될 곳에 존재하게 됩니다. 이는 단순한 정보를 클래스에 넣을 때 발생하는 다른 손실에 추가됩니다. 데이터가 불변인 경우, 누군가 변경될 수 있는 정보에 의존하게 될 수 있다는 점을 제외하면 액세스 권한을 제공한다고 해서 발생할 수 있는 피해는 거의 없습니다. 사람들은 실생활에서 항상 그렇게 하고, 상황이 바뀌면 적응합니다. 그리고 이성적인 사람이라면 변화할 수 있는 무언가에 기반하여 결정을 내릴 때 미래에 적응해야 할 수도 있다는 것을 알고 있습니다. 따라서 위험 관리 결정은 프로그래머가 자유롭게 내릴 수 있어야 한다고 생각합니다.
사람들이 추상적인 프로그래밍을 원하고 구현 세부 사항과 결혼하는 것을 경계하는 감성이 없다면 좋은 프로그래머가 될 수 없습니다.
포거스: 감성과 언어 철학의 경계는 어디까지라고 할 수 있을까요? 즉, 프로그래머는 언어에 의해 강제되는 것이 아니라 불변성의 관습을 따라야 한다고 간단히 말할 수 있다는 점에서 불변성에 대해서도 마찬가지일까요?
히키: 불변성 규칙을 적용해 본 사람이라면 누구나 알 수 있듯이 불변성 규칙 같은 것은 존재하지 않습니다. 데이터 구조가 불변 API만 제공한다면 그것이 가장 중요합니다. 혼합 API를 제공하는 경우, 이는 불변성이 아닙니다.
적용은 직교적입니다. 많은 최적화가 적용될 수 있기 때문에 적용에 가치가 없다는 말은 아닙니다. 하지만 순도를 강제할 수 있는 공짜 점심 같은 시스템은 복잡합니다.
Fogus: I have studied the Clojure Datalog implementation and am saddened that it does not get a lot of exposure. Do you think that there is a place for it, or some derivative, as the basis for that "logic system"?
Hickey: Yes, definitely. I like Datalog a lot.
Fogus: To what extent should a programming language be designed to prevent programmers from making mistakes or writing bad code?
Hickey: I'm reluctant to say "should", as different languages can rightly take different approaches to this. I know my personal focus is on enabling people to do the right thing rather than preventing them from doing the wrong thing. In the end, there is nothing that will prevent people from making mistakes or writing bad code.
Fogus: Following that idea—some people are surprised by the fact that Clojure does not engage in data-hiding encapsulation on its types. Why did you decide to forgo data-hiding?
Hickey: Let's be clear that Clojure strongly emphasizes programming to abstractions. At some point though, someone is going to need to have access to the data. And if you have a notion of "private", you need corresponding notions of privilege and trust. And that adds a whole ton of complexity and little value, creates rigidity in a system, and often forces things to live in places they shouldn't. This is in addition to the other losing that occurs when simple information is put into classes. To the extent the data is immutable, there is little harm that can come of providing access, other than that someone could come to depend upon something that might change. Well, okay, people do that all the time in real life, and when things change, they adapt. And if they are rational, they know when they make a decision based upon something that can change that they might in the future need to adapt. So, it's a risk management decision, one I think programmers should be free to make.
If people don't have the sensibilities to desire to program to abstractions and to be wary of marrying implementation details, then they are never going to be good programmers.
Fogus: Where can we draw the line between sensibilities and language philosophy? That is, could the same be said for immutability in that we could simply say that programmers should follow a convention of immutability instead of it being enforced by the language?
Hickey: There's no such thing as a convention of immutability, as anyone who has tried to enforce one can attest. If a data structure offers only an immutable API, that is what's most important. If it offers a mixed API, it's simply not immutable.
Enforcement is orthogonal. That's not to say there isn't value in enforcement, as many optimizations can come into play. But there's no free lunch—type systems that can enforce purity are complex.
# 클로저는 리스프인가?
포거스: 클로저가 "진짜 리스프"가 아니라고 주장하는 사람들에게 뭐라고 말씀하시겠어요?
히키: 그런 사람들에게 시간을 보내기에는 인생은 너무 짧습니다. 많은 리스프 전문가들이 클로저를 리스프로 인정하고 있습니다. 모든 사람이 자신이 좋아하는 Lisp보다 Clojure를 선호할 것이라고는 생각하지 않습니다. 어떤 면에서 다르지 않다면 존재할 이유가 거의 없을 테니까요.
포거스: Lisp-1 대 Lisp-2와 같은 명백한 언어 선택 외에 Clojure는 Common Lisp 및 Scheme과 어떻게 다르며 어떤 점에서 개선되기를 바라나요?
히키: 가장 중요한 두 가지 변화는 핵심 라이브러리가 구체적인 데이터 유형이 아닌 추상화(예: 컨셀이 아닌 시퀀스 및 연관 추상화)로 구현된다는 점과 핵심 데이터 구조가 변경 불가능하고 영구적이라는 점입니다.
포거스: Clojure를 사용하면 기존 상점에 Lisp를 몰래 숨겨 넣을 수 있다고 말씀하신 것을 다시 한 번 언급하자면, 이 점에서 Clojure는 다른 JVM 기반 Lisp와 어떻게 다른가요?
히키: 크게 다르지 않습니다. 거의 모든 JVM 언어를 비슷하게 몰래 넣을 수 있습니다.
포거스: 클로저의 인기에 놀랐다고 하셨는데, 다른 한편으로는 첫 번째 버전을 만들기 위해 다른 수입이 거의 없거나 전혀 없는 상태에서 인생의 몇 년을 걸지 않았나요?
히키: 저는 저에게 주어진 안식년 기간 동안 이 일을 시작했습니다. 일로부터의 휴식이 아니라 완전히 자유로운 사람으로서 일로부터의 휴식이었죠. 다른 사람의 시선이나 수익에 대한 동기를 고려하지 않고 제가 옳다고 생각하는 것을 할 수 있도록 휴가를 주었습니다. 저는 새로운 언어를 출시하면서 10명에서 100명 정도의 사람들이 사용할 것이라는 일반적인 기대감을 가졌습니다. 어쩌면 도움을 받거나 코드 기여를 할 수도 있겠죠.
그런데 이 프로젝트가 시작되면서 제가 계획했던 안식년보다 훨씬 더 많은 시간이 필요하게 되었습니다. 그래서 저는 제가 투자한 일부를 회수하려고 노력하고 있습니다. 금전적인 동기로 시작한 일이었다면 클로저는 존재하지 않았겠지만, 투자한 것을 후회하지는 않아요.
포거스: 클로저를 소개하는 일련의 동영상을 공개하여 이 언어에 대해 큰 화제를 불러일으켰습니다. 제 생각에는 특히 신생 언어에 대한 훌륭한 마케팅 전략이라고 생각합니다. 의도적으로 마케팅 자료로 이러한 동영상을 제작한 건가요, 아니면 단순히 정보를 제공하려는 목적의 부수적인 효과였나요?
히키: jfli 및 Foil 메일링 리스트의 극소수 회원에게 Clojure의 존재를 알리는 첫 번째 이메일을 보낸 것 외에는 의도적으로 마케팅을 한 적이 없습니다.
저는 많은 초청 강연을 해왔고, 이 동영상은 그 강연 중 일부를 녹화한 것입니다. 강연에 쏟은 노력을 활용할 수 있는 현명한 방법인 것 같았어요. 한 번에 50~100명의 청중과 대화하는 것보다 이런 동영상이 훨씬 더 효율적이라는 것을 증명하는 것이죠.
Fogus: What would you say to people who claim that Clojure is not a "real Lisp"?
Hickey: Life is too short to spend time on such people. Plenty of Lisp experts have recognized Clojure as a Lisp. I don't expect everyone to prefer Clojure over their favorite Lisp. If it wasn't different in some ways, there'd be little reason for it to exist.
Fogus: Aside from an obvious language choice like Lisp-1 vs. Lisp-2, how does Clojure differ from and hope to improve on Common Lisp and Scheme?
Hickey: The two most significant changes are: the core library is implemented in terms of abstractions, not concrete data types, e.g. sequence and associative abstractions rather than cons cells, and the core data structures are immutable and persistent.
Fogus: Referring back to your previous statement about Clojure allowing Lisp to be sneaked into traditional shops—how does Clojure differ in this respect from other JVM-based Lisps?
Hickey: Not much. You can sneak in almost any JVM language similarly.
Fogus: You've said you've been surprised by how popular Clojure has become, but on the other hand didn't you bet a couple years of your life with little or no other income to produce the first version?
Hickey: I started it while on a sabbatical I had given myself. Not a break from work, but a break to work, as a completely free person. I gave myself leave to do whatever I thought was right, with no regard for what others might think, nor any motivation to profit. In releasing it, I had the normal expectations for a new language—that ten to a hundred people might use it. Maybe I would get some help or code contributions.
It has taken off, and subsequently demanded far more time than the sabbatical I planned. So, I'm trying to recoup some of the investment I've made. Had it been a financially motivated undertaking, I'm sure Clojure would not exist, but I don't regret having invested in it.
Fogus: You released a series of videos introducing Clojure that generated serious buzz around the language. In my opinion they are a brilliant marketing strategy, especially for a young language. Were you intentionally creating those videos as marketing material, or was that simply a side effect of a purely informational pursuit?
Hickey: I've never intentionally marketed Clojure, other than the first email announcing its existence to the very few members of the jfli and Foil mailing lists.
I've given many invited talks, and the videos are recordings of some of those talks. It just seemed like a sensible way to leverage the effort that went into doing the talks. I was quite surprised by the audience they received, but it proves that videos like that are much more efficient than talking to fifty to a hundred people at a time.
포거스: 논문을 읽을 정도로만 하스켈을 알고 있는 사람으로서 클로저는 하스켈의 영향을 상당히 많이 받은 것 같습니다. 가져가기, 놓기, 반복하기, 반복하기 등 핵심 함수의 이름과 작동 방식부터 프로토콜 기능까지, 하스켈 프로그래머라면 알아볼 수 있는 많은 부분이 Clojure에 있습니다. 하스켈이 클로저에 미친 긍정적인 영향과 부정적인 영향에 대해 자세히 설명해 주시겠어요?
히키: 하스켈은 경외심을 불러일으키는 환상적인 언어라고 생각합니다. 화를 내며 사용한 적은 없지만 분명 긍정적인 영향을 미쳤습니다. 하스켈은 함수형 프로그래밍의 이상을 추구한다는 점에서 클로저보다 훨씬 더 나아간 것이 분명합니다. 특히 유형을 사용하여 사물을 강제하는 접근 방식이 다릅니다.
어떤 면에서 클로저는 정적 강제성 없이 함수형 프로그래밍의 이점을 얼마나 많이 구현할 수 있는지 알아보기 위한 실험이라고 할 수 있습니다. 물론 클로저는 불변 데이터와 순수 함수를 기본값으로 제공하고 사용자가 이를 사용하도록 선택하는 것만으로도 많은 이점을 얻을 수 있다는 것을 보여줍니다. 마치 인도를 걷도록 강제하는 가드레일이 없어도 인도를 걸을 수 있는 것과 같은 이점을 얻을 수 있는 것과 마찬가지입니다.
실제 사용에서 유형 시스템의 가장 큰 과제는 복잡성을 증가시키지 않으면서도 더 많은 표현력을 확보하는 것이라고 생각합니다. 저는 아직 그런 것을 보지 못했기 때문에 프로그래밍의 복잡성을 줄이려는 제 바람과 맞지 않습니다.
프로토콜에 관한 한, 프로토콜은 일반적인 OO에서처럼 함수와 데이터를 결합하는 것보다 함수와 데이터를 분리하는 것이 더 유연하고 확장성이 뛰어나다는 것을 보여주는 Haskell의 타입 클래스뿐만 아니라 Common Lisp의 일반 함수와도 비슷합니다.
포거스: 프로토콜이 CLOS의 영향을 받는 것은 분명합니다. 하지만 CLOS를 사용하면 복잡한 클래스 계층 구조를 구축할 수 있는 반면, 클로저의 유형과 프로토콜은 그렇지 않습니다. 클래스 계층 구조와 관련된 문제와 프로토콜이 이를 해결하는 방법에 대해 말씀해 주시겠어요?
히키: 상속과 계층 구조를 논리적 함축의 한 형태로 생각하는 한 가지 방법은 X가 Y라면 Y에 참인 모든 것은 X에도 참이라는 것입니다. 문제는 계층 구조에 무언가를 붙일 때 발생합니다. Y가 인터페이스에 불과하다면 충돌이나 모순 없이 X가 이를 만족하도록 만드는 것이 비교적 쉽습니다. Y가 행동 및/또는 데이터라면 상황이 빠르게 위험해집니다. 충돌과 모순이 발생할 가능성이 더 커지며, 일반적으로 상속을 부분적으로 재정의하는 방법도 있으므로, ISA 함축을 검증할 수 있습니다. 함축이 깨지고 사물에 대한 추론 능력이 진흙탕으로 변합니다. 물론 상속 기반 설계의 유형 침입 문제도 있습니다.
프로토콜과 데이터 유형은 일반적으로 구현 상속을 피하고 상호 운용을 위한 인터페이스 상속만 지원합니다. 프로토콜은 상속 없이 데이터타입을 프로토콜에 직접 연결하는 것을 지원합니다. 그리고 프로토콜은 직접 구현 구성을 지원하는데, 제 생각에는 이러한 목적에서는 상속보다 훨씬 더 바람직합니다. 프로토콜을 인터페이스로 확장하여 구현 상속을 얻을 수도 있지만, 이는 인터옵 목적상 필요한 타협/악수이므로 신중하게 사용해야 합니다.
Fogus: 프로토콜과 데이터 유형은 부트스트랩된 클로저의 기초를 제공하는데, 클로저에서 클로저를 구현하는 것이 얼마나 중요한가요?
히키: 데이터 구조와 알고리즘을 구현할 수 있는 충분한 기능을 갖추기 위해서는 클로저로 클로저를 구현하는 것이 중요합니다. 저희는 새로운 데이터 구조를 이 방식으로 구현하고 있으며, 잘 작동하고 있습니다. 과거로 돌아가서 다시 작업할 때 가장 중요한 부분은 Clojure 컴파일러라고 생각합니다. 현재 자바가 너무 많아서 유지 관리하기가 재미없습니다. 또한 도구에 대한 더 나은 지원을 제공하기 위해 이 컴파일러에서 다르게 하고 싶은 몇 가지 사항이 있습니다. 그 다음으로 중요한 것은 추상화를 인터페이스에서 프로토콜로 옮기는 것입니다. 마지막으로 전체 부트스트랩을 사용하면 포트를 더 쉽게 만들 수 있습니다.
포거스: 대상 호스트가 다르면 당연히 Clojure 기능의 다른 하위 집합을 지원할 것입니다. 포트를 어떻게 통합할 계획인가요?
히키: 없습니다. 대규모 프로그램을 한 호스트에서 다른 호스트로 포팅하는 것은 Clojure의 목표가 아니었고 앞으로도 그럴 것입니다. 이는 시간 낭비일 뿐 아니라 거의 아무도 필요로 하지 않습니다. 현재는 호스트를 변경할 때 Java에서 C# 또는 Javascript로 언어를 변경해야 하는 경우가 많습니다. 완전한 이식성 계층은 부족하지만 이보다는 낫습니다. 이 아이디어의 핵심은 Clojure와 핵심 라이브러리, 그리고 현재 사용 중인 호스트에 대한 지식을 가지고 무언가를 해낼 수 있다는 것입니다. 물론 Clojure의 코어와 같은 비IO 라이브러리는 호스트 간에 이동할 수 있습니다. JVM과 CLR은 대략적인 기능 동등성이 있습니다. 자바스크립트 호스트가 얼마나 제한적인지는 좀 더 지켜봐야 할 것입니다.
Fogus: As someone who only knows Haskell enough to read the papers, Clojure appears to be influenced by it substantially. From the names and operation of core functions—take, drop, iterate, repeat, etc.—to its protocols facility, there is a lot in Clojure that a Haskell programmer would recognize. Can you elaborate on Haskell's influences on Clojure both positive and negative?
Hickey: I think Haskell is a fantastic, awe-inspiring piece of work. I haven't used it in anger, but it certainly was a positive influence. Haskell obviously goes much further than Clojure in pursuing the ideals of functional programming. In particular they differ in the approach to using types to enforce things.
In some ways, Clojure is an experiment to see how many of the benefits of functional programming can be delivered without static enforcement. Certainly Clojure shows that you can get many benefits of using immutable data and pure functions merely by supplying them as defaults and choosing to use them, much in the same way you can get the benefits of walking on the sidewalk without there being guard rails forcing you to stay on the sidewalk.
I think the great challenge for type systems in practical use is getting them to be more expressive without a corresponding—or worse—increase in complexity. I have yet to see that, so they are not aligned with my desire to reduce complexity in programming.
As far as protocols go, they are as much akin to Common Lisp's generic functions as to Haskell's type classes, both of which demonstrate it is more flexible and extensible to keep functions and data separate, than to combine them as in typical OO.
Fogus: It's clear that protocols are influenced by CLOS. However, while CLOS allows you to build complex class hierarchies, Clojure's types and protocols do not. Can you comment on the problems associated with class hierarchies and how protocols address them?
Hickey: One way to think about inheritance and hierarchy is as a form of logical implication—if X is a Y, then all the things that are true of Y's are true of X's. The problems come about when you attach something to the hierarchy. If Y is just an interface, then it's relatively easy to make X satisfy it without conflict or contradiction. If Y is behavior and/or data, then things get dangerous quickly. There's more potential for conflict and contradiction, and, usually, there's also a method for partial overriding of the inheritance and thus, qualification of the isa implication. The implication is broken and your ability to reason about things turns to mud. And then of course there are the type-intrusion problems of inheritance-based designs.
Protocols and datatypes generally eschew implementation inheritance, and support interface inheritance for interop only. Protocols support direct connections of datatypes to protocols, without any inheritance. And protocols support direct implementation composition, which, in my opinion, is far preferable to inheritance for that purpose. You can still get implementation inheritance by extending protocols to interfaces, but that is a necessary compromise/evil for interop purposes, and should be used with care.
Fogus: Protocols and datatypes provide the basis for a bootstrapped Clojure—how important is it to implement Clojure in Clojure?
Hickey: It is important to be able to implement Clojure in Clojure, in order to make sure it has sufficient facilities to implement its data structures and algorithms. We are implementing any new data structures this way, and it is working out well. As far as going back and redoing things, I think the most important bit is the Clojure compiler. It currently is a lot of Java, and no fun to maintain. In addition, there are several things I'd like to do differently with it in order to provide better support for tools. Next most important would be to move the abstractions from interfaces to protocols. Finally, a full bootstrap would make ports easier.
Fogus: Different target hosts would naturally support different subsets of Clojure's functionality. How do you plan to unify the ports?
Hickey: I don't. It has not been, and will not be, the objective of Clojure to allow porting of large programs from one host to another. That is simply a waste of time, and needed by almost no one. Currently, you often have to change languages when you change hosts—from Java to C# or Javascript. This is better than that, while short of some full portability layer. The idea is to be able to take one's knowledge of Clojure and its core libraries, and of the host du jour, and get something done. Certainly, non-IO libraries, like Clojure's core, can move between hosts. The JVM and CLR have rough capability parity. We'll have to see how restrictive a Javascript host might be.
포거스: 클로저 인 클로저 프로세스의 일부로 "클로저 커널"을 공식적으로 정의하시겠습니까?
히키: 아닐 것 같습니다. 아마도 몇 개의 포트가 존재한 후에 공통점에 라벨을 붙일 수 있겠지만, 호스트 몇 개를 확보하기 전에 그런 공식화를 시도하는 것은 어리석은 일인 것 같습니다.
Fogus: 가장 좋아하는 도구는 무엇인가요? 에디터? 버전 관리? 디버거? 드로잉 툴? IDE?
히키: 서커스 조랑말 노트, 옴니그래프, 해먹. [참고 1]
포거스: 테스트 중심 개발에 반대하는 것으로 알려져 있습니다. 이에 대한 입장을 자세히 설명해 주시겠어요?
히키: 네: 저는 TDD를 '반대'한다고 말한 적이 없습니다. 제가 말씀드린 것은 인생은 짧고 하루에 주어진 시간은 한정되어 있다는 것입니다. 따라서 우리는 시간을 어떻게 쓸지 선택해야 합니다. 테스트를 작성하는 데 시간을 소비한다면 그 시간은 다른 일을 할 수 없는 시간입니다. 우리 각자는 양과 질 모두에서 결과를 극대화하기 위해 시간을 가장 잘 보내는 방법을 평가해야 합니다. 만약 사람들이 테스트 작성에 시간의 50%를 투자하는 것이 결과를 극대화한다고 생각한다면, 그럴 수도 있습니다. 하지만 제 경우에는 그렇지 않습니다. 저는 그 시간을 문제에 대해 생각하는 데 쓰고 싶습니다. 제 경우에는 다른 어떤 시간 사용보다 결함이 적고 더 나은 솔루션을 만들어내는 데 더 많은 시간을 할애할 수 있습니다. 완벽한 테스트 스위트를 갖춘 나쁜 디자인도 여전히 나쁜 디자인입니다.
포거스: 클로저는 에펠의 계약 프로그래밍의 하위 집합을 제공하는 사전 및 사후 조건 검사를 통해 함수 제약 조건을 제공합니다. 제약 조건이 단위 테스트의 필요성을 없애거나 보완하나요?
Fogus: Will you formally define a "Clojure Kernel" as part of the Clojure-in-Clojure process?
Hickey: I doubt it. Perhaps after a few ports exist we can put a label on the commonality, but trying to do such formalization prior to getting a few hosts under your belt seems folly.
Fogus: Favorite tools? Editor? Version control? Debugger? Drawing tool? IDE?
Hickey: Circus Ponies NoteBook, OmniGraffle, hammock. [Note 1]
Fogus: You have been known to speak out against test-driven development. Do you mind elaborating on your position?
Hickey: I never spoke out 'against' TDD. What I have said is, life is short and there are only a finite number of hours in a day. So, we have to make choices about how we spend our time. If we spend it writing tests, that is time we are not spending doing something else. Each of us needs to assess how best to spend our time in order to maximize our results, both in quantity and quality. If people think that spending fifty percent of their time writing tests maximizes their results—okay for them. I'm sure that's not true for me—I'd rather spend that time thinking about my problem. I'm certain that, for me, this produces better solutions, with fewer defects, than any other use of my time. A bad design with a complete test suite is still a bad design.
Fogus: Clojure provides function constraints via pre- and post-condition checks that provide a subset of Eiffel's contracts programming. Do constraints eliminate the need for, or complement unit testing?
히키: 단위 테스트를 보완합니다. 코드가 작성되는 시점에 코드의 의도를 문서화하고, 선택적으로 프로그램의 컨텍스트에서 실행할 수 있는 등 여러 가지 좋은 속성이 있습니다.
포거스: 클로저에 기능을 포함하기로 한 결정은 구현 및 내재된 복잡성과 직교하는 것 같습니다. 예를 들어 스트림은 통합 직전까지 갔다가 완전히 버려진 것 같았습니다. 마찬가지로 범위는 비교적 이해하고 구현하기가 간단하지만 마찬가지로 삭제되었거나 최소한 크게 지연된 것 같습니다. 특히 이 두 가지를 포기한 이유는 무엇이며, 일반적으로 Clojure에 새로운 기능을 추가할 때 궁극적인 기준은 무엇인가요?
히키: 기본 입장은 기능을 추가하지 않는 것입니다. 복잡성은 중요합니다.
특히 스트림은 API에서 제가 불편해하는 몇 가지 어려운 점을 노출했습니다. 이제 동기 부여가 되는 아이디어 중 일부는 좀 더 전체적인 의미가 있는 포드로 옮겨졌습니다. 포드, 트랜지언트, 레퍼런스 등 다양한 기능이 상호 작용하기 때문에 어느 하나만 따로 떼어놓고 볼 수 없습니다. 범위는 구현하기 쉬워 보이지만, 스레드 풀 스레드에 대한 변수 및 바인딩과 동일한 제한이 있는 방식으로만 구현할 수 있습니다. 저는 바인딩을 개선하는 방법에 대한 아이디어를 가지고 있으며, 그 작업은 스코프를 제공하기 전에 선행되어야 할 수도 있습니다. 범위는 여전히 테이블 위에 있습니다.
새로운 기능이 실제로 필요하고 제가 만족할 만한 디자인이 되었으면 좋겠어요. 탐색 작업과 생각할 시간이 필요한 과정입니다. 더 나은 아이디어를 생각해낼 권리는 저에게 있으며, 때로는 기다리면서 시간을 할애하기도 합니다. 저는 주로 기능을 연구하는 것이 아니라 기능을 통해 해결할 수 있는 문제를 연구한다고 생각하고 있습니다. 범위는 기능이지만 리소스 관리는 문제이고, 스트림과 포드는 기능이지만 프로세스는 문제입니다. 문제를 해결하면서 기능에 대한 아이디어를 개발하기도 하고 때로는 포기하기도 합니다.
포거스: 전직 동료 몇 명과 이야기를 나눠봤는데, 문제 해결과 디버깅의 달인이라고 하더군요. 디버깅은 어떻게 하나요?
히키: 저는 과학적인 방법을 사용합니다. 사용 가능한 정보를 바탕으로 상황을 분석하고 더 많은 사실을 수집합니다. 알려진 사실에 맞는 무엇이 잘못되었는지에 대한 가설을 세웁니다. 가설을 테스트할 수 있는 가장 작은 것을 찾습니다. 그렇게 해 보세요. 가능하면 고립된 재현 사례를 구축하는 것이 좋습니다. 작은 테스트를 통해 가설이 확인된 경우에만 더 큰 응용 프로그램에서 해당 문제를 찾아보세요. 그렇지 않다면 더 많은 또는 더 나은 사실을 확보하고 다른 아이디어를 생각해냅니다. 더 큰 맥락에서 문제를 해결하려고 시도하거나, 디버거에서 실행하거나, 효과를 보기 위해 무언가를 변경하는 등의 시도는 피하려고 노력합니다.
이상적으로는 컴퓨터를 만지기 전에 사실에 맞는 가설을 세웠기 때문에 문제를 해결했다는 것을 알 수 있습니다.
포거스: 명령형/OO 코드 디버깅과 클로저 코드 디버깅 사이에 근본적인 차이점이 있나요?
히키: 근본적인 차이는 없지만 함수형 코드를 디버깅하는 것이 더 나은 로컬리티 덕분에 훨씬 쉽습니다.
Fogus: Clojure의 스레드 동시성 스토리는 다양한 사용 시나리오를 제공하는 다양한 종류의 참조 유형으로 매우 견고합니다. 현재 Clojure가 제공하는 동시성 기능에 만족하시나요, 아니면 현재 참조 모델을 확장하거나 분산 동시성 분야로 진출할 계획이 있으신가요?
히키: 시간이 지남에 따라 저는 동시성 그 자체보다는 상태/아이덴티티/가치/시간/프로세스에 더 가깝다고 생각하게 되었습니다. 물론 동시 진행 프로그램에서는 매우 중요합니다. 적어도 하나 이상의 참조 유형을 추가할 여지가 있다고 생각합니다. 일시적인 프로세스를 통해 하나의 값이 다른 값에서 생성되는 경우, 해당 프로세스의 범위 및/또는 여러 참여자를 허용하는 구조를 가질 수 있습니다. 이것은 사람들이 잠금을 사용하여 임시로 하는 일이며, 다른 것들과 마찬가지로 이를 자동화하고 명시적이고 안전하게 만들어주는 참조형 구조인 포드로 감쌀 수 있습니다.
저는 분산 동시성을 언어의 문제로 보지 않습니다. 또한, 대부분의 애플리케이션은 직접 연결된 분산 객체로 잘 제공되지 않으며, 대신 일종의 메시지 큐를 사용하는 것이 더 낫다고 생각합니다.
Hickey: They complement unit tests. They have a number of nice properties—they document the intent of the code at the point it is written, and can optionally run in the context of the program.
Fogus: It seems that your decision to include features in Clojure is orthogonal to their implementation and inherent complexities. For example, it seemed that streams were right on the cusp of being integrated but were discarded outright. Likewise, scopes are relatively simple to comprehend and implement, but likewise seem to have been dropped, or at least delayed greatly. What are the reasons that you stepped away from these two in particular, and in general, what is your ultimate criteria for adding new features to Clojure?
Hickey: The default position is to not add features. Complexity does matter.
Streams, in particular, exposed some difficult things in the API with which I wasn't comfortable. Now some of the motivating ideas have moved into pods, where they make more holistic sense. Various features interact, e.g. pods, transients, and references, so you can't look at any one in isolation. Scopes may seem easy to implement, but only in ways that suffer the same limitations as vars and binding vis-à-vis thread-pool threads. I have ideas about how to do that and binding better, and that work may have to precede delivering scopes. Scopes are still on the table.
I'd like for any new features to be actually needed and have designs I feel good about. It is a process that requires exploratory work, and time to think. I reserve the right to come up with a better idea, and sometimes I am just allocating time to do that by waiting. I like to think I don't primarily work on features—I work on problems that features help solve. Scopes are a feature but resource management is a problem; streams and pods are features but process is a problem. As you work on problems, you develop—and sometimes abandon—ideas for features.
Fogus: I've spoken with a few of your former co-workers, and they described you as a trouble-shooting and debugging master. How do you debug?
Hickey: I guess I use the scientific method. Analyze the situation given the available information, possibly gathering more facts. Formulate a hypothesis about what is wrong that fits the known facts. Find the smallest possible thing that could test the hypothesis. Try that. Often this will involve constructing an isolated reproducing case, if possible. If and only if the hypothesis is confirmed by the small test, look for that problem in the bigger application. If not, get more or better facts and come up with a different idea. I try to avoid attempting to solve the problem in the larger context, running in the debugger, just changing things to see effects, etc.
Ideally, you know you have solved the problem before you touch the computer, because you have a hypothesis that uniquely fits the facts.
Fogus: Is there a fundamental difference between debugging imperative/OO code versus Clojure code?
Hickey: There is no fundamental difference, but debugging functional code is much easier because of the better locality.
Fogus: Clojure's threaded concurrency story is very solid with numerous flavors of reference types providing different usage scenarios. Do you feel satisfied with Clojure's current concurrency offerings, or do you have plans to expand on the current reference model, or perhaps venture into distributed concurrency?
Hickey: Over time I've come to see this as more of a state/identity/value/time/process thing rather than concurrency in and of itself. Obviously it matters greatly for concurrent programs. I think there is room for at least one more reference type. To the extent one value is produced from another via a transient process, you could have a construct that allowed that process to have extent and/or multiple participants. This is the kind of thing people do on an ad hoc basis with locks, and could be wrapped in a reference-like construct, pods, that would, like the others, automate it, and make it explicit and safe.
I don't see distributed concurrency as a language thing. In addition, I don't think most applications are well served with directly connected distributed objects, but would be better off with some sort of message queues instead.
# 화이트헤드와의 연결점
포거스: 병렬 처리를 지원하는 프리미티브도 있지만, 클로저는 확장할 수 있는 여지가 많습니다. 포크 조인이나 데이터 흐름과 같은 더 높은 수준의 병렬 라이브러리를 포함할 계획이 있으신가요?
히키: 예, 기존 데이터 구조에서 포크 조인 기반의 병렬 맵/축소/필터 등을 지원할 계획이 있으며 일부 구현 작업도 진행 중입니다.
포거스: 고수준 언어는 최적화하기가 더 어렵나요?
Hickey: 저도 잘 모르겠습니다. 다만 가상화, 적응형 런타임, 동적 컴파일 등을 더 많이 사용함에 따라 이러한 런타임에서 모든 언어에 대한 결정론적 성능 모델을 얻는 것이 점점 더 어려워지고 있다는 것 정도는 알고 있습니다. 이는 아마도 수동 최적화를 통해 얻을 수 있는 것보다 더 나은 성능을 얻기 위한 절충안일 것입니다.
포거스: 클로저의 상태, 시간, 정체성 개념을 설명할 때 알프레드 노스 화이트헤드의 철학, 특히 그의 저서인 '과정과 실재'와 '과학과 현대 세계'를 인용하셨어요. 프로그래머로서 우리는 화이트헤드와 철학 전반에서 무엇을 배울 수 있을까요? 소프트웨어 개발자 교육에 철학이 들어갈 자리가 있나요?
히키: 저는 화이트헤드의 철학이나 형이상학을 지지하는 사람이 아니며, 모든 것을 이해한다고 주장할 수도 없습니다. 저는 JVM 언어 서밋의 기조 연설을 준비하면서 Clojure 작업에서 언어와 무관한 핵심 아이디어를 찾기 위해 노력했습니다. 대학에서 공부했던 화이트헤드가 생각나서 그의 책 몇 권을 펼쳐들었습니다. 놀랍게도 화이트헤드는 제 강연 시간, 프로세스, 불변성 등의 주제를 다루고 있었습니다. 화이트헤드는 꽤 인용할 만한 인물이라서 저는 그를 강연의 '영웅'으로 삼았습니다. 하지만 화이트헤드가 클로저에 영감을 준 것은 아니었고, 어떤 연결고리도 사후에 우연히 발견한 것이었습니다. 그렇긴 하지만 연결의 수는 놀라웠습니다.
객체 시스템과 같은 단순화된 세계 모델을 프로그래밍 구조로 만드는 한도에서는 세상에 대한 폭넓은 이해가 프로그래머에게 도움이 될 수 있다고 생각합니다.
[주 1] 히키는 앞서 언급한 코드를 입력하는 것보다 문제에 대해 생각하는 데 더 많은 시간을 할애하는 자신의 성향을 "해먹 중심 개발"이라고 불렀습니다.
Fogus: While there are also primitives supporting parallelism, Clojure's story here has a lot of room for expansion. Do you plan to include higher-level parallel libraries such as those for fork-join or dataflow?
Hickey: Yes, there are plans, and some implementation work, to support fork-join–based parallel map/reduce/filter etc. on the existing data structures.
Fogus: Are high-level languages harder to optimize?
Hickey: I have no idea. What I do know is that, as we get to more virtualization, adaptive runtimes, dynamic compilation, etc., it is becoming more difficult to obtain a deterministic performance model for all languages on such runtimes. This is presumably a trade-off to get better performance than we could obtain through manual optimization.
Fogus: You've cited the philosophy of Alfred North Whitehead—in particular his works Process and Reality and Science and the Modern World—in explaining Clojure's notion of state, time, and identity. What can we, as programmers, learn from Whitehead specifically and philosophy in general? Is there a place for philosophy in the education of software developers?
Hickey: I am not a proponent of the philosophy or metaphysics of Whitehead, and could hardly claim to understand it all. I was putting together a keynote for the JVM language summit and striving to find language-independent core ideas in the Clojure work. I was reminded of some Whitehead I had studied in college, so opened up a few of his books. Sure enough, he was all over some of the themes of my talk—time, process, immutability, etc. He is quite quotable, so I made him the 'hero' of the talk. But Whitehead was not an inspiration for Clojure—any connections were a serendipitous discovery after the fact. That said, the number of connections was startling.
To the extent we create simplified models of the world, like object systems, as programming constructs, yes, I guess any broader understanding of the world could benefit programmers.
[Note 1] Hickey has dubbed his previously mentioned tendency to spend more time thinking about problems than typing in code "Hammock-Driven Development".
Copyright (C) 2011. All rights reserved.
Postscript:
This interview was available at:
until some time in 2017 when it appears that the site www.codequarterly.com was discontinued. As of 2018-Mar-23 it was still available on the Internet Archive Wayback Machine at this location:
This interview was linked to and discussed somewhat on news.ycombinator.com here: