Ruby Creator Y. Matsumoto

루비의 창시자인 Matsumoto가 컴퓨터 분야에서 일하기 원하는 사람에게 제안한 10가지 팁이 있다.

한 가지 이상의 언어를 배우고, 좋은 책을 많이 보고, 코드를 많이 읽으라는 조언은 당연해 보이지만 그만큼 꾸준히 실천하기 어려운 것도 없는 것 같다.

어쨌거나 좀 더 능동적으로 의문을 가지고 탐구하며, 또 즐겨야겠다.

  • Learn more than one programming languages, preferably many different style ones, like scripting, object-oriented, functional, logic, etc. Learning languages teaches you many about programming.

  • Read good books, for example, “Pragmatic Programmers”, “Refactoring”, and “Art of Computer Science”.

  • Read the source code. The source code is the source of information and knowledge. Thanks to the opensource.

  • Don’t focus too much on tools. Tools changes. Algorithms and basic fundamentals don’t.

  • Don’t focus too much on machines. Programmers often fall in the computer’s view point. But human make programs, programs serve human. Don’t forget that programming is a human oriented activity.

  • Be lazy. Machines should serve human being. Often programmers serve machines unconsciously. Let machines serve you. Do everything you can to make you lazy.

  • Test early, test often. Write test suites before you code, if possible.

  • Be nice to others. Consider interface first, man to man, man to machine, and machine to machine. Again, remember, human factor is important.

  • Be creative.

  • Enjoy programming and life. I believe that is one of the purposes of life.

Continuation을 지원하는 언어 Ruby

정확한 정의는 아니지만, continuation 프로그램 수행 도중의 한 시점을 저장하고 나중에 이 시점으로 다시 돌아올 수 있음을 의미한다. glibc의 setcontext나 Scheme 언어의 call/cc 등이 이런 범주에 들어간다.

최신 언어에는 python만이 stackless python의 영향으로 continuation 개념을 도입한 줄 알았는데 더 찾아보니 Ruby 역시 continuation을 class로 제공하고 있었다.

ruby의 continuation 오브젝트는 Kernel#callcc 를 호출하면 생성되고 이 오브젝트는 return address와 수행 환경(execution state)를 저장하고 있기 때문에 프로그램 수행 도중 callcc block으로 다시 돌아올 수 있다.

continuation이 중요한 의미를 가지는 이유는 coroutine, generator, user level thread 등을 구현할 수 있는 building block이기 때문이다. continuation은 종종 goto with arguments로 표현하기도 하고, 기존의 복잡한 loop construct를 이론상 모두 대체할 수 있다.

RubyFromPython을 읽어보면 ruby의 continuation을 이용해 python의 simple generator를 구현하는 예를 볼 수 있다. 일단 효율적인 측면을 제쳐두면 coroutine이나 user level thread도 continuation 만으로 구현이 가능하다.

문제는 continuation 오브젝트를 만드는데 비용이 어느정도 들며, 이걸 extensive하게 활용했을 때 어떤 문제가 있냐는거다. ruby 메일링 리스트에 callcc가 어떤 점에서 유용하느냐는 질문이 올라온 적이 있는데 사람들은 seaside 프로젝트를 예로 들고 있다. 웹의 새로운 프레임웍을 제공한다는데, 그 근간을 보면 웹페이지를 처리함에 있어 그때 그때 상태를 continuation으로 저장해두면 사용자가 back page를 누르거나 했을 때 그때 당시의 state를 그대로 복원하여 transaction을 처리할 수 있다는 의미로 보인다.

continuation이 프로그래밍에 있어서 새로운 패러다임을 가져올 수 있는 요소임은 분명해 보이나 보다 구체적인 사용 예와 그 비용을 알아봐야겠다.

Method는 default로 non-virtual이어야 하나?

일단 상업적으로 가장 활발히 이용되고 있는 Java와 C#의 예를 들어보자. Java에서 instance method는 final로 선언되지 않은 이상 모두 virtual이다. 반대로 C#에서는 virtual로 선언하지 않는 이상 모두 non-virtual method이다.

Java의 후발주자격인 C#이 모든 instance method는 default로 non-virtual이 되게 한 데에는 몇 가지 이유가 있다. C# 개발자 주 아키텍터(lead architect)인 Anders Hejlsberg는 다음과 같은 이유를 들었다.

첫 번째 이유는 성능(performance) 때문이다. virtual method는 해당 instance의 runtime type을 check 후에 virtual method table을 참고해서 해당 method를 dispatch 한 후에 호출하므로 non-virtual method보다 overhead가 크다. 일반적인 Java 프로그래머들은 virtual일 필요가 없는 method를 선언할 때 final을 빼먹는 경우가 많은데, 이 때문에 Java로 작성된 대부분의 프로그램은 method invocation의 overhead가 필요 없이 커지는 경향이 있다. 물론 virtual method를 inlining하는 algorithm도 나와 있으나 모든 경우를 해결하긴 힘들다.

