루비 온 레일스 학습 가이드



황대산
황대산 me@daesan.com

미국 예일대학교에서 수학을 전공했고, 현재 국내에서 프리랜서 개발자로 활동중이다. 루비/레일스 에반젤리스트를 자임하며 틈틈이 블로그나 잡지 등에 관련 글을 기고하는 등 활발히 활동하고 있다. ‘beyond the status quo' 블로그를 운영하고 있으며, 최근에는 ‘웹 개발 2.0 루비 온 레일스’라는 책을 집필했다.


난이도 : 초급
2007년 3월27일


[오픈 디벨로퍼웍스]는 여러분이 직접 필자로 참가하는 코너입니다. 이 글에서는 최근 몇 년 간 매우 빠른 속도로 성장하고 있는 웹 개발 프레임워크인 루비 온 레일스에 대해 알아봅니다.

루비 온 레일스(Ruby on Rails)가 장안의 화제다. 우선 모두들 궁금해하는 이름부터 짚고 넘어가자. 루비면 루비고, 레일스면 레일스지 ‘루비 온 레일스’란 대체 무엇일까?

우선 루비는 일본의 유키히로 마츠모토가 1995년에 처음 공개한 객체지향 스크립트 언어로, 그 이름은 6월의 탄생석인 펄(Perl)1 에 이어 7월의 탄생석인 루비(Ruby)에서 따왔다고 한다. 간결하고 직관적인 신택스 때문에 개발자들의 많은 사랑을 받고 있는 루비는 ‘2006년 올해의 프로그래밍 언어’2 로 선정되기도 했다.

레일스는 2004년 덴마크의 데이빗 해너마이어 한슨에 의해 개발된 오픈소스 웹 개발 프레임워크로, 흔히 말하는 ‘루비 온 레일스’는 이 레일스 프레임워크를 가리키는 애칭이다. 이 문구는 고속열차가 철도(rails) 위를 질주하듯이 빠르고 쾌적한 웹 개발을 지향한다는 의미로 이해하면 되겠다. 레일스 애플리케이션은 언제나 루비 코드로 작성되며, 레일스는 웹 애플리케이션 개발을 편리하게 만들기 위한 각종 도구와 라이브러리 모음을 패키지 형태로 제공하고 있다. 레일스는 최근 컴퓨터월드(Computer World)에서 ‘2007년에 가장 주목해야 할 기술’3 로 선정되기도 했다.

이름에 대한 설명은 이쯤 하고, 이제 본격적으로 레일스에 관한 이야기를 풀어보자. 웹 개발 역사가 10년을 훌쩍 넘은 지금, 왜 갑자기 새로운 혁신이 일어나게 됐을까?

필자의 생각은 이렇다. 어떤 면에서 지난 10여 년간은 그동안 고안된 여러 개발 패러다임과 방법론 들을 검증하기 위한 시간이었다. 이들 중에는 유용한 것도 많았지만, 이론과는 다르게 현실에는 잘 들어맞지 않는 경우도 왕왕 있었다. 레일스는 이러한 시행착오를 거울삼아 밑바닥부터 완전히 새롭게 설계된 웹 개발 프레임워크다. 여기에 레일스만의 참신한 개발 철학과 루비의 동적 특성이 결합되면서 누구도 미처 예상하지 못했던 시너지 효과가 생겨났다.

여기에서 말하는 시너지 효과란 물론 개발 생산성 향상을 말한다. 레일스는 DRY(Don’t Repeat Yourself, 반복적인 코딩 작업은 피하시오) 원칙과 ‘설정보다는 관례가 더 편리하다’는 원칙 그리고 각종 코딩 자동화 기법을 통해 웹 개발 생산성을 획기적으로 높여주었다. 이런 이유로 레일스를 이용한 웹 개발은 자바에 비해 보통 5~10배 정도 더 빠르다.

