생각의 폭을 넓혀주는 프로그래밍 언어, 루비


루비는 포스트 모던 프로그래밍 언어이다. 모더니즘이 순수한 이상을 추구한다면, 포스트 모더니즘은 여러 이상의 실용적인 결합을 추구한다. 루비는 기존 프로그래밍 언어의 장점을 받아들여 만들어진 무척 실용적인 프로그래밍 언어이다. 지금부터 필자와 함께 루비의 매력을 하나둘 짚어본다.

루비에 많은 영향을 준 언어에는 객체지향 언어의 아버지라 불리는 Smalltalk, 함수형 언어의 시조인 Lisp, 그리고 텍스트 처리에 뛰어난 Perl 등이 있다. 루비는 Smalltalk의 계보를 잇는 순수 객체지향 언어이지만, Lisp의 클로져(Closure)와 메타프로그래밍(Metaprogramming) 기능 또한 지원하며, Perl의 강력한 정규식 기능도 지원하고 있다. 어쩌면 프로그래밍의 각 패러다임을 대표하는 이들 언어가 하나의 교착점에서 만났다는 것이 바로 루비의 최대 강점일지도 모르겠다.

루비가 순수한 객체지향 언어라는 것은 루비에서 원시형 데이터 타입을 전혀 지원하지 않는다는 것을 의미한다. 루비에서는 모든 데이터가 곧 객체이다. 이러한 데이터 타입의 일관성은 루비의 신택스(Syntax)를 간소화시켰을 뿐만 아니라, 루비의 동적 타이핑(Dynamic Typing)과 맞물려서 루비로 작성된 코드를 매우 깔끔하게 만들어줬다.

루비에서는 클로져를 흔히 블록(Block)이라고 부르는데, 블록은 루비의 트레이드 마크와도 같은 기능이다. 블록은 배열 등과 같은 집합 데이터의 원소를 순차적으로 처리하는 작업 등에 특히 유용하며, 코드를 보다 간결하고 직관적으로 만들어주기 때문에 루비에서는 상당히 보편적으로 사용되는 기능이다. 최근에는 루비의 영향으로 자바에서도 클로져 기능을 추가하는 것이 논의되고 있을 정도다.

기존의 프로그래밍 언어와 차별화되는 루비의 가장 강력한 기능은 아마도 메타프로그래밍일 것이다. 메타프로그래밍이란 프로그램 코드를 작성하는 프로그램을 만드는 것을 말하는데, 보통 기계적이고 반복적인 코딩을 자동화하는 데 사용되는 매우 유용한 프로그래밍 기법이다. 어느 정도 루틴화 된 코드를 반복하여 작성하는 일은 개발자에게 지루한 작업일 수 밖에 없다. 메타프로그래밍은 이러한 코드를 아예 자동으로 생성하는 프로그래밍 기법으로, 루비에서는 메타프로그래밍을 통하여 런타임에 프로그램 코드를 동적으로 추가하는 것을 지원하고 있다.

이러한 루비의 메타프로그래밍은 C의 매크로 전처리나 C++의 컴파일 타임 템플릿 메타프로그래밍과는 대조적으로, 메타프로그래밍 코드 자체가 루비로 작성되며 컴파일 타임이 아닌 런타임에 프로그램 코드가 생성된다는 특징이 있다.

루비는 또한 텍스트 처리에 매우 뛰어난 프로그래밍 언어이다. 루비는 기본적으로 Perl의 텍스트 처리 기능을 그대로 계승하고 있는데, 이 때문에 루비의 텍스트 처리 능력은 Perl과 거의 동일하다고 말할 수 있다. 루비에서의 정규식은 내부적으로는 객체로 구현되어 있지만, 신택스 레벨에서는 Perl과 동일한 형태의 정규식 리터럴(literal)을 사용할 수 있다.

