LISP을 다시 살펴보는 이유

복잡한 언어와 복잡해지는 언어

요즘 필자를 사로잡고 있는 테마는 LISP이다. 거의 사용되지 않는 것을 알면서도 호기심 때문에 어쩔 수가 없었다. LISP은 예전에 AI의 언어로 유명했던 언어로 컴퓨터 학계와 업계에서 중요한 언어였다. 표현력도 좋고 메모리는 많이 사용하지만 처리속도도 그다지 느리다고 할 수 없는 괜찮은 언어였는데 90년대 이후로 갑자기 점유율이 줄어들었다(업그레이드는 뛰어난 회사와 개발자들에 의해 계속 이루어지고 있다.). LISP의 사용자가 줄어들었다기보다는 언어의 사용자층이 다른 언어들에서 급증한 것이 그 이유다. 자바나 C++와 비교하면 사용자층은 분명히 상대적으로 떨어진 것이다.

폴 그레이엄의 해커와 화가 LISP은 2000년도 이후 사용자층이 조금 늘어났다. 외국에서는 LISP 붐이 잠시 일어난 적도 있었던 것이다. Peter Siebel의 Practical Common LISP 같은 책이 아마존에서 컴퓨터 서적 판매의 베스트셀러가 되기도 했다. 책의 반응으로 보아 분명히 사람들은 LISP에 관심이 있었다. 영향력도 있고 글도 잘 쓰는 해커인 폴 그레이엄(Paul Graham:paulgraham.com) 이나 구글의 피터 노빅(Peter Norvig:norvig.com) 같은 사람들이 LISP의 중요성을 강조했기 때문이기도 하다. 호기심이 있고 컴퓨터의 표현력(expression)에 대해 관심이 있는 사람들의 관심을 끌게 된 것이다. 그래서 나름대로 호기심을 갖는 사람들의 머릿속이 LISP의 서식지라고 말할 수 있다.

그런데 표현력은 곰곰이 생각해보면 중요한 요소다. 프로그래밍에서 어떤 일에 대한 추상적인 생각을 코드로 옮기는 언어고유의 표현능력은 대단히 중요하다. 폴 그레이엄과 노빅은 표현능력에서 LISP의 표현능력이 훨씬 더 강하다고 주장한다. 그렇다면 속는 셈치고 해 볼 만하지 않은가?

초기에는 스티븐 레비의 <해커>에 나오는 제 1 세대 해커들이 LISP의 주인공들이었다. 이들이 중요한 구현자, 사용자, 연구자를 모두 겸하던 시절이 있었고 미국의 AI의 초기연구들은 LISP에서 출발했다. 그래서 많은 아이디어와 도구들이 LISP을 바탕으로 출발하기는 했으나 LISP으로 돌아오지는 않았다. LISP은 알고리즘을 세련된 모습으로 표현하는 데에는 성공적이었으나 사실은 프로그래밍을 배우기가 어려웠다. 실제의 업무에 사용하는 프로그램은 좀 더 간단하고 단순할 필요가 있었다.

1960년을 전후하여 프로그래밍의 3가지 중요한 원형이 등장했다. 하나는 최초의 고급언어인 FORTRAN으로 그 후에 나온 BASIC은 비슷한 원형을 사용했다. 요즘은 특별한 용도를 제외하고는 사용하지 않는다. 그 다음에 나온 원형이 LISP이었다. LISP은 List Processing을 의미한다. 다른 원형이 C.A.R. Hoare의 Algol-60 이었다. C와 Pascal, Java와 C++는 Algol의 표현을 따랐다. 요즘은 Algol의 계열이 주류이고, LISP계열의 언어가 몇 개 존재하며 나머지를 새로운 형태의 언어를 포함한 언어들이 채우고 있다.