백문이 불여일견이라고 했으니, 이쯤에서 다음 URL을 방문하여 ‘15분 만에 블로그 만들기’ 스크린캐스트를 감상하자(이 스크린캐스트를 감상하려면 애플 퀵타임 플레이어가 컴퓨터에 설치되어 있어야 한다).

http://media.rubyonrails.org/video/rails_take2_with_sound.mov

직접 간단한 레일스 애플리케이션을 만들어보고 싶다면, 필자의 블로그에 있는 ‘레일스 따라하기 1’ 튜토리얼도 참고한다.

http://beyond.daesan.com/articles/2006/07/28/learning-rails-1

앞에서는 비교적 간단한 애플리케이션을 예로 들고 있지만, 그래도 이렇게 적은 양의 코드로 웹 애플리케이션 하나가 뚝딱하고 만들어진다는 것에 적잖이 놀랐을 것이다. 이것이 가능한 것은 앞에서 잠깐 언급했던 레일스의 개발 철학 덕분이다. 이제부터 필자와 함께 이들을 하나씩 살펴보도록 하자.




위로


DRY 원칙

레일스의 개발 철학을 대표하는 첫 번째 원칙은 반복적인 코딩 작업을 피하라는 DRY 원칙이다. 모든 프로그램에서는 중복되는 코드가 필연적으로 발생하기 마련인데, 이를 줄이기 위한 첫 번째 방법은 함수를 사용하여 코드간의 공통분모를 묶어내는 것이다. 레일스는 프레임워크의 모든 부분에서 중복적인 코드를 줄이기 위한 메서드(함수) 사용을 적극적으로 장려하고 있다.

하지만 레일스는 이보다 한 발짝 더 나아가서, 아예 함수를 정의하는 과정을 자동화하는 기능 또한 지원하고 있다. 왜 함수를 정의하는 과정을 자동화해야 할까? 이는 웹 개발에서 사용되는 여러 함수들이 기본적으로 구조가 비슷한 경우가 많아, 매번 이들 함수를 정의하는 작업 자체가 중복되는 일이기 때문이다. 따라서 프레임워크가 웹 개발에 필요한 여러 종류의 함수를 자동으로 정의해준다면, 개발자는 함수를 정의하는 코드를 수작업으로 작성하는 번거로운 과정을 거치지 않고도 이들 함수를 사용할 수 있게 된다.4 이 글의 뒷부분에서는 이러한 자동화 기능이 레일스에서의 웹 개발을 어떻게 편리하게 만드는 지를 간단하게 살펴볼 것이다.

설정보다는 관례가 더 편리하다

레일스의 또 다른 주요 원칙은 ‘설정보다는 관례가 더 편리하다’는 것이다. 관례란 사회가 효율적으로 기능하도록 만들어주는 핵심적인 요소다. 관례의 효용성은 버스 정류장에서 차례로 줄서기, 도서관에서 떠들지 않기 등과 같이 간단한 사회적 약속들을 법률로 제정하는 경우를 상상해보면 쉽게 이해할 수 있다. 법률 제정은 그 절차도 까다로울 뿐더러 실제 상황에서 적용하기도 훨씬 더 복잡하다. 버스 정류장 줄이 흐트러진 게 누구 잘못인지 시시비비를 가리러 재판까지 간다고 한번 생각해보라. 이런 일은 법보다는 사회적 관례가 훨씬 더 효율적이라는 것에 쉽게 공감할 수 있을 것이다.

레일스는 웹 개발 프레임워크에 이러한 상식을 도입하고 있다. 프레임워크의 모든 부분을 법률 정하듯이 일일이 설정하는 작업은 개발자를 지치게 만드는 일이다. 레일스에서는 웹 애플리케이션의 구조 및 설정에 다양한 관례를 도입함으로써 개발자가 일일이 신경 써야 하는 요소를 최소화하고 있다.