루비의 마지막 장점은 배우기에 무척 쉬운 언어라는 점이다. 루비처럼 강력한 프로그래밍 언어가 배우기 쉽다는 사실은 어쩌면 다소 아이러니컬하게 들릴지도 모르겠다. 하지만 루비를 만든 마츠모토 유키히로(Matsumoto Yukihiro)는 처음 설계할 때부터 단계적으로 익히기 쉬운 언어를 지향했다고 한다. 그 덕분인지 루비는 신택스가 매우 직관적일 뿐만 아니라, 완전히 마스터하기 이전에도 활용성이 비교적 뛰어난 언어이다. 처음부터 메타프로그래밍과 같은 고급 프로그래밍 기법을 알아야 할 필요는 없다. 루비는 기본적인 신택스만 알아도 범용 스크립팅 언어로 활용할 수 있기 때문에, 단계적으로 고급 기능을 익혀가면서 루비의 활용 범위를 점차 넓혀갈 수 있다.

루비의 직관적인 신택스가 루비를 처음 접하는 사람에게만 유용한 것은 아니다. 루비의 신택스는 직관적인 동시에 간결하기 때문에 루비로 작성된 코드는 가독성이 매우 뛰어나다. 실제로 루비 개발자 중에서 루비의 최대 장점으로 코드 가독성을 손꼽는 이들도 적지 않다.

앞에서는 몇가지 언어적 특성을 중심으로 루비를 개괄적으로 설명해 보았다. 이제부터는 코드 예제와 함께 루비의 이런 언어적 특성이 실제 코드에서 어떻게 반영되고 있는지를 살펴보고, 루비 개발 환경에 대한 내용도 일부 다뤄보도록 한다.

루비의 객체지향성

다시 말하지만 루비는 순수 객체지향 언어이다. 즉, 루비의 모든 데이터는 곧 객체이기 때문에 언제나 데이터에서 직접 메소드를 호출할 수 있다. 명령 프롬프트 창에서 irb[1]를 실행시켜 다음을 한번 입력해 보자.

c:\> irb --simple-prompt
>> -124.abs
=> 124
>> 124.abs
=> 124
 

여기서 'abs'는 절대값을 리턴하는 메소드이다. 루비에서는 숫자 역시 객체이기 때문에 예로 든 경우처럼 숫자에 직접 메소드를 호출하는 것이 가능하다. 사실 루비 코드는 객체와 메소드로만 이루어져 있다고 해도 과언이 아니다. 루비에서는 심지어 클래스 조차도 객체로 구현되어 있다. 루비에서 새로운 객체를 생성할 때는 일반적으로 클래스의 'new' 메소드를 호출하는 방법이 사용된다.

>> t = Time.new
=> Sat Sep 16 18:28:05 KST 2006
 

루비의 연산자는 실제로 모두 메소드로 구현되어 있다. 다음 코드를 한번 살펴보자.

>> 5 + 3
=> 8
>> 5.+(3)
=> 8
 

위에서 첫번째 코드는 숫자 5와 3을 더하라는 연산이고, 두번째 코드는 5라는 숫자 객체의 '+' 메소드를 호출하여 숫자 3을 인자로 넘기라는 의미이다. 이 두 가지 코드는 완전히 동일한 코드로, 첫번째 코드는 두번째 코드를 호출하는 또다른 방법에 불과하다. 아울러 정수를 나타내는 Fixnum 클래스의 '+' 메소드의 정의를 변경하면, 실제로 '+' 연산자의 기능 자체를 바꾸는 것도 가능하다. 다음의 예를 한번 살펴보자.

>> class Fixnum
>>   def +(other)
>>     (self.to_s.concat(other.to_s)).to_i
>>   end
>> end
=> nil
>> 5 + 3
=> 53
 

위에서 새롭게 정의한 '+' 메소드는 각 숫자를 문자열로 바꾸어서 결합한 다음, 그 결과를 다시 숫자로 바꾸어 리턴하고 있다. 위의 코드는 클래스의 정의를 아무때나 변경할 수 있는 루비 클래스의 개방성을 보여주는 셈이다. 또한 루비는 자바와는 다르게 동적 타이핑(Dynamic Typing)을 지원한다. 이 때문에 객체에 어떤 메소드를 호출하는 것도 가능하다. 만약에 존재하지 않는 메소드가 호출되면, 컴파일 시점에 에러가 나는 것이 아니라 단지 런타임에 예외(Exception)가 발생할 뿐이다.

