IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
한국 developerWorks   >   Open developerWorks  > developerworks

얼랭(Erlang) 웹 프로그래밍, Part 2: ErlyWeb을 이용한 웹 개발



김석준김석준 sjoonk@gmail.com

웹2.0과 루비온레일스 기반 소프트웨어 개발, 컨설팅을 하는 유스풀패러다임의 대표다. 한때 공직에 근무하다 어릴 적부터 해오던 프로그래밍의 맛을 잊을 수 없어 업종을 전환한 경력을 가지고 있으며, 항상 끊임없이 새로워지려고 노력 중이다. 번역한 책으로 『프로그래밍 얼랭』, 『레일스와 함께하는 애자일 웹 개발』, 『레일스 레시피』가 있다.


난이도 : 중급
2008년 6월 17일

[오픈 디벨로퍼웍스]는 여러분이 직접 필자로 참가하는 코너입니다. 이번 회에서는 얼랭 기반 웹 개발 프레임워크 중 하나인 얼리웹(ErlyWeb)을 소개합니다.

이번 회에서는 얼랭 기반 웹 개발 프레임워크 중 하나인 얼리웹(ErlyWeb)을 소개한다. 얼리웹은 Yariv Sadan이 2006년부터 만들어 오고 있는 오픈 소스 웹 개발 프레임워크로서, 지난 회에 소개한 바 있는 Yaws(웹 서버)와 연동하여 Yaws의 애플리케이션 모듈로 작동한다. 루비온레일스나 스트럿츠 같은 많은 웹 프레임워크와 마찬가지로 얼리웹 역시 MVC 아키텍처를 채택하고 있으며, 특히 고가용성 무정지 시스템을 만들 때 사용하는 Erlang/OTP 라이브러리의 장점을 이용하는 점이 특징이다. 얼리웹의 주요 구성 모듈은 다음과 같다.

  • erlyweb: 다른 구성 모듈들을 조율하고 Yaws와의 인터페이스를 담당하는 얼리웹의 메인 모듈
  • erltl: 얼리웹 뷰에서 사용하는 템플릿 언어 모듈
  • erlydb: 데이터베이스 액세스 함수를 생성하고 데이터베이스 추상화를 담당
  • erlydb_mnesia, erlydb_mysql, erlydb_psql: 데이터베이스 드라이버 모듈
  • smerl: 얼랭으로 작성한 메타 프로그래밍 라이브러리. 얼리웹의 동적 코드 생성에 사용

백문이 불여일견이니 간단한 웹 애플리케이션을 하나 만들면서 주요 개념을 설명하겠다. 우선 얼리웹 사이트에서 얼리웹을 다운로드해 얼랭 라이브러리에 추가하자. 얼리웹이 Yaws 기반에서 작동하는 관계로 Yaws 역시 설치해야 하지만, 이 부분은 지난 회에 이미 설명했으니 생략한다.


새 애플리케이션 생성하기

그럼 얼리웹 애플리케이션을 하나 작성해 보자. 게시글과 댓글이 있는 간단한 게시판을 하나 만들어 보기로 한다. 우선 작업 디렉터리에서 erl 셸을 열고 다음 명령을 주어 얼리웹 애플리케이션을 하나 생성하자. 애플리케이션 이름은 erlyboard라고 주었다.

1> erlyweb:create_app("erlyboard", ".").

그러면 작업 디렉터리 아래에 다음과 같은 구조의 얼리웹 애플리케이션 디렉터리가 만들어진다. 이 디렉터리 중 src 디렉터리가 바로 우리가 만들 얼리웹 모듈들이 들어갈 디렉터리이며, www는 이미지나 css 파일, html 파일 등이 들어가는 곳이다. ebin은 컴파일된 코드들이 담기는 디렉터리다.

erlyboard / + ebin / + src / + components / + erlyboard_app_controller.erl + www /

이제 애플리케이션을 생성했으면 erl 셸에서 빠져 나와 yaws.conf 파일을 설정하자. 얼리웹이 Yaws의 애플리케이션 모듈로 작동하므로 이 작업은 꼭 해야 한다. yaws.conf를 열어 다음과 같이 작성하면 된다.

<server localhost> port = 8000 listen = 0.0.0.0 docroot = /home/sjoonk/works/erlyboard/www appmods = </, erlyweb> <opaque> appname = erlyboard </opaque> </server>