과거에는 웹 개발에 프레임워크 도입을 꺼려하는 개발자들이 적지 않았다. 반나절 이상씩 걸리는 복잡한 설정 과정을 마치기 전까지는 개발을 시작조차 할 수 없었기 때문이다. 하지만 레일스에서는 복잡한 설정 과정에 대한 걱정을 하지 않아도 된다. 레일스에서는 프레임워크 전체적으로 적절한 기본(default) 설정 값을 사용하여 아무런 설정 없이도 곧바로 개발을 시작할 수 있기 때문이다. 개발자는 개발 중에 필요한 요소가 생기면, 그때그때 설정을 추가하면 된다.

레일스에서는 또한 프레임워크의 각 요소에 적절한 관례를 적용하여 많은 설정 작업을 자동화하고 있다. 레일스 애플리케이션의 디렉터리 구조와 URL 구조 그리고 데이터베이스 테이블 이름과 모델 클래스 이름 간의 관계 등은 이러한 관례를 통해 설정의 필요를 아예 없애거나 최소화한 대표적인 예들이다.

이제부터는 레일스에서 이러한 철학이 실제로 어떻게 적용되고 있는지를 레일스의 주요 모듈 몇 개를 예로 들어 살펴보기로 한다.




위로


액티브 레코드

액티브 레코드는 레일스에서 데이터베이스의 데이터 관리를 담당하는 ORM(Object/Relational Mapping, 객체/관계 매핑) 모듈이다. 액티브 레코드를 사용하면 개발자는 SQL 구문을 직접 작성하지 않고도 손쉽게 데이터베이스에 데이터를 입력하고 검색할 수 있다. 액티브 레코드에는 레일스의 DRY 원칙과 ‘설정보다는 관례가 더 편리하다’는 원칙이 포괄적으로 적용되고 있다.

첫 번째로 액티브 레코드에서는 데이터베이스 테이블을 생성할 때 이름을 복수형 소문자 영어 낱말로 짓는 관례가 있다. 예를 들어 인명 정보를 관리하는 데이터베이스 테이블의 이름은 ‘people’이고, 게시판 글을 저장하는 테이블의 이름은 ‘posts’인 식이다.

이러한 관례는 시스템의 일관성을 높여주기도 하지만, 여기에는 좀더 중요한 목적이 있다. 테이블 이름을 짓는 방법이 관례화되면, 이제 이 테이블들에 접근하기 위한 모델 클래스 이름을 짓는 방법도 관례적으로 정할 수 있게 된다. 레일스에서는 ‘people’ 테이블을 접근하기 위한 모델 클래스의 이름은 ‘Person’으로, ‘posts’ 테이블을 접근하기 위한 모델 클래스의 이름은 ‘Post’로 짓게 된다. 따라서 레일스에서는 어떤 모델 클래스가 어떤 테이블에 매핑되는 지를 별도로 설정해줄 필요가 없다. 모델 클래스 스스로가 자신이 어떤 테이블에 매핑되고 있는 지를 유추할 수 있기 때문이다.

액티브 레코드의 두 번째 관례는 테이블의 필드명과 모델 클래스의 접근자 메서드의 이름을 동일하게 사용한다는 것이다. ‘people’ 테이블이 다음과 같은 구조를 가지고 있다고 가정해보자.



id name phone number note
1 홍길동 011-123-4567 활빈당 두목
2 임꺽정 016-345-6789 산적 두목
3 장길산 019-567-8901 녹림당 두목
표. 'people' 테이블


‘people’ 테이블이 위와 같이 정의되어 있다면, 레일스는 ‘Person’ 모델 클래스에 이 테이블의 ‘id’, ‘name’, ‘phone_number’, ‘note’ 필드에 대한 접근자 메서드를 자동으로 정의하여 추가한다. 즉, 테이블의 필드명과 모델 클래스의 접근자 메서드는 같은 이름을 사용한다는 관례 덕분에 이들 접근자 메서드를 정의하는 작업을 자동화할 수 있는 것이다. 다음에서는 ‘User’ 모델 클래스를 통해 ‘people’ 테이블의 데이터를 검색한 후, 이를 출력하는 루비 코드를 보여주고 있다.

  
person = Person.find(1)     # id가 1인 레코드를 검색
puts person.name            # "홍길동"을 출력
puts person.phone_number    # "011-123-4567"을 출력
puts person.note            # "활빈당 두목"을 출력


