 |
루비 메타프로그래밍, Part 1: 프로그램을 작성하는 프로그램 |
 |


난이도 : 중급
2008년 3월 25일
연재순서
1회(2008년 3월): 프로그램을 작성하는 프로그램
‘메타(meta-)’는 영어에서 다른 낱말 앞에 붙는 접두어로 본 낱말에 ‘일반적인 ~의 범주를 넘어서는’이라는 뜻을 부여한다. 예를 들어 ‘metaphysics’라는 낱말은 ‘메타(meta)’와 ‘물리학(physics)’이 결합되어 만들어진 합성어로 ‘일반적인 물리학의 범주를 넘어서는 학문’이라는 의미를 갖고 있다. 물리학은 존재하는 것, 곧 물질을 대상으로 다루는 학문이다. ‘일반적인 물리학의 범주를 넘어서는 학문’인 ‘metaphysics’는 ‘존재의 본질에 관한 학문’, 즉 ‘형이상학’인 것이다.
‘메타(meta)’와 ‘프로그래밍(programming)’의 합성어인 ‘메타프로그래밍(metaprogramming)’ 또한 ‘일반적인 프로그래밍의 범주를 넘어서는 프로그래밍’이란 의미를 가지고 있다. 여기에서 우리는 메타프로그래밍이 무언가 새로운 형태의 프로그래밍이라는 것, 그리고 메타프로그래밍이 다루는 대상이 기존 프로그래밍과는 차별화된다는 것을 유추할 수 있다. 그렇다면 메타프로그래밍은 과연 어떤 면에서 기존 프로그래밍과 구별되는 것일까?
우선 프로그래밍이란 무엇인지를 한번 돌이켜 생각해 보자. 조금 단순하게 정의하면, 프로그래밍은 '데이터를 처리하기 위한 자동화된 프로세스를 구현하는 작업'이라고 말할 수 있다. 이렇게 구현된 자동화된 프로세스를 우리는 '프로그램'이라고 부른다. 프로그램은 컴퓨터 코드로 작성되며 사용자가 입력한 숫자, 텍스트, 또는 바이너리 데이터를 컴퓨터를 통해 처리한 후 결과를 출력하거나 저장한다. 다시 말하면 프로그래밍이란 사용자의 데이터를 처리할 컴퓨터 코드를 작성하는 작업이라고 할 수 있다.
메타프로그래밍으로 작성된 프로그램 역시 자동으로 데이터를 처리하는데, 이때 처리 대상이 되는 데이터가 조금 특별하다. 메타프로그래밍으로 구현된 프로그램이 처리하는 데이터는 바로 컴퓨터 코드 자체이기 때문이다. 프로그램이란 곧 컴퓨터 코드이므로 메타프로그래밍이란 결국 컴퓨터 코드를 처리하기 위한 컴퓨터 코드를 작성하는 작업인 것이다.
메타프로그래밍을 처음 접하는 프로그래머들은 메타프로그래밍이 정말로 유용한지, 그리고 실제로 실무에 활용될 수 있는지에 대해 종종 의구심을 표현하곤 한다. 이는 컴퓨터 코드를 자동으로 처리한다는 것이 무언가 모호하고 추상적으로 느껴지기 때문일 것이다. 컴퓨터 코드를 자동으로 처리하는 것의 이점은 과연 무엇일까? 결론부터 이야기하자면 메타프로그래밍은 어느 정도 정형화되고 반복적인 유형의 코드를 자동으로 생성해줌으로써, 이전에는 프로그래머가 직접 손으로 작성하고 일일히 관리해야 했던 코드를 자동으로 작성하고 관리할 수 있게 해준다.
프로그래밍에서 코드 반복을 줄이기 위해 가장 많이 쓰이는 방법은 물론 반복적으로 사용되는 코드를 함수나 메서드 단위로 묶어내는 것이다. 함수는 이를 호출하는 단 한줄의 코드만으로 함수 전체 코드를 대신하게 해주며, 결과적으로 프로그램을 구성하는 코드 양과 코드 반복을 크게 줄여주고 이 코드들을 관리하는 작업 또한 쉽게 만들어준다.
그런데 프로그래밍을 하다 보면, 기본적으로 비슷한 골격을 가졌지만 완전히 동일하지는 않은 함수를 반복하여 정의하는 일이 비일비재하다. 예를 위해 다음 루비 코드를 한번 살펴보자.
Listing 1. person.rb
class Person
def initialize(name, gender, age)
@name = name
@gender = gender
@age = age
end
def name
@name
end
def gender
@gender
end
def age
@age
end
end
|
위의 코드는 Person 클래스를 정의하고 있으며, Person 클래스 안에는 생성자 메서드인 initialize와 이름, 성별, 나이 등의 객체 변수에 접근하기 위한 접근자(getter) 메서드 name, gender, age 등이 정의되어 있다. 위의 루비 Person 클래스는 다음과 같이 사용할 수 있다.
c:\> irb --simple-prompt
>> load "person.rb"
=> true
>> p = Person.new("홍길동", "남자", 30)
=> #
>> p.name
=> "홍길동"
>> p.gender
=> "남자"
>> p.age
=> 30
|
위에서 정의된 Person 클래스의 접근자 메서드 name, gender, age는 코드 구조가 완전히 같지만, 메서드 이름과 객체 변수 이름에서 구분되기 때문에 일반적인 프로그래밍 기법을 사용해 이 메서드들을 정의하는 작업을 자동화할 수는 없다. 하지만 이 메서드들을 정의하는 위의 코드에서는 명백한 코드 패턴 반복이 일어나고 있다. 반복적인 작업을 자동화하는 일이야말로 프로그래밍을 하는 가장 기본적인 목적이 아니겠는가?
루비에서는 이러한 접근자 메서드를 정의하는 작업을 자동화하기 위해 attr_reader라는 클래스 메서드를 제공한다. 우리는 attr_reader 메서드를 활용하여 앞의 Person 클래스를 다음과 같이 재정의할 수 있다.
Listing 2. person.rb
class Person
attr_reader "name", "gender", "age"
def initialize(name, gender, age)
@name, @gender, @age = name, gender, age
end
end
|
attr_reader는 메타프로그래밍 기능을 통해 구현된 메서드인데 인자로 지정된 문자열값에 해당하는 접근자 메서드를 정의해준다. 우리가 처음에 정의했던 Person 클래스는 코드가 모두 19줄이었지만, 위에서는 attr_reader를 활용하여 코드가 7줄로 줄어들었다. 이처럼 메타프로그래밍은 좀더 상위 레벨에서의 코드 반복을 줄이기 위한 방법을 제공함으로써 전체 코드 양을 줄여주고 코드를 관리하는 일을 한결 편리하게 해준다.
Part 1에서는 메타프로그래밍에 대한 개념적인 소개와 그 효용성에 대해 간단히 살펴봤다. 다음 연재에서는 attr_reader와 같은 메서드를 구현하는 데 쓰이는 루비의 메타프로그래밍 기능을 살펴볼 것이다. 이후 연재에서는 좀더 복잡한 코딩 작업의 자동화를 위해 메타프로그래밍을 활용하는 방법들을 소개하기로 한다.
필자 소개  | |  |
황대산 me@daesan.com
미국 예일대학교에서 수학을 전공했고, 현재 국내에서 프리랜서 개발자로 활동중이다. 루비/레일스 에반젤리스트를 자임하며 틈틈이 잡지 등에 관련 글을 기고하는 등 활발히 활동하고 있다. ‘웹 개발 2.0 루비 온 레일스’라는 책을 집필했다 |
|