Algol 계열의 언어가 주류가 된 것은 구조적 프로그래밍을 지원하고 80년대 말부터 빠르게 OOP의 옷을 입으면서 시류에 적응했기 때문이다. 실제로 프로그래밍 언어라는 것은 업계에서 인정해야 주류가 될 수 있고 업계는 적당한 시간과 난이도로 사람들이 훈련받을 수 있다는 것을 납득해야 한다. 그래서 개발인력을 확보할 수 있어야만 산업계는 일정한 일을 할 수 있다. C++가 초기의 회의적인 시각을 극복하고 주류에 편승할 수 있었던 것은 사람들을 가르치는 방법을 극복했기 때문이라고 볼 수 있다. 구조적 프로그래밍도 추상화에는 한계가 있었지만 가르치기는 어렵지 않았다. 이것은 중요한 사실이라고 생각한다. 언어를 배울 수 있어야 프로그래밍을 할 수 있다. 그리고 너무 어렵지 않은 일들은 간단한 프로그래밍언어로도 쉽게 해치울 수 있다. 문제가 발생하는 것은 나중에 복잡한 일들을 처리하면서 일어난다.

어떤 산업계이건 가르치고 배우는 먹이사슬은 항상 존재한다. 출판사나 교육기관 대학교 같은 곳은 언제나 수요가 많은 것을 가르친다. 필요한 것을 가르친다고 볼 수 있고 필요한 것을 배운다고 볼 수 있다. 사람들이 주류가 아닌 것을 배워서 고생을 자처하겠다고 나서지는 않을 것이기 때문이다. 그래서 유망해 보이는 언어들이 많이 있음에도 불구하고 언제나 이들은 대기자 명단에 올라가 있다. 산업계에서 필요하거나 필요하다고 인정받는 리스트는 잘 변하지 않는다.

SICP의LISP 은 그런 면에서는 실패했다고 볼 수 있다. 언어 자체가 너무 어렵고 방대했다. 초기에 갖고 있던 커다란 자원도 도움이 되지 않았다. 방대했던 LISP을 깔끔하게 고쳐놓은 교육용 언어 Scheme 의 사용자도 많지 않았다. 이 언어를 이용하여 교육에 적용했던 MIT의 SICP(Structure and Interpretation of Computer Programs - 얼마 후 번역본이 나온다고 한다.) 과정은 컴퓨터 교육에 새로운 이정표를 만들어 처음의 몇 년 동안 대단히 성공적이었다. 책은 정말 잘 만들어진 교재였으나 역시 어려웠다. 그래서 입문과정으로 SICP를 선택하는 다른 학교들의 교과과정은 점차 그 수가 줄어들었다(어쩌면 저자들인 MIT의 인공지능 연구소 출신 해커들의 이상이 너무 높았는지도 모른다. 그러나 분명히 대단한 책이며 고전이다.). 그래서 좀 더 현실적인 과정인 HTDP(How to Design Programs)로 이행하는 사람들도 생겨났다. 책의 박력은 SICP보다 덜했으나 입문서로서는 적당한 수준인 것만은 분명했다. 다른 LISP 책들과 과정들이 있었으나 오랜 시간을 투여해도 코딩을 하지 못하는 사람들이 상당수 있었다고 한다. 대부분의 사람들은 괄호와 Recusion으로 만들어진 언어를 그렇게 좋아하지 않았다.

문제는 어려워 보이는 것을 사람들이 좋아하지는 않는다는 것이었다. 수식과 기호를 몇 개 늘어놓으면 사람들은 싫어하는 경향이 있다. 그런데 LISP은 프로그램 그 자체가 식(expression)이다. 장점이기도하고 단점이기도 했다. 깔끔한 람다함수 표현식을 사용한 스킴도 좋아하지 않았다.

그 대신 사람들이 선택한 것은 어셈블러를 깔끔하게 옮겨 놓은 것 같은 C와 같은 언어였다. 프로그램 수준이 증가하면 표현력이 크게 증가할 것이라든가 생산성이 증가할지도 모른다와 같은 애매한 말들은 통하지 않았다. 인공지능의 연구에 사용될 정도로 복잡한 것을 표현할 수 있다는 설득도 먹혀들지 않았다. 플로우차트로 만들어진 알고리즘을 코드로 옮기는 데는 표현력이 그다지 중요하지 않다.