또 다른 이유는 API를 공개할 때 생기는 여파의 차이다. non-virtual method의 경우 해당 method가 어떤 일을 하며 어떤 값을 return하는지 정도만 기술해주면 충분하다. 그러나 virtual method의 경우 API 사용자에 의해 override 될 수 있고 override 된 method가 base class의 method 내에서도 쓰이게 된다. 대부분의 virtual method가 해당 플랫폼이나 API의 hook으로 동작하게 되는데(Template Method가 대표적인 예제) 이 경우 API 작성자는 해당 API가 어떤 경우에 호출되며 base class 안에서 어떤 일을 하는지 또 어떤 invariant를 가져야 하는지 자세하게 명시해야 한다. API 사용자가 이를 제대로 파악하지 못했다면 해당 class는 제대로 동작하지 않을 가능성이 크다.

그리고 virtual method를 default로 선택한 Java의 경우 versioning과 관련된 문제로 새로운 base class를 release하면서 새로운 method를 추가했는데 derived class를 쓰던 사람이 우연히 같은 signature의 method를 정의해서 쓰고 있었다면 이는 원래 의도와 다르게 virtual method가 되면서 override된다. C#의 경우 이런 경우를 막기 위해 virtual method는 반드시 virtual이라 명시하고, derived class에서 이를 override하면 override라는 keyword를 명시해주도록 하고 있다.

Java의 경우 C#의 override와 같은 keyword가 없기 때문에 derived class에서 overriding method를 mis-typing하여도 이를 알아낼 방법이 없다. Java는 새로운 method를 추가되었다고 생각할 뿐이기 때문이다. 또한 base class에서 method name을 바꿀 때도 override란 keyword를 사용한 derived class는 곧바로 compile error가 나겠지만 그렇지 않은 경우 systematic하게 이를 알아낼 방법도 존재하지 않는다.

프로그래밍 언어 그루비(Groovy) 특징

주말을 이용해 그루비 언어 가이드(Groovy – Language Guide)를 읽고 그루비의 특징들을 한 번 정리해보았다.

일단 그루비는 파이썬, 루비, 펄과 같은 스크립트 언어의 편리함은 기존의 자바 개발자들에게 제공하는 것이 제1의 목표인듯 하다. 따라서 전체적으로 파이썬이나 루비와 비슷한 느낌을 주되 자바 프로그래머가 직관적으로 사용할 수 있게 설계하였다.

그 예로 그루비는 List나 Map을 언어 차원에서 제공하지만, 이는 궁극적으로 java.util.List와 java.util.Map이 매핑(mapping) 된다. 또 closure를 비롯한 여러 language construct들도 다양한 문법적 편의(syntatic sugar)를 제공하지만 궁극적으로 자바 클래스의 메쏘드를 호출해 주는 경우가 많다. Basic Type들도 Java Primitive Type과 java.math.BigDecimal 등에 매핑되어 있는 구조다.

내부적으로 그루비의 클래스 하나가 바이트코드 상에서 자바 클래스와 1:1로 대응하기 때문에 자바는 그루비 코드를 임베딩(embedding) 할 수 있고, 그루비에서 자바 클래스를 자유롭게 이용할 수 있다.

언어는 다르지만 자바와 그루비 모두 궁극적으로 바이트코드로 변환되어 수행되기 때문에, 랭귀지 런타임 자체는 차이가 없는 셈이다. 결국 자바 대신 그루비를 택한다면 이는 스크립트 언어가 제공하는 독특한 편의성 때문일텐데, 이를 정리해 보면 다음과 같다.

클래스 없는 Plain Scripts의 지원

자바처럼 최소 하나 이상의 클래스(class)가 존재해서 public static void main(String[] args) method가 엔트리 포인트(entry point)가 되는 것이 아니라 스크립트를 읽어 차례대로 statements를 수행할 수 있다. 또 클래스에 속하지 않은 first-order function을 def 문을 이용해 파이썬과 비슷한 형태로 만들 수 있다. (물론 바이트코드로 번역될 때 내부적으로 Class를 생성한다)

클로저(Closure)의 지원

Functional Language의 패러다임(paradigm)인 closure는 function을 argument처럼 넘겨주고 받을 수 있다는 점 때문에 imperative/oo language에서도 유용성이 있다.

[1,2,3,4].each { println(it) }

위 예는 리스트를 iteration해서 결과를 보여주는데 무척 유용하다.

Lists, Ranges, Maps 등의 native 지원