그런 다음 yaws -i 명령으로 Yaws를 띄우고, erlyweb:compile/1 또는 erlyweb:compile/2 함수를 호출하여 코드를 컴파일하고 나면, http://localhost:8000/으로 접속하여 애플리케이션이 제대로 작동하는 것을 확인할 수 있을 것이다. 이것으로 골격은 갖춘 셈이 된다. 참고로 필자가 사용한 컴파일 명령은 다음과 같다({auto_compile, true} 옵션을 주면 이후 소스코드가 변경될 때마다 자동 컴파일이 되기 때문에 개발환경에서 적합한 옵션이다).

1> erlyweb:compile("erlyboard", [{erlydb_driver, mysql}, {auto_compile, true}]).;



위로


컴포넌트 추가하기

얼리웹은 컴포넌트 기반 프레임워크다. 즉, 컴포넌트(component)가 얼리웹의 중심에 있다는 말이다. 그렇다면 컴포넌트란 무엇일까? 얼리웹에서 말하는 컴포넌트는 MVC 아키텍처의 컨트롤러와 뷰, 그리고 모델을 하나의 단위로 묶은 것이다. 얼리웹이 MVC 구조를 취하긴 하지만, 얼리웹의 모든 동작은 이 컴포넌트를 중심으로 이루어지며, 따라서 컴포넌트가 모든 렌더링과 코드 재활용의 기본 단위가 된다.

지금 만드는 게시판 프로그램에서는 세 개의 컴포넌트를 사용할 것인데, 그 컴포넌트는 각각 board, post, comment라고 이름을 주기로 하자. 이 컴포넌트들은 하나의 컴포넌트에서 다시 다른 컴포넌트들을 호출하는 중첩 구조다. 얼랭이 함수형 언어라는 점을 상기한다면 이런 식의 접근은 자연스럽다. 우리가 만들 애플리케이션의 전체 구조는 다음 그림과 같다.

애플리케이션의 전체 구조

그럼 우선 board 컴포넌트부터 작성하자. yaws 셸에서 다음 명령을 주면 컴포넌트의 스캐폴드(scaffold)가 생성된다.

2> erlyweb:create_component("board", "./erlyboard").

그러면 src/components 디렉터리 아래에 board_controller.erl, board_view.erl, board.erl이라는 세 개의 파일이 생성되었음을 알 수 있다. 이 파일들은 각각 board의 컨트롤러, 뷰, 그리고 모델 역할을 담당하는 모듈들이다. 같은 방법으로 post와 comment 컴포넌트도 생성하면 된다.




위로


데이터베이스와 모델

대부분의 웹 애플리케이션은 결국 데이터베이스를 액세스하는 것이 주요 목적이며, 얼리웹 애플리케이션 역시 다르지 않다. 다만 얼리웹에는 ErlyDB라고 하는 데이터베이스 액세스 모듈이 있어서 번거로운 데이터베이스 처리 작업을 쉽게 해 준다. 우선 간단한 데이터베이스 스키마부터 작성하고, 데이터베이스를 생성하여 테이블을 추가하자. 여기서는 1:다 관계로 연관되는 post와 comment 테이블을 만들기로 한다(만드는 법은 지면 관계상 생략한다). Yaws 셸에서 간단하게 데이터베이스 처리를 테스트해 볼 수 있다. 다음은 몇 가지 예다.

3> post:new(). % 새로운 포스트 레코드를 하나 생성한다. 4> post:save(). % 포스트를 저장한다. 5> Post = post:find_id(3). % id가 3인 포스트를 추출하여 Post 변수에 할당한다. 6> post:title(Post). % Post의 title값을 반환한다. 7> post:comments(Post). % Post의 모든 comment를 반환한다.

앞서 create_component를 통해 생성된 모듈 중 board.erl, post.erl, comment.erl이 바로 모델(model)이었다. 얼리웹에서는 components 디렉터리에 들어있는 모듈들 가운데 XXX_controller와 XXX_view가 아닌 모든 모듈을 모델로 인식한다. 따라서 모델이 아니라면 반드시 삭제해야 한다. 우리의 경우 board는 컴포넌트이긴 하지만 모델은 필요가 없다. 따라서 생성된 파일에서 board.erl은 삭제해야 한다.

그럼 모델 파일을 하나 열어보자. 다음은 post.erl 모델의 내용이다. 보는 바와 같이 간단하다. 아니, 실은 아무 것도 없다고 해야 맞다.

