[Draft] YongJoon.Net 작성기

Yesod를 이제부터 만들려고 하는 서비스에 사용할 생각이다.
하지만 갑자기 만들려고 해도 공부한 것이 없고, 조금밖에 모르는 상황에서 만들면 나중에 몇번씩 처음부터 고쳐써야 할 것이다.

뭐 그것도 좋은 공부가 되기는 하겠지만, 서비스의 운영에는 치명적이다.

그렇기에 기술적 난이도가 간단한 page부터 만들어 가면서 Yesod를 익혀보려고 한다.
그 첫걸음으로써 조용준 개인의 공식 page인 YongJoon.Net을 작성해보려고 한다.

0. 요구되는 기능

국제화 – Internationalization – I18n

YongJoon.Net은 연구원으로써 필요한 정보를 공개하기 위한 page이다.
지금 연구를 하고 있는 곳은 일본이고 논문을 공개하는 곳은 국제 학회이기 때문에,
최소한 영어와 일본어로 된 page는 필요하다.
나중에 취업하는데도 필요할지 모르니까 한글 page도 만들어야 하고.

처음에는 급한데로 HTML code를 직접 써서 만들었지만, page구조를 바꾸려고 하면 똑같은 수정을 각 언어별 페이지에 적용해야 한다는 사태가 발생한다.
내용을 고칠때는 어짜피 각 언어별로 작성해야 하니까 더 간단하게 고칠 방법은 없지만,

그렇다면, 동일한 구조에 들어갈 내용만 언어별 page에 넣어 줄 기능이 있다면 편리할 것이다.

작게는 이런 문제를 해결해주기 위해서 web framework가 있는 것이 아닐까?

Front

위의 국제화 기능과 연관된 문제로, 사용자의 언어에 따라서 각 언어별 page를 불러오는 기능이 필요하다.
현재는 Apache의 rewrite_mod를 사용해서 언어별로 준비된 HTML file을 불러오도록 하고 있다.

Yesod를 이용하면 실제로 존재하지 않는 언어별 HTML file을 동적으로 생성할 것이다.
물론 static page에 대해서는 cache를 만들어주는 기능도 어딘가에 있을 것이다.

1. 무작정 시작하기

시작하기 전에, Yesod project를 하나 만들어두자.
Yesod 첫걸음에서도 간단히 설명하고 있지만,
일단 yesod init를 실행해서, Project nametest로 하자.

마지막의 설명에 cd test && cabal sandbox init && cabal install --enable-tests . yesod-platform yesod-bin --max-backjumps=-1 --reorder-goals && yesod devel와 같이 실행하도록 쓰여있지만,
이걸 실행하면 엄청나게 오래 걸리기 때문에 추천하지 않는다.
물론, 설명대로 실행하는 것이 Cabal package를 망가뜨리지 않기 때문에 안전하지만,
그냥 yesod devel을 실행하는 것만으로는 문제가 발생하지 않으니까 괜찮다.

먼저 원본을 보자.
원래는 tab이 들어있었지만, Hamlet을 위해1 다 space로 치환했다.

일단 Hamlet의 기술법에 따라서 <body> ... </body>안의 내용을 반쪽짜리 tag로 고쳐써 보았다.

한번 해보고서 안 것인데, 들여쓰기를 할때 space를 두개씩 넣으면 너무 길어지고,
그렇다고 한개씩 넣으면, 구조적인 포함관계를 까먹게 된다.
<section>이나 <div>와 같은 전체적 구성에 관한 tag에만 두개씩 넣고, 나머지는 한개씩 넣는 것이 좋을지도 모르겠다.

이 내용을 templates/homepage.hamlet file에 집어넣으면 compile되어 결과물이 나온다.
거의 의도한대로 내용물이 완성되었지만, 염려하고 있던 3가지 문제중 2가지가 발생했다.

발생한 문제들

주석(<!-- ... -->)이 사라졌다.