보다 복잡한 데이타 구조(data structure)를 지원하는 것은 스크립트 언어의 미덕인 된 듯하다. 파이썬의 예에서 이미 어느정도 검증되었듯이, 속도에 대한 고려가 크게 없다면 Lists나 Maps 등을 언어 차원에서 지원하는 것은 빠른 프로토타이핑에 매우 유용하다.

Slicing with Subscript Operator

각종 데이타 구조에서 필요한 elements를 쉽게 뽑아내는 방법인 slicing도 어느정도 범용성을 인정받는듯 하다. 마이너스 인덱스(minus index)를 이용해서 뒤에서부터 slicing을 하거나, reverse slicing을 이용해 문자열을 거꾸로 뽑아낸다던지 하는 것도 가능한데, 문자열(string)처리가 주인 스크립트 언어의 특징에 부합하는 부분이다.

정규 표현식(Regular Expression)의 지원

펄(Perl)이 스크립트 언어로서 강력함을 발휘할 수 있었던 이유는 정규 표현식(regular expression)을 언어 차원에서 지원함으로써, 문자열(string)을 다루는 간단한 프로그램들을 매우 빨리 짤 수 있었다는 점일 것이다.

Dynamic Typing

자바는 Static Typing에 기반한 언어이나 그루비는 스크립트 언어의 특성상 Dynamic Typing을 허용한다. return type이나 argument type을 생략할 경우 이는 java.lang.Object에 매핑하도록 만들어놨다.

의견

아직 스크립트 언어에 익숙치 않아서 각각의 언어 요소가 생산성이나 효율에 어느정도 영향을 미치는지 가늠하기가 힘들다. 위의 요소들은 최근에 널리 사용되는 스크립트 언어들에서 어느정도 그 유용성을 인정받고 있는것 만큼은 분명한 것 같고 이에 그루비는 이런 요소들을 포함시켰을 것이다. 각각의 요소가 어떤 영향을 미치는지는 좀 더 깊이 생각해 봐야겠다.

Polyphonic C#

자바가 처음 발표될 때 랭귀지에 멀티 쓰레드 프로그래밍을 인테그레이션(integration) 한 점을 강점으로 꼽았으나 synchonirzed과 wait만으로는 많은 프로그래밍 실수를 유발할 수 있음이 널리 알려지게 되었고, Java5에서 뒤늦게 java.util.concurrent package를 추가하며 결국 원래 모델인 멀티 쓰레드 관련 라이브러리 제공으로 회귀하게 되었다.

Polyphonic C#은 이러한 한계점을 극복하기 위한 시도로 시작 되었다.

Polyphonic C#은 Microsoft의 C# 언어를 바탕으로 컴파일러에 concurrency 지원을 추가한 실험적인 언어이다. 비슷한 목적에서 출발한 또 다른 실험 언어인 joint-calculus를 바탕으로 concurrency를 추상화(abstraction)해서 프로그램 개발자가 별도로 쓰레드 라이브러리를 사용할 필요없이 동기화(synchronization)을 비롯한 멀티쓰레드 프로그래밍(multi-threaded programming)을 컴파일러가 대신해주는 프레임웍이다.

개인적으로 이런 스타일의 리서치가 무척 좋다. 프로그래머에게 짐(burden)을 넘기지 않고, 컴팔일러가 최적화 할 수 있는 부분은 최대한 컴파일러가 끌고 들어오는 편이 맞다고 생각하고, concurrency 역시 어느정도 이 영역에 속한다고 본다. 컴퓨터 내부의 CPU와 아키텍처, 메모리 모델을 충분히 고려한 concurrnecy는 사람이 아니라 컴파일러의 몫이고 이를 자동화 할 수 있다면 기존 프로그램에서 자주 발견되는 데드락 실수 등을 현저히 줄일 수 있을 것이다. 이것을 가능하게 하기 위해서 concurrency 자체를 추상화할 수 있는 방법이 필요한데, polyphonic C#은 그 기초를 제공한다.

개인적으로 계속 지켜볼 주제다.

이 프로젝트는 지금 Microsoft Research Cambridge U.K.의 컴파일러인 Cw 프로젝트로 흡수되어 진행되고 있다.

통합적인 연구

20세기 학문의 발달은 특히 과학 분야를 중심으로 매우 환원주의적인 방법론을 고수했다. 본래 하나의 분야로 간주되었던 물리학, 화학, 생물학 등이 내부적으로 무수한 갈래로 뻗어나갔고 세계적인 학자라해도 자기 분야가 아닌 이상 옆동네 얘기도 외계인의 언어처럼 들리는 세분화 된 학문 세상에 살게 되었다.