-module(post).

이처럼 모델 모듈 속에는 아무런 코드도 없지만, 앞서와 같은 다양한 데이터베이스 액세스 함수를 호출할 수 있는 이유는 얼리웹이 컴파일 시에 동적으로 erlydb_base 모듈의 함수들을 확장해 주기 때문이다. 그리고 이 때 사용되는 모듈이 바로 얼리웹에서 메타 프로그래밍을 처리하는 smerl 모듈이다.




위로


URL 매핑과 컨트롤러 함수

얼리웹의 URL 매핑 관례는 간단하다. 만약 http://yourhome.com/board/show/1/2/3과 같은 URL로 호출을 할 경우, 얼리웹은 board 컨트롤러에 있는 show 함수를 호출하며, URL의 나머지 매개변수 값들은 호출하는 함수의 매개변수로 전달된다. 이 때 만약 URL을 http://yourhome.com/board와 같이 주어 호출 함수를 생략하면 자동으로 index 함수를 호출한다. 이런 방식의 관례를 벗어나는 접근이 필요한 경우라면 컨트롤러에서 catch_all/2 후크 함수를 만들어 처리하면 된다. 자세한 내용은 매뉴얼 문서를 참조하자.

그럼 이제 board 컴포넌트를 만들어 보자. http://localhost:8000/board라고 했을 때 게시판에 게시글 목록이 나오도록 하려고 한다. board_controller.erl 파일을 열어 아래와 같이 index/1 함수를 만들면 된다.

index(A) -> Posts = post:find(), lists:map(fun(Post) -> {ewc, post, [A, Post]} end, Posts).

이 함수는 post 테이블에서 모든 post를 읽은 다음, 이들 각각의 post에 대해 루프를 돌면서 {ewc, ... }라는 튜플의 리스트를 반환한다. 여기서 A는 Yaws에서 전달받은 Arg 매개변수다. 이 때 {ewc, ...} 튜플은 얼리웹 컨트롤러 함수에서 사용하는 반환값 중 하나다. 얼랭이 함수형 언어인 관계로 모든 함수는 반환값을 가지며, 얼리웹은 이 반환값을 적절하게 처리한 다음 그 결과를 다시 Yaws로 보내는 것이다.

얼리웹이 Yaws의 애플리케이션 모듈로 작동하므로, 반환값 역시 Yaws가 받을 수 있는 모든 값을 받을 수 있지만, 특별히 얼리웹에서는 몇 가지 기본적인 반환값을 설정해 쉽게 사용할 수 있도록 하고 있다. 다음은 얼리웹 컨트롤러 함수에서 사용하는 주요 반환값들이다.

반환값 설명



위로


얼리웹 템플릿과 뷰

컨트롤러를 작성하였다면 이번에는 뷰를 만들자. 얼리웹의 뷰는 두 가지 방식으로 만들 수 있다. 우선 일반적인 얼랭 모듈로 작성할 수 있다(이 경우는 확장자가 .erl이다). 또 한 가지 방법은 ErlTL이라는 템플릿 언어를 사용하여 작성하는 것이며 이 때는 확장자가 .et다. 통상적으로는 이 템플릿 파일을 사용하여 작성하는 경우가 많기 때문에 여기서도 템플릿 파일을 사용하여 작성하겠다.

다음은 board_view.et 파일의 내용인데, <%@ index(Data) %> 부분에서 앞서 컨트롤러 함수에서 반환한 {data, Data}의 값을 받아 처리하도록 되어 있음을 알 수 있다. 템플릿 자체는 PHP, JSP 등 여타 템플릿들과 크게 다르지 않기 때문에 설명을 생략한다.

<%@ index(Data) %> <h3>최근 게시물</h3> <p><table> <% Data %> </table></p> <a href="/post/new">새글 작성</a>



위로


게시판 완성하기

이제 컴포넌트와 모델/컨트롤러/뷰 같은 얼리웹의 기본 개념에 대한 설명을 마쳤으니, 게시판의 나머지 부분을 완성해 보자. 다음은 게시판의 메인 컴포넌트라고 할 post 컴포넌트의 컨트롤러 파일이다. 코드 내용은 간단하므로 지면 관계상 설명은 생략하기로 한다.