이건 별로 치명적인 문제는 아니다.
주석은 작성하는 사람이 읽기 위한 내용이기 때문에, 사용자에게 전송할 HTML code에는 포함되어있지 않아도 아무런 문제는 없다.

다만, 혹시 남기고 싶을 경우에는 다른 방법을 사용해야 한다.

<code> ... </code>안의 개행이 없어졌다.

이건 좀 심각한 문제이다.
<code>는 그 안에 포함된 내용을 그대로 표현하기 위한 tag이다.
그런데 개행이 되어있어야 할 부분이 그냥 한줄로 쭉 표시되고 있다.
게다가 Yesod가 적용한 CSS때문인지 한줄로 표시된 데에다, 글씨는 빨간색으로 바뀌어있다.
물론 개행이 되어있어도 표시할때는 개행을 무시하지만, 가능한 한 개행이 되어있는 부분에서는 wrapping을한다.

HTML code상에는 의도한대로 표시되어 있다. 다만, 전체를 ""으로 묶어놓고 있었다.
이게 표준적 기법인가?
덕분에 오른쪽에 보여야 할 사진까지 보이지 않는다.

문제는, 기본으로 제공되고 있는 static/css/bootstrap.css file에 있었다.

986행을 보면, white-space: nowrap이라고 쓰여 있다.
이 부분 때문에 <code> ... </code>를 개행없이 쭉 표시하고 있었던 것이다.

이것만 삭제하니까 의도하던대로 표시되었다.

물론 원래 사용하던 CSS file내용을 /static/css/bootstrap.css에 집어넣으니까 역시 아무런 문제가 없다.
다만, /static/css/normalize.css의 내용이 일부 적용되고 있는지, title이 중간으로 정렬된다.

<header>가 두개

<body> ... </body>안의 내용은 Homepage.hamlet에서 전부 나오는 줄 알았는데, 그렇지 않았나 보다.
생성된 file을 보면, 아무런 내용이 들어있지 않은 <header></header>와 같은 code가 들어있다.

Static file – 사진을 넣어보자.

원래의 HTML code에 있는 사진의 경로는 img/profile.yongjoon_joe.jpg이다.
이번에는 Homepage.hamlet만 수정했으므로, 당연히 사진 file은 들어있지 않다.

사진과 같은 file들은 어디어 넣어야 할까?
생성된 code를 살펴보면 hint가 있을 것이다.