컴퓨터 박스안의 세계와 박스 밖의 세계

그 러나 정말로 프로그램이 복잡해지면 표현의 능력에는 한계가 있다. 복잡한 상황을 간단하게 만드는 방법은 없으나 간단하게 표현하는 방법은 있을지 모른다. 복잡한 것을 간단하게 요약하는 추상화나 계층으로 요약하는 계층화를 가능하게 하는 방법론들이 나와 있고 객체지향의 방법도 그 중의 하나다. 분명히 방법론중의 하나라는 것을 잘 알지만 추상화와 계층은 객체지향의 방법론으로 처리하고 있다. 객체는 상속도 가능하다. 그래서 객체지향이 나쁜 방법도 아니다.

컴퓨터가 적다면 객체지향이건 객체지향이 아니건 중요한 일이 아닐 수도 있다. 그러나 컴퓨터가 세상을 덮고 있는 세상에서는 그렇지가 않다. 어쩌면 현실보다 현실을 시뮬레이트하는 컴퓨터의 세계가 더 복잡해진 것이다. 기호의 세계가 현실을 뒤덮는다. 이상한 형태이긴 하지만 매트릭스 영화에서 이미 그 전조가 보였다. 그 이전부터 보였던 것인지도 모른다. 철학자 보들리야르가 말하던 “시뮬라크와 시뮬라시옹”라는 개념이 영화 매트릭스에 들어가 있다(실제로 제작자 워쇼스키 형제는 배우들에게 이 책을 읽으라고 주문했다.). 책에는 아주 정밀한 지도가 나온다. 국경(실제의 지형에는 없다)과 온갖 자잘한 정보가 지도안에 들어가고 결국 지도는 실제의 땅보다 중요해진다. 기호의 왕국이 탄생하는 것인데 점차 속도가 빨라지고 강력해지는 컴퓨터가 기호를 저장하고 보여준다. 기호의 처리도 한다. 속도가 미덕이기도 하지만 아무리 빨라진다고 복잡한 것을 줄여주는 마술을 부려주지는 않는다. 그런데 너무 복잡해지면 간단하게 만들어야 한다.

어느 날 선택한 객체지향의 컴퓨터 세계에서 세상은 객체들로 구성되어 있음에 틀림없다. 세상은 객체이다. 분명히 프로그램들이 추상화하는 것이 객체이기 때문이다. 세상을 컴퓨터들이 뒤덮고 있으며 객체지향이 절대적이니 세상은 객체임에 틀림없다. 만약 순수한 객체로도 안 되는 일이 있다면 프로그래머들의 코딩방법을 객체에 맞추어주는 ‘패턴’도 있다. 패턴이 나올 정도가 되면 객체지향의 방법론도 이미 쉬운 것이 아니다. 하지만 세상은 이미 객체지향으로 진행되었기 때문에 프로그래머들은 기꺼이 패턴에 대해 공부한다. 객체지향을 비난하지도 않는다. 그동안 투자한 것이 너무나 많기 때문이다.

별다른 문제가 없다면 세상은 컴퓨터 박스안의 객체에 의해 표현되고 돌아갈 것이다. ‘시뮬라시옹’에서 지도가 영토를 대신하는 것처럼. 객체지향의 전성기가 다하는 그날까지 세상은 객체의 구현이다. 객체지향에 대한 책들은 계속 나올 것이며, 객체지향을 세련된 모습으로 표현하는 방법론도 계속 나올 것이다.

어 떤 객체는 다른 객체를 상속받아 만들어진 다형성의 모습을 띠며 이 객체는 다른 객체와 이러저러한 방법으로 통신하는 방법을 갖게 될 것이고 이 방법에 문제가 있다면 예외의 규정을 통하여 처리한다. 실제의 세계와 가상의 세계는 다르지만 가상세계의 비트가 이미 세상을 지배하고 있다. 문제는 이 비트를 지배하는 방법이 복잡해지기 시작한다는 것이다.