-module(post_controller). -compile(export_all). index(A, Post) -> {data, [integer_to_list(post:id(Post)), post:title(Post)]}. show(A, PostId) -> Post = post:find_id(PostId), [{data, Post}, [{ewc, comment, [A, Comment]} || Comment <- post:comments(Post)]]. new(A) -> {data, []}. delete(A, PostId) -> Post = post:find_id(PostId), post:delete(Post), {ewr, board}. create(A) -> Values = yaws_api:parse_post(A), Post = post:set_fields_from_strs(post:new(), Values), post:save(Post), {ewr, board}. add_comment(A, PostId) -> Values = yaws_api:parse_post(A), Comment = comment:set_fields_from_strs(comment:new(), Values), comment:save(Comment), {ewr, post, show, [PostId]}.

다음은 post_view.et 파일의 내용이다.

<%@ index([PostId, Title]) %> <tr> <td><%! PostId %></td> <td><a href="/post/show/<% PostId %>"><% Title %></a></td> </tr> <%@ show([Post, Comments]) %> <%? PostId = integer_to_list(post:id(Post)) %> <h2><% post:title(Post) %></h2> <p><% post:body(Post) %></p> <a href="#">수정</a> | <a href="/post/delete/<% PostId %>">삭제</a> <h4>댓글(<% integer_to_list(post:count_of_comments(Post)) %>)</h4> <ul><% Comments %></ul> <p> <h5>댓글 추가</h5> <form action="/post/add_comment/<% PostId %>" method="post"> <label for="author">작성자:</label><br/> <input type="text" name="author" id="author"/><br/> <label for="body">댓글:</label><br/> <textarea name="body" id="body" rows="2" cols="40"></textarea><br/> <input type="hidden" name="post_id" value="<% PostId %>"/> <input type="submit" value="완료"/> </form> </p> <a href="/board">목록보기</a> <%@ new([]) %> <h4>새글 작성</h4> <p> <form action="/post/create" method="post"> <label for="title">제목:</label><br/> <input type="text" name="title" id="title" size="50"/><br/> <label for="body">본문:</label><br/> <textarea name="body" id="body" cols="50" rows="5"></textarea><br/> <input type="submit" value="만들기"> <a href="/board">취소</a> </form> </p>

이 외에도 comment 컴포넌트의 컨트롤러와 뷰도 있어야 하지만, 역시 지면 관계상 생략하니 독자들이 직접 작성해 보기 바란다. 이렇게 하여 완성된 최종 게시판의 모습은 아래 그림과 같다.

최종게시판

이것으로 이번 회의 내용을 마친다. 가급적 얼리웹의 기본 개념을 쉽게 설명하려고 했지만 지면 관계상 충분히 전달되지 못한 부분도 있을 것 같다. 이 글에서 사용한 소스코드 또는 이 글과 관련한 문의가 있는 독자는 이메일로 연락을 주길 바라며, 아울러 최근에 얼리웹을 만든 Yariv가 Twoorl이라는 Twitter 클론을 얼리웹으로 작성하여 오픈 소스로 공개하였으니 관심 있는 독자는 그 코드를 살펴보면 얼리웹을 이해하는 데 많은 도움이 될 것이라는 점도 말해 둔다. 다음 회에서는 얼랭과 REST, 그리고 MochiWeb 등 얼랭 웹 프로그래밍의 다른 주제들에 대해 알아보기로 한다.



참고자료




위로


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us

이제 전문가의 글을 단순히 ‘보는 것’에서, 직접 여러분이 developerWorks의 필자가 될 수 있습니다. IBM developerWorks를 통해 공유하고 싶은 지식이 있으신 분들은 원고 기획안을 접수해주세요. 채택되신 분께는 소정의 원고료를 드립니다.



[지난 Open dW 보기]
사이트 여행

dW 커뮤니티
포럼 | 블로그 | Spaces
dW Student Community

로컬 컨텐츠

행사 및 세미나

기획 기사

개발자 입문

튜토리얼 및 교육

TOP 10 인기자료

SW 다운로드

RSS 피드

뉴스레터
 
  
자바스크립트가 작동이 중지되었습니다. 이 기능을 수행하시려면 브라우저에서 자바스크립스트를 작동시켜 주시거나 이곳을 클릭해주세요.

Special offers
Screencast
IBM SOA Sandbox 시험판
dW Student Community
로보코드
코드 트레이닝


    IBM 소개 개인정보 보호정책 문의