놀라운 점은 위와 같은 인터페이스를 사용하기 위해 레일스 개발자가 직접 작성해야 하는 코드가 거의 없다는 것이다. 이는 레일스가 직접 ‘people’ 테이블의 구조를 확인하여 필요한 메서드를 ‘Person’ 클래스에 자동으로 추가해주기 때문이다. 이번에는 데이터베이스로부터 데이터를 검색한 후, 이를 변경하는 루비 코드를 살펴보자.

  
person = Person.find_by_name("임꺽정")   # name이 "임꺽정"인 레코드를 검색
person.phone_number = "010-789-0123"    # phone_number를 "010-789-0123"로 수정
person.save                             # 수정된 레코드를 데이터베이스로 저장


이처럼 액티브 레코드는 레일스의 두 가지 주요 원칙을 활용하여 데이터베이스 프로그래밍을 거의 완전히 자동화해주고 있다. 여기에서는 가장 기본적인 예만을 다루고 있지만, 실제로 액티브 레코드는 데이터 생성•검색•수정•삭제뿐만 아니라 필드 데이터 검증과 테이블 간 관계 처리 등 복잡한 작업도 위와 비슷한 방법을 사용하여 자동화해준다.




위로


액션 뷰와 액션 컨트롤러

액션 뷰는 레일스에서 HTML 템플릿을 관리하는 모듈이고, 액션 컨트롤러는 웹 브라우저가 레일스 애플리케이션에 특정 URL을 요청했을 때 이를 처리하는 모듈이다. 우선 다음 액션 컨트롤러 클래스를 살펴보자.

  
class PhonebookController < ApplicationController

  def list
    @people = Person.find(:all)
  end
end


위에서 PhonebookController 클래스 안에서는 ‘list’ 액션 메서드가 정의되고 있다. 이제 웹 애플리케이션 사용자가 웹 브라우저 주소 창에 ‘http://www.mysite.co.kr/phonebook/list’라고 입력하면, 이 ‘list’ 액션이 실행된다(이 URL은 레일스의 관례에 따라 ‘Phonebook-Controller’의 ‘list’ 액션에 매핑되고 있다). 이 ‘list’ 액션 안에는 ‘@people’이라는 변수가 선언되고 있는데 이처럼 변수명이 ‘@’로 시작하는 경우, 이들 변수는 자동으로 HTML 템플릿 파일로 넘겨지게 된다.

‘list’ 액션의 마지막에서는 이 액션이 사용할 HTML 템플릿 코드가 호출되어야 하는데, 별도 호출이 없는 경우 ‘list’ 액션은 관례적으로 ‘list.rhtml’ 파일을 HTML 템플릿으로 사용하게 된다. 다음에서는 ‘list.rhtml’ 파일의 예를 보여주고 있다.

  
<html>
<head>
  <title>전화번호 목록</title>
</head>

<body>
<h3>전화번호 목록</h3>
<ul>
  <% for person in @people %>
  <li><%= person.name %>: <%= person.phone_number %></li>
  <% end %>