이러한 경향은 비단 자연 과학에만 국한되지 않고 엔지니어링 쪽에서도 마찬가지 인듯 하다. 우리학교 컴퓨터 공학과 대학원 랩만 해도 크게 시스템 소프트웨어, 소프트웨어 엔지니어링, 데이타베이스, 네트웍, 고성능컴퓨팅연구 그리고 인공 지능을 다루는 일련의 랩들(기계 번역이나 자연어 처리, 미디어 프로세싱) 등으로 세분화 되어있다. 그리고 한 분야를 본격적으로 다루기 시작한 대학원생들은 다른 분야의 지식이 거의 전무한 것 또한 사실이다.

대부분의 도메인에서 쉽게 풀 수 있는 문제들은 이미 대부분 정리되고, 매우 수학적이고 복잡한 접근을 요구하는 이른바 곁다리 문제들만 남은 현실에서 자기 분야 문제 하나를 풀기위해서만 엄청난 시간이 필요한 것은 사실이다. 그러나 말그대로 곁다리 문제이기 때문에 그걸 풀어낸다고 해서 인간 생활에 그다지 큰 변화가 오는 것도 아닌 것 같다.

결국 학자로서 인류 생활에 크게 이바지할 수 있는 방법은 완전히 새로운 학문 영역(domain)을 만들어 내거나, 기존의 영역들의 경계점에 속해서 어느 쪽으로부터 관심을 받지 못했던 교차점을 발견해 내는 두 가지 방법이 있을 것 같다. 완전히 새로운 학문 분야의 발견은 그 특성상 신의 선물로 생각할 수 밖에 없을테니, 가장 현실적이고 효과적인 방법은 여러 학문을 통합하여 새로운 영역을 개척하는 것일테다.

문제는 이런 스타일의 연구를 뒷받침하기 위한 지원이나 노력이 거의 없다는 점이다. 대학에서 복수 전공을 한다고 해도 학사 일정이 서로 겹치고 빠듯하여 결국 한 쪽도 제대로 못하는 양쪽 학문 모두에서 절름발이가 되기 쉽상이다. 또 최소 한국 현실의 대학원에서 특별히 다른 분야의 랩과 공동 연구를 하거나 하는 경우가 무척 드문것 또한 사실이다.

생명과 컴퓨터, 경제와 심리처럼 완전히 별개로 보이는 학문간의 결합이 아니라, 컴파일러, 프로그래밍 랭귀지, 시스템 소프트웨어 그리고 소프트웨어 엔지니어링 등이 가미되어 생산성 있고 획기적인 프로그래밍 수행 환경과 툴셋을 만드는 연구 등도 분화된 현재의 학문 세상에서는 틀림 없는 학제간 연구다. 어쨌건 이런 현실을 탓하기보단 나름대로의 현실 인식을 바탕으로 최대한 많은 분야에 두루 관심을 두고 필요할 때 깊이 파고드는 능력이 중요할 것 같다.

Sun이 API 잘라내기(subsetting)을 반대하는 이유

Sun의 Java Platform Team의 Fellow인 Graham Hamilton와의 인터뷰에서 Java Technology의 가장 큰 위협이 무엇이냐는 질문을 던졌다.

Hamilton은 호환성(compatibility)가 깨지는 것을 가장 큰 위협으로 꼽았다. 각 벤더(vendor)들이 좀 더 빠른 제품 출시나 자신들만의 특수한 요구 사항으로 인해 다른 벤더와의 호환성을 깨뜨리거나 API의 일부만 잘라내서 사용할 경우 단기적으로는 제품 판매에 있어서 이익을 볼 수 있으나 이는 자바의 가장 큰 장점인 Portability를 잃게 만든다는 것이다.

Q. One final question. What is the biggest risk that you see facing the Java language today?

A. I think one of the key core values of the Java platform is compatibility. We aren’t always perfect, but we do go to great lengths to try to make programs portable across different J2SE systems or across different J2EE app servers. I wouldn’t go so far as to say compatibility is “at risk” but I think this is something we will always have to watch very closely.
“I suspect that the Java language will be good for another 20 to 30 years if we are careful in managing its evolution.”

There is always a temptation for each individual vendor to cut corners on compatibility. If someone can get their product out a little faster by skipping a few features or failing a few tests, I can understand that temptation. But we are all in this together. If each vendor cherry-picks the set of features that they want to implement, then we will end up with a fragmented platform where there is no real application portability. Fortunately, all of the major vendors understand the benefits of strong compatibility, but at the same time, no one wants to be unfairly disadvantaged.

One of the strengths of the Java Community Process is that it has very strong requirements around compatibility which are binding on all participants. This helps reassure the vendors that they are all held to the same standards. So it may take work to achieve compatibility, but all participants face the same work. And as developers, this means we benefit from a wide range of competing, but compatible, Java implementations!