>> "gun".length
=> 3
>> "gun".fire
NoMethodError: undefined method `fire' for "gun":String
        from (irb):3
 

이러한 루비의 동적 타이핑은 루비에서의 개발을 상당히 편리하게 만들어 주는 요소다. 이 덕분에 루비에서는 추상 클래스의 상속을 통하지 않고도 다형성(Polymorphism)을 실현할 수 있다. 이는 루비가 변수에 클래스 타입을 지정하지 않기 때문에 가능한데, 주어진 객체가 특정 메소드를 지원하는 것만 알고 있으면 그 객체가 실제로 어떤 클래스의 객체인지는 그다지 중요하게 생각하지 않는다.

이처럼 객체가 명시적으로 어떤 클래스에 속하느냐의 문제보다는 해당 객체가 어떤 메소드를 지원하느냐의 문제를 훨씬 더 중요시하는데, 이를 흔히 덕 타이핑(Duck Typing)이라고도 한다. 즉, 오리처럼 뒤뚱거리며 걷고 오리처럼 꽥꽥거리고 울면, 그 클래스 타입과는 상관없이 그냥 오리로 취급해도 무방하다는 식이다.

이 때문에 루비에서는 변수를 선언할 때도 클래스 타입을 명시적으로 지정하지 않고, 심지어 변수의 선언 자체도 자동으로 이뤄진다. 처음으로 변수에 값이 지정되는 시점에 그 변수가 자동으로 선언되는 것이다.

자바와 같은 스태틱 타이핑(Static Typing) 언어에 익숙한 개발자라면, 타이핑 측면에서 루비의 이러한 자유분방한 접근방식이 처음에는 다소 불안하게 느껴질 수도 있다. 하지만 이러한 접근방식에 조금만 익숙해지고 나면, 다이내믹 타이핑(Dynamic Typing)이 루비에서의 개발을 훨씬 더 편리하게 해준다는 점을 공감하게 될 것이다.

루비에서는 다중 상속의 복잡성을 피해가기 위해서 기본적으로 단일 상속 체계를 사용하고 있다. 하지만 루비는 실질적으로 다중 상속의 기능을 거의 다 지원하고 있는데, 이는 바로 모듈(Module)과 믹스인(Mixin) 덕분에 가능하다. 모듈은 일종의 불완전 클래스라고 말할 수 있는데, 모듈에는 멤버 변수와 메소드가 정의될 수 있다. 루비의 클래스는 단 하나의 부모 클래스만을 가질 수 있지만, 동시에 임의의 개수의 모듈을 포함(Mixin)할 수 있다. 믹스인은 바로 클래스에 모듈의 멤버 변수와 메소드를 추가하는 기능이다. 루비는 이처럼 모듈과 믹스인 기능을 통해 실질적인 다중 상속 기능을 실현하고 있다고 볼 수 있다.

블록

블록은 프로그램 코드를 데이터처럼 취급하게 해주는 기능이다. 즉, 함수를 정의하는 식으로 블록을 정의하여 다른 메소드에 이를 인자로 넘길 수 있다. 이처럼 코드를 데이터로 다룰 수 있는 것은 실로 매우 강력한 기능이다. 블록의 가장 보편적인 사용 케이스는 배열과 같은 집합 데이터의 각 원소에 특정 코드를 순차적으로 적용시키는 것이다. 다음의 코드를 한번 살펴보도록 하자.

>> ["apple", "banana", "orange"].map {|fruit| fruit.upcase}
=> ["APPLE", "BANANA", "ORANGE"]
 

'{ ... }' 부분이 바로 블록인데, 배열의 'map' 메소드는 이 블록을 배열의 모든 원소에 적용시킨 후, 블록이 리턴하는 값을 가지고 새로운 배열을 만들어 리턴한다. 블록의 이러한 활용은 집합 데이터를 처리하는 데 필요한 코드의 양을 획기적으로 줄여줘 매우 유용한 코딩 기법으로 평가된다. 물론 집합 데이터를 처리하는 것이 블록의 유일한 용도는 아니며, 메소드에 알고리즘을 인자로 넘기는 경우나 이벤트에 콜백(Call back)을 걸어주는 경우에도 블록의 사용은 필요한 코드의 양을 상당 부분 줄일 수 있다.

메타프로그래밍

앞에서 설명한 것처럼 메타프로그래밍은 프로그램 코드를 생성하는 프로그램을 만드는 것이다. 다음의 코드를 한번 살펴보자.

>> class Person
>>   def name
>>     return @name
>>   end
>>
?>   def name=(name)
>>     @name = name
>>   end
>> end
=> nil
>> p = Person.new
=> #<Person:0x53c050>
>> p.name = "Kim Chul Soo"
=> "Kim Chul Soo"
>> p.name
=> "Kim Chul Soo"
 

위의 코드에서는 Person 클래스를 정의하고 있는데, 'name' 메소드와 'name=' 메소드가 정의되어 있다. 'name' 메소드는 getter 메소드로 단순히 '@name' 멤버변수를 리턴해주고 있고, 'name=' 메소드는 setter 메소드로 넘겨받은 인자를 '@name' 멤버변수에 지정해주고 있다. 위의 코드에서는 Person 객체를 생성하여 앞에서 정의한 getter 메소드와 setter 메소드를 사용하는 것도 보여주고 있다.

위와 같은 getter/setter 메소드의 정의는 매우 보편적으로 사용되는 코딩 패턴으로, 별도의 툴을 사용하지 않는 한 개발자가 매번 수작업으로 코딩할 수밖에 없었다. 루비에서는 메타프로그래밍을 사용하여 이 작업을 자동화할 수 있다. 다음의 코드를 보자.

>> class Person
>>   attr_accessor "name"
>> end
=> nil
=> #<Person:0x52dce4>
>> p.name = "Lee Young Hee"
=> "Lee Young Hee"
>> p.name
=> "Lee Young Hee"
 

'attr_accessor'는 일종의 클래스 메소드로 "name" 문자열을 인자로 받아 'name' getter 메소드와 'name=' setter 메소드를 런타임에 자동으로 생성해주고 있다. 이처럼 루비의 메타프로그래밍은 런타임에 새로운 메소드를 자동으로 추가하는 용도로 많이 사용된다. 'attr_accessor' 클래스 메소드는 상위 클래스로부터 Person 클래스로 자동으로 상속되고 있지만, 이런 메소드를 개발자가 직접 정의할 수도 있다. 다음의 코드를 한번 살펴보자.

>> class Person
>>   def self.my_attr_accessor(str)
>>     class_eval "def #{str}; @#{str}; end"
>>     class_eval "def #{str}=(#{str}) @#{str}=#{str}; end"
>>   end
>>  
?>   my_attr_accessor("name")
>> end
=> nil
>> p = Person.new
=> #<Person:0x538fcc>
>> p.name = "Hong Gil Dong"
=> "Hong Gil Dong"
>> p.name
=> "Hong Gil Dong"
 

'class_eval'은 문자열로 넘겨받은 루비 코드를 런타임에 실행해주는 메소드인데, 이 메소드가 바로 루비에서 메타프로그래밍을 가능하게 하는 핵심이다. 위에서 정의된 'my_attr_accessor' 클래스 메소드는 넘겨받은 문자열에 매칭되는 getter/setter 메소드를 정의하는 루비 코드를 문자열 형태로 구성한 후, 'class_eval' 메소드를 통하여 이 코드를 실행한다.[2] 'my_attr_accessor' 메소드는 런타임에 호출되고 있으며, 따라서 이들 getter/setter 메소드는 런타임에 동적으로 생성되어 프로그램의 실행 코드에 추가된다.

텍스트 처리

루비의 텍스트 처리 기능은 Perl을 그대로 벤치마킹했다. 여기서 주목할 부분은 루비가 Perl 스타일의 텍스트 처리 기능을 온전히 객체지향적으로 구현하고 있다는 점이다. 다음 코드를 한번 살펴보도록 하자.

>> if /([0-9]+)/ =~ "A year has 365 days."
>>   puts $1
>> end
365
=> nil
 

위의 코드를 보면 '/ ... /' 부분의 정규식이 Perl과 동일한 형태로 사용되고 있는 것을 볼 수 있다. 루비에서는 위의 정규식 리터럴이 객체이며, '=~'는 이 정규식 객체의 메소드로 정의되어 있다.

>> /([0-9]+)/.class
=> Regexp
>> /([0-9]+)/.=~("A year has 365 days.")
=> 11
 

텍스트 처리에 있어 정규식의 주요 사용 케이스 중 하나는 바로 텍스트의 일부를 치환하는 작업이다. 루비에서는 문자열 객체의 'sub' 메소드와 정규식 패턴을 사용하여 문자열의 특정 부분을 치환할 수 있다.

>> "banana".sub(/a/, "@")
=> "b@nana"
 

만약 매칭되는 모든 패턴을 치환하고 싶다면, 'sub' 대신에 'gsub'를 사용한다.

>> "banana".gsub(/a/, "@")
=> "b@n@n@"
 

이처럼 루비에서는 Perl의 텍스트 처리 기능을 객체지향적으로 구현하고 있으므로, 정규식의 사용이 Perl과 마찬가지로 편리하고, 코드의 가독성은 Perl보다 훨씬 더 뛰어나다고 할 수 있다.

왜 지금 루비인가

루비는 1990년대 말부터 그 저변이 꾸준히 확대되어 왔지만, 최근 들어 스포트라이트를 받게 된 결정적인 계기는 바로 레일스 프레임워크의 등장 때문이다. 레일스는 몇 가지 독창적인 아이디어와 루비의 강력한 기능이 절묘하게 결합되어 만들어진 웹 개발 프레임워크로, 이미 북미 지역에서는 레일스로 구축된 B2C 사이트만 해도 수 백 여개에 이르는 등 웹 개발 분야에 커다란 변화를 일으키고 있다.

레일스가 루비의 메인스트림 진입에 커다란 역할을 한 것은 사실이다. 하지만 여기서 주목할 것은 이제 루비는 레일스와 같은 주요 프레임워크가 그 기반으로 만들어질 수 있을 만큼 성숙했다는 점이다. 이미 레일스 말고도 수많은 애플리케이션과 프레임워크가 루비를 기반으로 만들어지고 있고, 이제 어떠한 개발 프로젝트에도 부족하지 않은 풍부한 라이브러리를 갖춰가고 있다.

레일스는 루비의 강점을 명확히 보여주는 프레임워크인데, 예를 들어 레일스에서의 웹 개발은 자바에 비해 적어도 5배 이상 더 빠르다. 레일스의 성공에 자극을 받은 다른 프로그래밍 언어에서도 레일스와 유사한 프레임워크를 구현하려는 시도가 잇따르고 있지만, 아직까지 이러한 시도는 그다지 성공적이지 못하였다. 이는 레일스가 루비만이 지원할 수 있는 고차원의 프로그래밍 기법을 십분 활용하여 설계된 프레임워크이기 때문이다. 레일스를 통한 마케팅 덕분에 루비는 지난 수년간 다양한 환경에서 그 효용성이 입증되어 왔다. 이제 루비를 익힌다는 것은 단순히 새로운 언어를 사용해보는 것을 넘어, 실무에서 활용하고 이력서에 추가할 수 있는 새로운 기술을 배우는 것이라고 할 수 있다.

루비 개발을 위한 툴

개발 프로젝트를 효율적으로 진행하기 위해서는 언어 이외에도 개발을 보조하는 다양한 툴들이 필요하다. 여기서는 루비 개발에 일반적으로 사용되는 몇 가지 툴을 소개한다.

프로그래밍에 있어 가장 중요한 툴은 텍스트 편집기이다. 윈도우 기반의 개발에서는 SciTE, UltraEdit, TextPad 등이 이미 루비 신택스를 지원하고 있으며, 레일스 개발에는 Eclipse 기반의 RadRails가 널리 사용되고 있다. 맥 OS X 기반의 개발에서는 TextMate, TextWrangler 등이 주로 사용되고 있으며, 유닉스 기반의 개발에서는 Emacs와 Vim 등이 루비를 지원하고 있다. 또한 루비는 라이브러리 관리 툴로 루비젬이라는 유틸리티를 사용하고 있는데, 이는 각종 루비 라이브러리를 자동으로 설치하고 관리해주는 핵심적인 유틸리티이다. 루비젬을 통해 새로운 라이브러리를 설치하는 과정은 다음과 같이 간단하다.

c:\> gem install xml-simple
Attempting local installation of 'xml-simple'
Local gem file not found: xml-simple*.gem
Attempting remote installation of 'xml-simple'
Successfully installed xml-simple-1.0.9
 

프로젝트의 빌드 툴로는 루비로 구현된 rake라는 툴을 사용한다. rake에서는 별도의 파일 포맷을 사용하는 대신에 루비로 구현된 내장형 DSL(Domain Specific Lan-guage)을 사용하고 있다. 이 덕분에 rake는 자바의 ant에 비해 빌드 파일 포맷이 훨씬 더 간결하면서도 더욱 강력한 기능을 자랑한다. RDoc은 API 문서를 자동으로 만들어주는 루비 유틸리티로 자바의 JavaDoc과 비슷한 역할을 한다. <화면 1>은 RDoc으로 생성된 루비 API 문서를 보여주는 웹 브라우저의 모습이다.


<화면 1> RDoc으로 생성된 루비 API 문서

RDoc으로 만들어진 API 문서는 다음처럼 ri 유틸리티를 통해 조회할 수도 있다.

c:\> ri Array#join 
--------------------------------------- Array#join
  array.join(sep=$,)    -> str
--------------------------------------------------
  Returns a string created by converting each
  element of the array to a string, separated by
  _sep_.

      [ "a", "b", "c" ].join        #=> "abc"
      [ "a", "b", "c" ].join("-")   #=> "a-b-c"
 

RDoc 문서는 보통 웹 브라우저에서 조회하지만, 간단한 확인이 필요할 때는 ri도 유용하게 사용될 수 있다. 루비젬, rake, rdoc처럼 기본적으로 제공되는 툴 외에도, 루비는 강력한 표준 라이브러리를 갖추고 있다. 다음에 보여지는 것처럼 'require' 메소드를 써서 손쉽게 표준 라이브러리를 사용할 수 있다.

>> require 'net/http'
=> true
>> response = Net::HTTP.get_response("www.imaso.co.kr", "/")
=> #<Net::HTTPOK 200 OK readbody=true>
>> response["content-type"]
=> "text/html; charset=EUC-KR"
>> response["last-modified"]
=> "Mon, 18 Sep 2006 02:34:31 GMT"
 

이는 'net/http' 라이브러리를 사용하여 마이크로 소프트웨어 홈페이지에 접근하는 것이다. 'response'의 'body' 메소드를 호출하면, 해당 문서의 html을 직접 확인할 수도 있다. 아울러 루비에서 제공하고 있는 표준 라이브러리의 API 문서는 http://www.ruby-doc.org에서 확인할 수 있다.

엔터프라이즈 환경에서의 루비

국내에서는 이제 조금씩 루비에 관심을 갖는 단계이지만, 외국의 경우에는 이미 루비가 엔터프라이즈 환경에서 널리 사용되고 있다. 루비의 유연한 프로그래밍 모델이 복잡한 기술을 통합해 다뤄야 하고 고객의 요구에 따라 갑작스런 변화가 발생하는 엔터프라이즈 개발 환경에 여러가지로 유리한 면이 많기 때문이다.

오래전부터 루비를 엔터프라이즈 개발에 사용해온 대표적인 회사로는 ThoughtWorks를 꼽을 수 있다. ThoguhtWorks는 "엔터프라이즈 애플리케이션 아키텍처 패턴", "리팩토링" 등의 저서로 국내에도 널리 알려진 Martin Fowler가 CTO로 있는 다국적 IT 컨설팅 회사이다. ThoughtWorks는 그동안 각종 프로젝트에 루비를 사용함으로써 개발 시간을 현저히 단축시키고 많은 비용을 절감해왔다.

루비를 주요 엔터프라이즈 개발 언어로 사용하는 또다른 IT 컨설팅 회사에는 MomentumSI가 있다. MomentumSI는 웹서비스, SOA, 대용량 데이터 처리, 웹 애플리케이션, 프로토타입 개발 등의 분야에서 루비를 사용할 것을 적극적으로 권장하고 있다. 컨설팅 회사 이외에도 미국에서는 Amazon, EarthLink 등과 같은 많은 IT 기업들이 루비를 내부 및 외부 프로젝트에 사용하고 있다. Amazon은 과거 자체 전자상거래 엔진이 주로 Perl로 구현되었지만, 최근 많은 부분을 루비로 바꿔 개발하는 것으로 알려졌다.

루비의 문제점

루비가 강력한 프로그래밍 언어인 것은 틀림없지만, 그렇다고 모든 면에서 완벽한 언어는 아니다. 여기서는 루비의 문제점을 살펴봄으로써, 특정 프로젝트에 루비가 적합한지 아닌지를 판단하는 데 도움을 주고자 한다.

루비의 첫번째 문제로 실행 속도를 꼽을 수 있다. 루비는 해석형 언어이기 때문에 실행 속도에 어느 정도 핸디캡이 있다. 실행 속도가 핵심적인 프로젝트에 루비를 사용하기 위해서는 최적화가 필요한 모듈은 C 언어로 개발해야 한다. 실제로 루비에는 필요한 모듈을 C로 개발할 수 있는 API가 포함되어 있다.

현재 루비 2.0이 가상 머신(Virtual Machine)을 기반으로 개발되고 있어, 머지않아 속도 문제가 상당 부분 해결될 전망이다. 여기에 최근에는 루비를 .NET으로 이식하는 RubyCLR, IronRuby 등의 프로젝트도 활기를 띠고 있고, 썬마이크로시스템즈가 JRuby[3] 프로젝트를 인수하는 등 루비의 실행 속도 문제는 빠른 속도로 개선될 것으로 예상된다.

흔히 지적되는 루비의 또다른 약점은 다소 제한적인 유니코드의 지원이다. 루비의 문자열 클래스는 현재도 유니코드를 지원하고 있지만, 몇가지 필수적인 메소드가 바이트 단위에서만 작동한다는 문제가 있다. 이 문제는 기존 코드와의 호환성 유지 때문에 루비 2.0의 API 변경과 함께 다뤄질 예정으로 현재는 수정이 이루어지지 않고 있다. 다만 이러한 유니코드 이슈는 외부 라이브러리를 사용하면 쉽게 해결되는 문제이므로, 이 때문에 루비의 사용을 미룰 필요는 없다.

  1. irb는 루비에서 제공하는 인터랙티브 루비 쉘이다. irb 프롬프트에 루비 코드를 입력하고 엔터를 치면, 입력된 루비 코드가 한줄씩 실행되어진다.
  2. 'class_eval' 메소드에 인자로 넘겨지는 문자열에서 세미콜론(;)은 루비 코드 여러줄을 한줄에 작성할때, 줄을 끊어주는 역할을 한다.
  3. 자바로 작성된 루비 실행 환경으로 루비 코드를 JVM(자바 가상머신)에서 실행되는 바이트 코드로 컴파일 해준다.

노트: 이 글은 마이크로 소프트웨어 2006년 10월호에 "스페셜 리포트 1부: 전통 언어의 혈통을 잇는 스크립트 언어, 루비"라는 제목으로 실렸습니다.