</ul>
<script type="text/javascript">
var _tiq = 'undefined' !== typeof _tiq ? _tiq : [];
_tiq.push(['__setConfig', {enableScroll:true, enableClick:true, enableButton:true}]);
_tiq.push(["__setParam", "svcdomain", "user.tistory.com"]);
(function(d) {
	var se = d.createElement('script'); se.type = 'text/javascript'; se.async = true;
	se.src = location.protocol + '//m2.daumcdn.net/tiara/js/td.min.js';
	var s = d.getElementsByTagName('head')[0]; s.appendChild(se);
})(document);
_tiq.push(['__setParam', 'param_ex', JSON.stringify({"userId":"213323","blogId":"215188","entryId":"276"})]);
_tiq.push(['__trackPageview']);
_tiq.push(['__content', 't_content', 
{"c_id":"215188_276","c_title":"%EB%A3%A8%EB%B9%84%20%EC%98%A8%20%EB%A0%88%EC%9D%BC%EC%8A%A4%20%ED%95%99%EC%8A%B5%20%EA%B0%80%EC%9D%B4%EB%93%9C","type":"article","author":null,"author_id":"213323","cp":"http%3A%2F%2FHybridego.net%2F%20%3CHo%20Cheol%20Jeon%3E","cp_id":"215188","regdata":"2007-04-05 11:12:09","plink":"http:\/\/hybridego.net\/276","media":"pcweb"}
]);
var addEvent = function (evt, fn) { window.addEventListener ? window.addEventListener(evt, fn, false) : window.attachEvent('on' + evt, fn); };
var removeEvent = function(evt, fn) { window.removeEventListener ? window.removeEventListener(evt, fn, false) : window.detachEvent('on' + evt, fn);};
var ua = navigator.userAgent.toLowerCase(); var isIOS = /iP[ao]d|iPhone/i.test(ua);
var contentExStat = function() {
		_tiq.push(['__content', 't_content_ex', {
			'data_type':'usage'
, 'meta': 
{"c_id":"215188_276","c_title":"%EB%A3%A8%EB%B9%84%20%EC%98%A8%20%EB%A0%88%EC%9D%BC%EC%8A%A4%20%ED%95%99%EC%8A%B5%20%EA%B0%80%EC%9D%B4%EB%93%9C","type":"article","author":null,"author_id":"213323","cp":"http%3A%2F%2FHybridego.net%2F%20%3CHo%20Cheol%20Jeon%3E","cp_id":"215188","regdata":"2007-04-05 11:12:09","plink":"http:\/\/hybridego.net\/276","media":"pcweb"}
}]);
		removeEvent(isIOS ? 'pagehide' : 'beforeunload', contentExStat);
};
addEvent(isIOS ? 'pagehide' : 'beforeunload', contentExStat);
</script>
<script type="text/javascript">window.roosevelt_params_queue = window.roosevelt_params_queue || []; window.roosevelt_params_queue.push({channel_id: "dk", channel_label: 'tistory'});</script>
<script type="text/javascript" src="//t1.daumcdn.net/midas/rt/dk_bt/roosevelt_dk_bt.js" async></script><script type="text/javascript">if(window.console!=undefined){setTimeout(console.log.bind(console,"%cTISTORY","font:8em Arial;color:#EC6521;font-weight:bold"),0);setTimeout(console.log.bind(console,"%c  나를 표현하는 블로그","font:2em sans-serif;color:#333;"),0);}</script><iframe style="position:absolute;width:1px;height:1px;left:-100px;top:-100px" src="http://hybridego.tistory.com/api" id="editEntry"></iframe></body>
</html>


위의 HTML 템플릿에서는 앞의 ‘list’ 액션에서 건네진 ‘@people’ 변수가 사용되고 있는 것을 알 수 있다. '<% ... %>' 부분의 코드는 루비 코드로 HTML 템플릿 파일 내에서 HTML 코드를 출력하는 용도로 쓰이고 있다. 위에서 '<% for person in @people %> ... <% end %>' 부분은 전체 사람의 이름과 전화번호를 HTML로 출력하게 된다.

지금까지는 레일스의 DRY 원칙과 ‘설정보다는 관례가 더 편리하다’는 원칙이 레일스 프레임워크의 몇 가지 모듈에서 어떻게 적용되고 있는 지를 살펴보았다. 여기에서는 개략적인 내용만을 간단히 다뤘지만 비슷한 기능을 가진 다른 프레임워크를 사용한 적이 있다면, 레일스 프레임워크가 얼마나 사용하기 편리하게 설계되어 있는 지를 충분히 공감할 수 있었으리라고 생각한다.