세월이 지나면서 객체가 실제와 가상세계를 잘 반영하지 못하자 20년 가까이 지난 다른 프로토콜을 끄집어내기 시작했다. 요즘 유행하기 시작하는 aspect-oriented programming (AOP)와 aspect-oriented software development(AOSD)같은 것들이 OOP를 보완하기 위해 등장했다. AOP에서 키워드는 ‘관심의 분리(Separation of Concerns)’이다. 프로시저나 모듈은 서로 인터페이스가 교차하는 관심 영역에서는 분리되어야 했다. AOP는 기존의 OOP를 적용한다고 해도 분리하기 어려운 문제의 해결책을 들고 나왔다. 관심의 교차가 만나는 영역을 언어수준에서 지원하고 정의한다. 문제는 간단하게 풀릴 수도 있지만 사람들의 머릿속은 복잡해진다. AOP가 나오자 AOP에 대해 반대하는 중요 개발자들도 나왔다. 그러나 AOP를 지원하는 AspectJ와 같은 도구들은 이미 발표가 되어있고 IBM은 AOP를 처음부터 지원했다. AOP뿐만 아니라 이름도 잘 모르는 개발 철학의 미들웨어나 개발 프레임워크는 산더미처럼 쌓여있다(이런 추세를 다 따라가야 한다고 생각하면 너무 진지한 것인지도 모른다. 사실 추상화 방법의 하나인 객체에 너무 많은 것을 요구하고 있는 것인지도 모르고 설계가 너무 복잡한 것인지도 모르며 문제가 되는 코드를 부분적으로 손으로 쓰는 것과 큰 차이가 없을지도 모른다. 아니면 프로그래머들의 디버깅 공포증이 너무 심해진 것일지도 모른다.).

당연히 프로그래밍에 대한 요구는 많아질 것이다. 아직은 아니지만 만약 AOP가 대세가 되면 프로그래머들은 또 AOP같이 보이는 프로그램을 짜야할 것이다. 이런 일이 언제까지 계속될지는 아무도 모르며 OOP가 어디까지 복잡해질 지는 아무도 모른다. 마찬가지로 이들을 구현하는 언어도 복잡해져 간다. 그렇다고 연구하는 사람들이 이런 문제를 모르고 있었는가 하면 그것도 아니다. Metaobject 프로그래밍이 발표된 지는 이미 오래전이다(AOP의 Gregor Kiczales는 1991년 출판된 The Art of the Metaobject Protocol 의 저자이기도 하며 LISP의 OOP는 이 책을 기초로 만들어진 것이다. CLOS 라고 하는 LISP의 OOP는 상당히 유연하고 AOP로 이행하는데 어려움이 없었다.). 언젠가는 모듈들이 많은 접합점을 만들고 실제의 기계나 물건처럼 움직여야 할 것이라는 것도 예전부터 알고 있었다. 이들에 대한 코드를 자동적이건 반자동적인건 만들어 내야 한다는 것도 어렴풋이 알고 있었다. 명확히 글과 그림으로 옮기기에는 조금 경험의 곡선이 부족했을 뿐이다. 더 복잡한 ‘시뮬라시옹과 시뮬라크르’를 만드는 조물주게임은 컴퓨터 박스 안에서 계속될 것이 틀림없다.

그런데 OOP의 원점으로 돌아가서 살펴보면 OOP의 출발은 복잡한 것이 아니었다. 어쩌다보니 세상만큼이나 복잡해졌다. OOP의 시작인 smalltalk 나 simula의 이상은 조용한 것이었다.

이 토록 복잡한 객체들이 만들어내는 세상은 더 복잡해질지도 모른다. 객체가 복잡해지고 객체들을 다루는 방법론도 더 복잡해지는 것은 사실이다(그리고 복잡성을 다스리기 위한 방법론 그 자체도 복잡성을 다스리기 위해 만들어진 접근법들이다. 메타방법론의 메타다).