CSS file이 어디에 있는가 살펴보면, static/css/*.css에 있다.
Yesod project directory안에도, static/css/*.css가 있으니,
적당히 Yesod project directory에 사진 file을 놓으면 될 것 같다.

하지만, 단순히 img directory를 만들고서 profile.yongjoon_joe.jpg를 놓아도 표시되지 않는다.
실행해둔 warp server도 다른 file들은 잘 찾는데, 사진 file만 못 찾는다.
당연히 이것저것 Yesod project가 만들어 둔 directory들이 잔뜩 있으니까, 지정한 directory 이외에서는 file을 찾지 않는지도 모른다.
그러면, 어떻게 directory를 등록할 수 있을까?

설정을 찾아보면 그럴싸한 것이 있을 것 같으니까 /config directory를 살펴보았다.
route라는 file이 있었는데, 여기에서 설정을 하면 될 듯 하다.

보자마자 느낄 수 있지만, 단순히 /img만 추가하면 끝나는 게 아니라 먼가 이것저것 추가해야 할 것 같다.
CSS file과 비슷할테니까 비슷하게 작성해보자.

아직 내용을 살펴보지 않아서 모르겠지만,

  • ImgR을 만들어야 할 것 같다.
  • Static은 쓸 수 있을 것 같지만, 확인은 해봐야겠다.
  • getStatic도 쓸 수 있을 것 같지만, 역시 확인은 해봐야겠다.

File 내부를 검색해보니, StaticR은 특별히 정의되어 있지는 않다.
그렇다면, ImgR을 만들 필요는 없을 것 같고,

이라고 쓰는 것만으로도 충분할 것 같다.

실행해보니,
Multiple declarations of `StaticR’
Declared at: Foundation.hs:38:1
Foundation.hs:38:1
와 같은 에러를 발생시킨다.

역시 ImgR을 만들어야 하나보다.

으로 실행해보니, 실행은 되는데 역시 사진 file은 불러들이지 못한다.

그럼 역시 Static이라고 쓰여져 있는 부분을 다 읽어봐야 될 것 같다.

관련된 file들은
* /config/routes
* /Foundation.hs
* /Settings.hs
* /Settings/StaticFiles.hs
4개이다.

먼저 /Settings.hs를 읽어보니, 주석에 필요한 내용이 다 쓰여있다.

24,25행의 내용과, 40,41행의 내용을 복사해서 추가하면 될 것 같다.

다음과 같이 써보자.

한가지 걱정되는 것이, imgRoot의 type을 설정하는 부분인데, 아무리 생각해도 사진 file을 Text로 취급하는 것은 좋지 않은 선택일 것 같다.
일단 실행해보고 나자.

다음에 /Settings/StaticFiles.hs를 살펴보자.

보면 알겠지만, 6행의 내용을 하나 더 추가해야 할 것 같다.
또, 12,13행, 20행의 내용도.

여기까지 수정하고 나니, 20행의 $(staticFiles Settings.staticDir)을 어떻게 처리해야 할 지 모르겠다.
틀린 것 같지만, 그냥 한번 더 추가했다.

절차적 언어라면, 이렇게 해도 되겠지만, 함수형 언어에서는 이런 식으로 추가해도 아무런 의미도 없을텐데.

일단은 compile됬으니까 새로 고침 해보면, 여전히 찾지는 못한다.

역시 /Foundation.hs도 고쳐야 할 것 같다.

조금 고쳐봤지만, 실패.

좀 더 알아봐야겠다.

어쩔 수 없이, /img/profile.yongjoon_joe.jpg file을 static directory에 옮기니까 일단 사진은 표시된다.

국제화

일단 HTML은 표시 할 수 있게 되었으니 국제화를 실험해보자.

먼저 *.msg file을 만들어보자.
/messages directory를 살펴보면 /messages/en.msg라는 file이 있는 것을 알 수 있다.
여기에 들어있는 Hello를 어디에서 사용했는가 하면, 원래의 내용의 _{MsgHello}에서 사용한 것 을 알 수 있다.2

이건 상당히 단순한 작업이니 설명은 생략한다.

Homepage.hamlet file:

en.msg file:

똑같이 ja.msgko.msg를 작성했다.

다음에, 어떻게 언어 인식 기능을 활성화 할 수 있을까 생각하고 있었는데, 아무런 설정을 안해도 한글 page가 떴다.
하지만, 어떻게 하면 다른 언어 page를 볼 수 있을까가 과제로 남았다.
원래는 Apache가 언어를 인식해서 실제로 존재하는 index-en.htmlindex-ko.html를 보여주도록 되어 있었기 때문에 link로 선택할 수 있었다.

일단, link로 선택하는 방법은 모르겠지만, Yesod 본가의 tutorial을 참고하기로 했다.
제목이 Blog: i18n, authentication, authorization, and database인 만큼,
무언가 hint가 있을것이라고 생각하고, 일단 실행해 보았다.

Link는 아니지만, pull-down menu로 언어를 선택할 수 있게 되어있다.
좀 더 간편한 interface를 만들고 싶지만, 당장 작동하는 page를 만들고 싶으므로 일단 가져오기로 했다.

Foundation.hs에 다음과 같은 code를 추가.

homepage.hamlet의 마지막에 다음과 같은 code를 추가

마지막으로 config/routes에 다음과 같은 code를 추가

하면, 무사히 언어 선택이 가능한 page가 생성된다.

message를 사용한 것으로 인한 추가적인 기능으로 sanitization 처리가 이루어졌다.
HTML의 규칙대로라면 &&amp;로 써야 한다.
하지만 Hamlet안에 &을 써넣었을 경우에는 그대로 &이 나오는데,
ko.msg안에 써놓은 &은 제대로 &amp로 처리되어 나온다.

<head>,<header>의 수정.

이건 단순한 문제였는데, <head><header>Homepage.hamlet에 들어있는게 아니라,
default-layout-wrapper.hamlet에 들어있었던 것이 문제였다.

단순하게 default-layout-wrapper.hamlet를 수정하는 것으로 해결

<?php>는 뭐냐?

최종 단계 – Deploy

Page가 일단 완성되었으니 server에 올려보자.
이 단계에서 꽤 고생했지만, 어떻게 성공했다.

Apache proxy 설정

Yesod 첫걸음에서 한번 설명했지만,
Apache를 reverse proxy로 사용하는 방법을 설명한다.

Yesod 내부에서 사용하고 있는 Warp를 사용하는 경우에는 Apache 설정의 단계를 넘기고서,
config/settings.yml의 port를 http web server용으로 사용하면 된다.
보통 80번이니까, 3000 대신 80으로 바꾸기만 하면 된다.

그럼 Apache 설정을 살펴보자.

위에서 작성한 page만을 사용하는 경우에는, /etc/apache2/sites-enabled/000-default

와 같이 설정한다.
혹여 000-default가 아닐지도 모르지만, 설정을 바꾸지 않았다면 000-default일 것이다.

Binary 작성

일단, 작업 directory, 이를테면 /Yesod/test/로 이동해서,
cabal clean
cabal configure
cabal build
로 binary가 만들어진다.

Binary는 /Yesod/test/dist/build/test/test에 있다.

꼭 주의할 점은, 위의 command만으로는 필요한 library가 저절로 설치되지 않는다는 점이다.
꼭 미리 필요한 library가 설치되어있는지 확인하자.

Desktop에서 test할 때는 특별히 신경쓸 필요는 없지만, server에 code를 전송하면 저절로 compile/deploy하는 경우에는 신경써야 할 부분이다.

Service 등록하기

그럼, Linux에서 자동으로 실행되도록 설정해보자.
최근의 Linux distribution 이라면 upstart를 사용하고 있을테니까, 이용하기로 한다.

먼저, 설정 파일부터 만들자.

/etc/init/yesod-test.conf와 같은 파일을 만들고 다음과 같은 내용을 넣는다.

이것으로 server를 재시작하면 작동할 것이다. 아마도.

당장 실행해보기 위해서는
initctl reload-configuration
initctl start yesod-test

를 해보면 실행될 것이다.

사용하고 있던 servre가 느려서 그랬는지 실행시킨 다음에 page를 볼 수 있을 때까지 상당히 시간이 걸렸다.
동작하는지 확인할 때는 2~3분 정도 기다려 보는것을 추천한다.
처음빼고는 1분안에 동작했다.

이외에도, Version Control System으로 갱신하면 server에서 저절로 build하고 자동으로 재시작하는 기능같은 것도 있지만,
별로 잘 만든 기능은 아니라서 설명은 생략한다.

이것으로, YongJoon.Net작성기를 끝낸다.

공부하면서, 찾아가면서, 삽질하면서, 글을 써가면서, 재설치하면서 작성했는데도 10시간밖에 안걸린 것을 보면,
이걸 보고 작성하시는 분들은 1시간쯤이면 동일한 정도의 page를 작성하실 수 있을 것이라고 생각한다.

Cabal package의존성 파탄으로 인해, 이 글을 작성하면서 Haskell Platform을 두번정도 재설치했다.
이걸 보신 분들은 꼭 Cabal 간단 manual을 보고서 조심해서 다루어주기 바란다.


  1. Hamlet에서는 tab 문자를 인식하지 않는다. 아니, 거부한다는 것이 정확할 것이다. 

  2. 프로그래밍해보신 분들은 아시겠지만, 저절로 접두어를 붙여주는 경우는 매우 드물다. 

변경 이력:

There are no revisions for this post.

CC BY-NC-ND 4.0 This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.