위로


   소셜 북마크

   mar.gar.in mar.gar.in
    digg Digg
    del.icio.us del.icio.us
    Slashdot Slashdot

레일스 스터디를 위한 가이드

레일스로 개발하는 과정은 무척 재미있다. 중복되는 노력 없이 최소한의 코딩 작업만으로 웹 애플리케이션을 완성해 나갈 수 있기 때문이다. 하지만 얼마 전까지는 레일스에 대한 한글 문서가 거의 전무했기 때문에 국내 개발자가 레일스를 익히는 것은 원서 몇 권과 영문 웹 사이트 그리고 영문 메일링 리스트 등을 전전해야 하는 어려운 일이었다.

다행스럽게도 한국 루비 포럼을 중심으로 한 국내 초창기 루비 개발자들은 오랫동안 한글 문서 작업에 매달려왔고, 이들 덕분에 이제 레일스를 시작하는 개발자들은 좀더 쉽게 레일스에 접근할 수 있게 되었다.

현재 국내에는 필자가 집필한 루비/레일스 입문서인 ‘웹 개발 2.0 루비 온 레일스’를 비롯하여 ‘프로그래밍 루비’, ‘레일스와 함께하는 애자일 웹 개발’, ‘레일스 레시피’, ‘Ruby on Rails: 초고속 웹 개발의 시작’ 등의 번역서가 출간되어 있어 레일스를 처음으로 시작하는 개발자의 어깨를 가볍게 해줄 것이다.

한글로 된 루비/레일스 관련 사이트에는 ‘루비 홈페이지', ‘한국 루비 포럼’이 있다. 특히 루비 포럼에서는 많은 루비 개발자들이 활동하고 있으므로, 루비/레일스로 개발하는 과정에서 많은 도움을 받을 수 있을 것이다.

레일스에 관한 한글 자료가 점차 늘어가고는 있지만, 아직은 영문 자료에 비해 그 양이나 다양성이 부족한 것이 사실이다. 한글 자료로 나와 있는 내용을 모두 공부했다면, 그 다음에는 구글 등을 통해 영문 자료를 참고하는 것이 필요할 것이다. 이 글의 마지막에는 도움이 될만한 영문 사이트를 정리해두었으니 참고하도록 하자.

어느 정도 레일스에 대해 익숙해지고 나면, 언젠가는 꼭 레일스 프레임워크의 소스코드를 들여다 볼 것을 권하고 싶다. 루비 코드는 가독성이 뛰어나기 때문에 이들 코드를 이해하는 것은 생각보다 어렵지 않으며, 이는 레일스를 깊이있게 이해하는 데 많은 도움이 될 것이다.

마지막으로 앞으로 루비/레일스를 공부하면서 익히는 노하우를 블로그와 포럼 등을 통해 다른 국내 개발자들과 공유할 것을 제안하면서 이 글을 마치고자 한다.




위로


Notes

1 펄의 영문 이름은 원래 진주를 의미하는 Pearl이 될 예정이었지만, 이미 같은 이름을 가진 프로그래밍 언어가 나와 있었던 관계로 Perl로 정해졌다고 한다.
2
TIOBE 프로그래밍 커뮤니티 인덱스
3 http://www.computerworld.com/action/article.do?command=viewArticleBasic&articleId=9011969
4 함수를 정의하는 과정을 자동화시키는 것은 루비의 동적 특성 때문에 가능하다. 이처럼 함수를 자동으로 정의해주는 코드를 작성하는 작업을 흔히 메타프로그래밍이라고 부른다.


참고 자료

  1. 레일스 공식 블로그
  2. 레일스 API
  3. 레일스 위키
  4. 레일스 메일링 리스트
  5. 루비 메일링 리스트
신고

'Ruby on Rails' 카테고리의 다른 글

루비 온 레일스 학습 가이드  (0) 2007.04.05
Ruby vs Python  (0) 2007.03.10
Posted by Real_G