이 렇게 복잡하게 돌아갈 줄 미리 알았더라면 LISP 이나 다른 도구들을 채택하지 말라는 법도 없었겠지만 지도는 이미 예전에 그려졌다. 개발 언어와 환경을 공급하는 기존의 대기업체 가운데 주도권을 놓으려는 팀은 어디에도 없다. 사실 복잡한 것을 다스리는 좋은 방법으로는 PROLOG도 있었다. PROLOG는 선언형(declarative form) 추론 엔진을 사용하여 rule-base의 프로그래밍을 한다. 프롤로그가 더 발전되어 있었다면 프로그램 라인 중에 “어느 곳에서는 관심(Concern)이 있어야 한다.”라고 선언을 하면 프로그램은 그렇게 움직일 지도 모를 일이다.

논리 프로그래밍의 우아한 표기방법임에도 불구하고 PROLOG를 배우기는 쉽지 않았다. 1970년대 말과 1980년대 유럽과 제5세대 컴퓨터를 표방하던 일본의 개발자들은 1990년대 초에 개발을 멈추고 야심찼던 프로젝트는 커다란 성과가 없이 끝났다. 개발자들이 멍청했던 것도 아니지만 이 좋은 방법론도 소수의 사용자를 갖는 연구용 언어로 조용히 남아있게 된 것이다. 관련이 있던 많은 AI 프로젝트들도 동면상태로 들어갔다.

그러나 어느 날 오늘날의 패러다임에 싫증이 나면 LISP처럼 움직이는 제어모듈(그때는 객체가 리스트 사이를 바쁘게 누비고 다닐지 모른다. Paul Graham은 Java나 다른 언어에서 표현력을 높이는 유일한 방법이 LISP의 평가기(evaluator)를 구현하는 것이라고 주장을 할 정도니까.)이나 Prolog의 추론엔진을 탑재하는 제어모듈을 Java로 구현하는 일이 유행할지도 모른다.

결국

과거나 지금이나 나름대로 복잡한 문제를 풀어야 한다는 과제는 변함이 없다. 문제는 복잡한 문제를 정의하고 푸는 비용이 어느 정도인가가 문제다. 도구의 문제이기도 하다. 언어나 라이브러리는 때로 도구의 수준을 넘어 신념과 종교와 같을 때가 있다고 하는데 아마 사실일 것이다. 접근론이나 개발의 방법론도 달라질 수밖에 없다. 그렇다면 다른 세상이다. 개발에 있어서 기존의 툴을 더 개량하는 방법도 있을 것이고(이것은 새로 나오는 방법론에 관심을 갖고 살펴보는 것으로) 독자적이고 새로운 방법을 찾아보는 방법도 있을 것이며(자신이 필요한 분야에서 온갖 방법을 동원하여 찾아보는 것) 과거에 나온 방법론의 유전자를 재활용하는 방법도 있다. 때로는 그 방법이 자신에게 더 맞는 것이라든가 그 예전의 방법론에서 사용가능한 유전자를 발견할 수도 있다. 과거에는 메모리나 성능의 제한 때문에 사장되거나 실용성을 잃어버린 구현들도 꽤 많다. 당시에는 컴퓨터가 할 수 있는 것에 대해 낙관론이 지배하던 시대였다. 70년대의 로직 프로그래밍의 수준이 그렇게 유치했던 것도 아니다.

만약 너무 진지해보이지 않는다면 취미삼아서라도 과거의 기술적인 유전자들을 살펴 볼 필요가 있다. 노래나 옷들도 복고풍으로 되살아 나기도한다. 한때 폭발적인 에너지를 갖고 탄생한 문화 속에서 존재할 만한 이유가 있던 감성의 디자인들이 요즘의 재료와 터치로 재탄생한다. 비슷한 이유로 자신에게 맞는 존재 이유를 갖는 디자인 철학들과 맞닥뜨릴 수도 있을지도 모른다. 과거에 만들어진 중요한 문화유전자들을 쉽게 버릴 이유는 없다. 꼼꼼히 살펴볼 필요가 있는 것이다.@

    저작권자 ⓒ ZDNet Korea 무단전재-재배포 금지