<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>유스풀패러다임</title>
 <link href="/" rel="self"/>
 <link href=""/>
 <updated>2021-11-05T02:09:23+00:00</updated>
 <id></id>
 <author>
   <name>Useful Paradigm</name>
   <email>contact@usefulparadigm.com</email>
 </author>

 
 <entry>
   <title>Jekyll 테마(Theme) 다루기</title>
   <link href="/2018/04/30/using-jekyll-themes/"/>
   <updated>2018-04-30T00:00:00+00:00</updated>
   <id>/2018/04/30/using-jekyll-themes</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2018/using-jekyll-themes_featured.jpg&quot; alt=&quot;featured&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://jekyllrb.com/&quot;&gt;지킬(Jekyll)&lt;/a&gt;은 정적 웹사이트 빌더(static site builder) 도구입니다. 간단하게 웹사이트나 블로그를 만들 때 유용하게 사용할 수 있죠. Jekyll은 워드프레스나 여타 다른 웹사이트 빌더들에 비해 몇 가지 장점이 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;사용법이 간단&lt;/li&gt;
  &lt;li&gt;마크다운(Markdown) 기반&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt;에서 무료 호스팅 지원&lt;/li&gt;
  &lt;li&gt;다양한 테마 및 플러그인, 편집기(editor) 생태계 보유&lt;/li&gt;
  &lt;li&gt;확장 가능한 테마 시스템&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 글에서는 이 중 Jekyll의 테마 시스템과 그 사용법을 소개합니다.&lt;/p&gt;

&lt;h2 id=&quot;아주-간단한-테마&quot;&gt;아주 간단한 테마&lt;/h2&gt;

&lt;p&gt;앞서도 말했듯 Jekyll은 정적인 웹사이트 빌더입니다. 그러니 실은 HTML파일만 있으면 됩니다. 여기에 CSS로 약간의 스타일링을 추가하면 더 좋겠죠.&lt;/p&gt;

&lt;p&gt;아무 디렉터리나 하나 골라 다음과 같이 간단하게 index.html 파일을 하나 만들고  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll serve&lt;/code&gt; 명령을 줍니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;title&amp;gt;Hello Jekyll&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  
  &amp;lt;h1&amp;gt;Hello, Jekyll!&amp;lt;/h1&amp;gt;
  
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그런 다음 Jekyll 서버 기본 포트인 4000번 포트로 접속하면 다음과 같이 웹사이트가 작동합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2018/using-jekyll-themes/DDFA94A7-0425-4FA2-917A-E4CFB41B8EC3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;방금 전 만든 디렉터리에 가보면 아래와 같이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_site&lt;/code&gt;라는 이름의 디렉터리가 하나 자동으로 추가된 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2018/using-jekyll-themes/AC03CA69-50E6-42D0-921D-22FC012AB8FD.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이처럼 Jekyll은 실행 시점에서 필요한 리소스 파일들을 컴파일하여 디폴트로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_site&lt;/code&gt; 라는 디렉터리 아래에 둡니다. 이 디렉터리가 실제로 우리가 웹 상에서 보게되는 파일들이 위치하는 디렉터리입니다. (흔히 “public 폴더”라 부르는 곳인 셈이죠)&lt;/p&gt;

&lt;p&gt;이제 간단한 페이지를 하나 추가해 보겠습니다. 파일명을 about.md 라고 주고 이번엔 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pages&lt;/code&gt; 라는 하위 디렉터리를 하나 만들어 그 속에 두겠습니다.  (이 때 파일 앞 부분에 빈 &lt;a href=&quot;https://jekyllrb.com/docs/frontmatter/&quot;&gt;Front Matter&lt;/a&gt; 영역을 둔 이유는 이렇게 해야만 Jekyll이 md 파일을 html로 변환하기 때문입니다. Jekyll은 Front Matter가 있는 모든 파일들을 대상으로 변환 처리를 합니다)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
---
# About Us

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quod dicit Epicurus etiam de voluptate, quae minime sint voluptates, eas obscurari saepe et obrui. Hic, qui utrumque probat, ambobus debuit uti, sicut facit re, neque tamen dividit verbis.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;마찬가지로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll serve&lt;/code&gt; 명령을 실행한 후 웹 브라우저에서 접속해 보면 다음과 같이 마크다운 파일이 html로 변환되어 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_site/pages&lt;/code&gt; 디렉터리 아래에 놓여 있음을 알 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2018/using-jekyll-themes/8C783528-00E0-493B-9456-CE93D4B8B625.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이런 식입니다. Jekyll은 프로젝트 폴더 내의 파일들을 Jekyll의 관례와 규칙에 따라 해석하여 최종적으로 정적인 웹사이트를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_site&lt;/code&gt; 디렉터리에 생성합니다. 이게 전부입니다.&lt;/p&gt;

&lt;h2 id=&quot;루비-젬-기반-테마gem-based-themes&quot;&gt;루비 젬 기반 테마(gem-based themes)&lt;/h2&gt;

&lt;p&gt;Jekyll 3.2 버전부터는 새로 젬 기반 테마(gem-based theme)라는 개념이 도입되었습니다. 이 개념이 나오기 전까지는 Jekyll에서 다른 사람이 만든 테마를 가져다 쓰려면 앞서와 같이 프로젝트 디렉터리에 테마 파일 전체를 복사해 넣고 수정하는 방식으로 테마를 관리하는 방법 밖에 없었습니다.&lt;/p&gt;

&lt;p&gt;젬 기반 테마의 경우, 테마 파일이 루비 젬(gem) 패키지 파일 형태로 배포되기 때문에 이 테마를 가져다 쓸 사람들은 일일이 복사하여 넣을 필요 없이 루비 젬 설치 명령으로 해당 테마 파일을 설치하면 바로 테마가 작동합니다.&lt;/p&gt;

&lt;p&gt;이는 마치 워드프레스 테마 시스템과 유사합니다. 워드프레스에서는 &lt;a href=&quot;https://codex.wordpress.org/Child_Themes&quot;&gt;자식테마(Child Theme)&lt;/a&gt; 개념을 지원해서 부모 테마를 상속받고 필요한 부분만 수정하여 사용하는 방식을 제공하며 또 권장되기도 합니다. Jekyll의 젬 기반 테마는 이 자식테마와 유사한 개념입니다.&lt;/p&gt;

&lt;p&gt;그럼 이번엔 젬 기반 테마 방식으로 테마를 한번 설치해 보겠습니다.&lt;/p&gt;

&lt;p&gt;흔히 Jekyll 사이트를 새로 만들 때는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll new&lt;/code&gt; 명령을 사용하지만, 여기서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll new&lt;/code&gt; 명령 대신, 앞서 만들던 지점에서 이어나가 보기로 하겠습니다. (참고로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll new&lt;/code&gt; 명령으로 생성되는 사이트는 &lt;a href=&quot;https://github.com/jekyll/minima&quot;&gt;Minima&lt;/a&gt;라는 젬 기반 테마를 디폴트로 설치합니다)&lt;/p&gt;

&lt;p&gt;여기서는 &lt;a href=&quot;https://mmistakes.github.io/minimal-mistakes/&quot;&gt;Minimal Mistakes&lt;/a&gt;라는 테마를 한번 설치해 보기로 하겠습니다. Minimal Mistakes는 Jekyll 테마 중 가장 인기 있는 테마 중 하나입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2018/using-jekyll-themes/65717029-B723-4657-BC77-70162C9B8E99.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;우선 터미널에서 테마 젬 파일을 설치합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ gem install minimal-mistakes-jekyll 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;설치가 완료되면 이어 프로젝트 루트 디렉터리에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt; 이라는 파일을 하나 생성하여 다음과 같이 테마를 지정합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;title: Hello Jekyll
theme: minimal-mistakes-jekyll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;마지막으로 index.html 파일을 열어 다음과 같이 변경합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
layout: home
---
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;끝입니다. 이제 다시 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll serve&lt;/code&gt; 명령을 실행한 후 브라우저에서 보면 그림과 같이 Minimal Mistakes 테마가 정상적으로 적용된 것을 확인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2018/using-jekyll-themes/797E2133-F32E-4003-A1AF-2386658C5B0C.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그럼 디렉터리 구조는 어떨까요? 궁금한 분들은 직접 한번 확인해 보시기 바랍니다.&lt;/p&gt;

&lt;p&gt;물론 모든 Jekyll 테마들이 젬 기반 테마인 것은 아니며, 이럴 경우 이전 방식(테마 파일 전부를 프로젝트 디렉터리에 붙여 넣는 방식)으로 사용할 수 밖에 없다는 점에 유의해야 합니다. 어떤 테마가 젬 기반인지 여부는 보통 해당 테마의 문서에 적혀 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;어떤-방식이-좋을까요&quot;&gt;어떤 방식이 좋을까요?&lt;/h2&gt;

&lt;p&gt;젬 기반 테마를 썼을 때 좋은 점은 무엇일까요? 무엇보다 테마 자체의 업데이트가 쉽다는 게 가장 큰 장점입니다. 테마를 별도의 젬 파일로 관리하기 때문에 테마의 업데이트가 필요할 때면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gem update&lt;/code&gt; 명령만 주면 됩니다. 또한 실제 관리하는 사이트의 파일 구조가 간단해 지는 점도 장점일테죠.&lt;/p&gt;

&lt;p&gt;그렇지만 젬 기반 테마가 반드시 장점만 있는 건 아닙니다. 일단 시중에 나와 있는 모든 테마가 다 젬 기반을 지원하는 것은 아닙니다. 그리고 테마에서 커스텀 영역이 많아질수록 젬 기반 테마가 갖는 장점은 적어 질 수 밖에 없습니다.&lt;/p&gt;

&lt;p&gt;앞서도 말했듯, 젬 기반 테마는 워드프레스의 자식테마와 개념이 비슷합니다. 반면 테마파일을 그대로 가져다 수정하는 방식은, 워드프레스로 치면 테마 파일 자체를 건드리는 방식입니다. 둘 중 어느 게 더 나은 방법인지는 사실 프로젝트의 성격에 따라 다르기 때문에 하나로 이거다 결론 짓기가 애매한 부분이 있습니다만, Jekyll 사이트라면 이렇게 말하는 게 좋을 것 같습니다: “&lt;strong&gt;젬을 제공하는 테마라면? 젬 기반으로 쓰고, 그렇지 않으면 직접 복사해서 쓰세요!&lt;/strong&gt;” 라고 말이죠!&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://jekyllrb.com/docs/themes/&quot;&gt;Jekyll Themes 공식 문서&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://mmistakes.github.io/minimal-mistakes/&quot;&gt;Minimal Mistakes Theme 문서&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jekyllthemes.io/&quot;&gt;Jekyll Themes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Hugo와 Netlify로 '스매싱' 웹사이트 만들기</title>
   <link href="/2017/11/24/building-smashing-website-with-hugo-and-netlify/"/>
   <updated>2017-11-24T00:00:00+00:00</updated>
   <id>/2017/11/24/building-smashing-website-with-hugo-and-netlify</id>
   <content type="html">&lt;p&gt;웹 디자이너와 개발자들이 즐겨 찾는 인기있는 웹사이트 중 하나인 &lt;a href=&quot;https://www.smashingmagazine.com/&quot;&gt;스매싱매거진(Smashing Magazine)&lt;/a&gt;이 최근 &lt;a href=&quot;https://next.smashingmagazine.com/2017/03/a-little-surprise-is-waiting-for-you-here/&quot;&gt;리뉴얼&lt;/a&gt; 되었습니다.&lt;/p&gt;

&lt;p&gt;이번 리뉴얼은 그간 사용해 오던 &lt;a href=&quot;https://wordpress.org/&quot;&gt;WordPress&lt;/a&gt; 대신 &lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt;라는 CMS 도구를 썼고 또 &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;라는 서비스를 이용해 호스팅한 점이 특히 눈에 띕니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;관련 글&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://discourse.gohugo.io/t/smashing-magazine-s-redesign-powered-by-hugo-jamstack/5826&quot;&gt;Smashing Magazine’s Redesign Powered by Hugo (JAMstack)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.netlify.com/blog/2017/11/21/smashing-magazine-is-now-live-on-netlify/&quot;&gt;Smashing Magazine is now live on Netlify&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 글에서는 이 둘의 사용법을 간단하게 정리해 봅니다.&lt;/p&gt;

&lt;h2 id=&quot;hugo로-웹사이트-만들기&quot;&gt;Hugo로 웹사이트 만들기&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/2CB42710-C0A1-493F-8DA0-77CA9FEB4FAB.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt;는 한마디로 정적 웹사이트 생성기(static website generator)입니다. &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;을 접해 보신 분에겐 아마 ‘Go 언어로 작성된 Jekyll’이라고 소개하는 게 더 잘 와닿을 지도 모르겠습니다. (물론 Hugo는 기분 나쁠 수 있습니다. 어디 감히 함부로 대문호의 이름을 한낱 작품 주인공 이름과 비교하다니요?)&lt;/p&gt;

&lt;p&gt;어쨌거나, Jekyll이나 Hugo 같은 웹사이트 생성기의 좋은 점은, 간단하게 웹사이트를 만들고 콘텐츠를 바로 바로 퍼블리싱 할 수 있는 구조(틀)와 도구를 제공한다는 점에 있습니다. Hugo 역시 마찬가지구요.&lt;/p&gt;

&lt;p&gt;맥OS 사용자라면 터미널 명령으로 다음과 같이 간단하게 사이트의 뼈대를 만들 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ brew install hugo
$ hugo new site hello-hugo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;성공적으로 사이트가 만들어지면, 친철하게도 Hugo가 다음 단계를 알려 줍니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Congratulations! Your new Hugo site is created in /hello-hugo.

Just a few more steps and you're ready to go:

1. Download a theme into the same-named folder.
   Choose a theme from https://themes.gohugo.io/, or
   create your own with the &quot;hugo new theme &amp;lt;THEMENAME&amp;gt;&quot; command.
2. Perhaps you want to add some content. You can add single files
   with &quot;hugo new &amp;lt;SECTIONNAME&amp;gt;/&amp;lt;FILENAME&amp;gt;.&amp;lt;FORMAT&amp;gt;&quot;.
3. Start the built-in live server via &quot;hugo server&quot;.

Visit https://gohugo.io/ for quickstart guide and full documentation.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위에서 Hugo가 알려준 대로 이제 테마를 하나 설치해 보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://themes.gohugo.io/&quot;&gt;Hugo Themes&lt;/a&gt; 디렉터리에 보면 Hugo에서 사용할 테마들이 많이 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/1447D499-FD48-47A8-B7BC-5C74641D0E7B.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;물론 테마를 직접 만들어도 되지만, 여기서는 이 디렉터리에 있는 테마 중 하나를 골라 적용해 보도록 하겠습니다. 제 취향으로 ‘&lt;a href=&quot;https://themes.gohugo.io/bilberry-hugo-theme/&quot;&gt;Bilberry Hugo Theme&lt;/a&gt;’ 테마를 선택해 보겠습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/5F41AB66-8C4A-46D4-B042-7BEF5552DE9A.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;테마를 클릭해 보면 테마에 대한 자세한 설명 및 데모(demo)와 함께 이 테마의 설치 방법 등이 자세히 소개되어 있기 때문에 그대로 따라하기만 하면 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd hello-hugo/themes
git clone https://github.com/Lednerb/bilberry-hugo-theme.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(만약 git을 사용하지 않는다면, 테마 파일을 다운로드 받아 themes 디렉터리 아래에 압축을 풀어 놓아도 상관없습니다)&lt;/p&gt;

&lt;p&gt;테마 파일을  설치했다면, 이제 마지막으로 프로젝트의 루트 디렉터리에 있는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.toml&lt;/code&gt; 파일을 열어 다음과 같이 테마를 지정해 줍니다. 방금 전 설치한 테마 파일의 디렉터리명과 일치시켜주면 됩니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;theme = &quot;bilberry-hugo-theme&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 터미널에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hugo server&lt;/code&gt; 명령으로 웹서버를 실행한 다음 브라우저에서 http://localhost:1313/ 로 접속해 보면, 다음과 같이 웹사이트가 표시되는 것을 확인할 수 있습니다. (테마의 DEMO에서 보는 것과 같은 좀 더 멋진(?) 디자인을 지금 당장 확인해 보고 싶다면, 테마 속에 들어 있는 exampleSite 폴더를 프로젝트의 루트 내로 복사하여 붙여 넣으면 됩니다)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/29A279FD-6E26-49C9-AE88-F8C392D2FD26.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;새 포스트를 추가하려면, 다음과 같이 터미널에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hugo new&lt;/code&gt; 명령으로 간단하게 추가할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ hugo new post/어서와-휴고는-처음이지.md 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 명령으로 새 포스트를 추가한 다음, 프로젝트의 content/post 폴더 아래에 가보면 방금 생성한 새 포스트 파일이 추가되어 있는 것을 확인할 수 있습니다. 파일을 열어 포스트의 내용을 적절하게 채워주면 나머지 작업은 Hugo가 알아서 처리합니다.&lt;/p&gt;

&lt;p&gt;금방 뚝딱 새 포스트가 하나 만들어 졌네요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/0CCE516E-D405-4596-9AEE-277F61DA5B75.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기까지 따라했다면, 지금까지의 내용을 &lt;a href=&quot;https://github.com/usefulparadigm/hello-hugo&quot;&gt;GitHub&lt;/a&gt;에 저장합니다. (이 단계는 나중에 배포할 때 필요한 부분이며, GitHub에 저장하기 방법에 관한 별도 설명은 생략합니다)&lt;/p&gt;

&lt;p&gt;지금까지의 내용은 Hugo의 아주 기본적인 사용법만 보인 것일 뿐, Hugo는 정말이지 그 이름에 걸맞게 멋진 기능들을 많이 갖추고 있습니다. Hugo의 더 자세한 기능과 사용법은 &lt;a href=&quot;https://gohugo.io/documentation/&quot;&gt;Hugo 문서&lt;/a&gt;를 참조하세요!&lt;/p&gt;

&lt;h2 id=&quot;netlify로-사이트-배포하기&quot;&gt;Netlify로 사이트 배포하기&lt;/h2&gt;

&lt;p&gt;대부분의 정적 사이트 생성기가 그렇듯, Hugo 역시 사이트 배포(deployment)와 관련해 &lt;a href=&quot;https://gohugo.io/hosting-and-deployment/&quot;&gt;다양한 옵션들을 제공&lt;/a&gt;합니다. (&lt;a href=&quot;https://gohugo.io/hosting-and-deployment/hosting-on-github/#deployment-from-your-gh-pages-branch&quot;&gt;GitHub Pages로 배포&lt;/a&gt;도 가능은 하지만, &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt;에 배포할 경우라면 아무래도 Jekyll을 쓰는 게 낫겠죠?)&lt;/p&gt;

&lt;p&gt;앞서도 소개했듯 최근 리뉴얼된 &lt;a href=&quot;https://www.netlify.com/blog/2017/11/21/smashing-magazine-is-now-live-on-netlify/&quot;&gt;스매싱매거진(Smashing Magazine)이 Netlify를 사용&lt;/a&gt; 하기에, 여기서도 &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;를 한번 사용해 보기로 하겠습니다. (사실 웹사이트 생성기는 최종 산출물 디렉터리만 호스팅 서버에 올리면 되기 때문에 웹서버 기능만 갖춘 곳이라면 어디든 배포가 가능합니다)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/F8471E02-B0A3-46DA-A776-9058A95C1035.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;는 배포 자동화 기능을 갖춘 호스팅 서비스입니다. 굳이 비교를 하자면 &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;와 유사한 서비스라고 할 수 있지만, Heroku가 주로 서버측 애플리케이션을 호스팅하는 반면, Netlify는 프론트엔드(frontend) 코드를 호스팅한다는 점에 차이가 있습니다. CDN과 지속적 배포(continuous delivery) 도 지원합니다.&lt;/p&gt;

&lt;p&gt;Netlify 서비스에 가입하면 아래와 같이 대시보드가 나옵니다. 아직 아무 것도 없는 빈 대시보드입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/D0C03F1C-99C9-491A-B8E2-5D8247D4C8E1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;좌측 상단의 “New site from Git” 버튼을 클릭합니다 (맞습니다! Netlify에 코드를 배포하기 위해서는 Git 저장소가 필요합니다).  다음과 같이 사이트 생성 화면이 열립니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/A2D59AE3-B505-42CA-803B-DD30966699A8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서는 GitHub를 사용해 보겠습니다.  (앞서 저장해 두었던 것을 기억하나요?) “GitHub” 버튼을 눌러 나오는 인증(authorize) 팝업창에서 인증을 완료하면 저장소를 선택하는 페이지가 나옵니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/82F74535-CB5C-41E3-97E5-C97192DBF635.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 때 앞서 미리 저장해 두었던 Hugo 사이트의 git 저장소를 선택합니다. 그러면 설정의 마지막 단계로 몇몇 셋팅값을 입력하는 부분이 나옵니다. 여기서 build settings값을 다음과 같이 설정하고 “Deploy site” 버튼을 누릅니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/210E3478-DF34-428D-8C4B-D2BDCD8B4FCA.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;잠시.. 기다립니다. 그동안 Netlify는 GitHub 저장소로부터 파일을 불러와 자동으로 빌드하고 배포합니다. 배포 과정은 Delply log로 확인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/52C40113-5F06-4CC4-AF3C-43BD90EE0E46.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;정상적으로 배포가 완료되면 아래와 같이 사이트 배포가 완료되었다고 나옵니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/46981CAD-E593-4370-B85B-A9F0D72CC367.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;끝입니다. Netlify가 자동으로 URL도 하나 만들어 주기 때문에, 대시보드에 나와 있는 이 URL로 접속하면 사이트가 인터넷 상에 퍼블리싱된 것을 바로 확인할 수 있을 것입니다. 도메인명은 ‘brave-bohr-eabe89.netlify.com’ 에서처럼  임의로 주어지지만, 나중에 변경할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/usefulparadigm/2017/my-cool-new-blog.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Netlify는 자동 배포(auto publishing) 기능이 기본으로 켜져 있어서, 이후 GitHub 저장소에 추가되는 모든 업데이트는 Netlify에 의해 감지되어 자동으로 배포가 일어납니다. 새로운 컨텐츠를 올릴 경우에도 GitHub에만 올려 주면 됩니다. (물론 이 옵션은 꺼 둘 수 있습니다)&lt;/p&gt;

&lt;p&gt;그 밖에 사이트의 도메인명을 변경하거나 커스텀 도메인을 추가하고 HTTPS를 적용하고 하는 과정들은 Netlify에 잘 나와 있어 별도 설명은 생략합니다.&lt;/p&gt;

&lt;p&gt;지금까지 본 것처럼, Netlify는 Git 저장소와 연동하여 간단하게 프론트엔드 웹앱(SPA)이나 웹사이트를 배포할 때 사용하면 좋은 서비스입니다. Netlify에 관한 더 자세한 내용은 &lt;a href=&quot;https://www.netlify.com/docs/&quot;&gt;Netlify 문서&lt;/a&gt;를 참조하세요!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;※ 몇 가지 유의사항: Hugo 사이트를 Netlify로 배포할 때&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Hugo 사이트를 Netlify에 배포하는 경우, Hugo 테마를 위에서 했던 것처럼 clone 하거나 다운로드 방식으로 설치하면 작동하지 않습니다.  git의 submodule을 사용해서 테마를 설치해야 하며, 그 이유와 자세한 내용은 &lt;a href=&quot;https://gohugo.io/hosting-and-deployment/hosting-on-netlify/#use-hugo-themes-with-netlify&quot;&gt;여기&lt;/a&gt;를 참조하면 됩니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;이 글을 쓰는 현재, Hugo의 버전을 Netlify에 알려줘야 한다고 되어 있습니다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netlify.toml&lt;/code&gt; 파일을 만들어 버전 정보를 적어 주거나 Netlify 콘솔에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HUGO_VERSION&lt;/code&gt; 환경변수를 셋팅하는 방식으로 설정 가능합니다. 자세한 내용은 &lt;a href=&quot;https://gohugo.io/hosting-and-deployment/hosting-on-netlify/&quot;&gt;여기&lt;/a&gt;를 참조하세요!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>플라타너스트리 2017 Updates</title>
   <link href="/2017/11/04/platanustree-2017-updates/"/>
   <updated>2017-11-04T00:00:00+00:00</updated>
   <id>/2017/11/04/platanustree-2017-updates</id>
   <content type="html">&lt;p&gt;책 읽는 좋은 습관! 온라인 책 관리 서비스 &lt;a href=&quot;https://platanustree.com&quot;&gt;플라타너스트리&lt;/a&gt;가 업데이트 되었습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://platanustree.com/&quot; target=&quot;_blank&quot;&gt;
&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/2017-11-04_EC5524AB-6123-4B52-93F3-CF39FC50098C.jpg&quot; alt=&quot;플라타너스트리 2017&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;이번 업데이트는 새 기능의 추가 보다는 기존에 있던 기능들의 사용성을 개선하는 데 좀 더 초점을 맞췄습니다.&lt;/p&gt;

&lt;p&gt;주요 업데이트 내용은 다음과 같습니다.&lt;/p&gt;

&lt;h4 id=&quot;ui-테마-업데이트&quot;&gt;UI 테마 업데이트&lt;/h4&gt;

&lt;p&gt;플라타너스트리는 오픈소스 UI 프레임워크인 &lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Twitter Bootstrap&lt;/a&gt;을 사용합니다. 이번 업데이트에서는 Bootstrap의 버전을 v3에서 v4 (v4.0.0-beta.2)로 판올림하였으며 이에 따라 지원하는 브라우저가 변경됩니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;IE8, IE9와 iOS 6은 지원하지 않으며 IE10+ 및 iOS 7+ 만 지원.&lt;/li&gt;
  &lt;li&gt;Android v5.0 Lollipop’과 WebView.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;모바일-우선-디자인&quot;&gt;모바일 우선 디자인&lt;/h4&gt;

&lt;p&gt;PC(데스크톱) 버전의 서재 목록 구성도 모바일 버전처럼 목록이 일렬로 배열되어 목록 관리가 좀 더 간단해 졌습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/2017-11-04_5B23BBAE-B613-4A34-89CA-8B032A96CFCD.jpg&quot; alt=&quot;플라타너스트리 서재 목록(PC버전)&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;책-상세-페이지-ui-개선&quot;&gt;책 상세 페이지 UI 개선&lt;/h4&gt;

&lt;p&gt;책 상세 페이지에서 읽기 상태를 관리하고 노트를 작성하는 부분이 좀 더 편리해 졌습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/2017-11-04_C0D33C82-3EDE-4BFA-A0AA-756ADCFB05CF.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;기타&quot;&gt;기타&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;월별 모아보기&lt;/strong&gt;.  내 서재에서 책 목록을 월별로 모아 볼 수 있습니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;❤️ Favorite 버튼&lt;/strong&gt;. 내가 좋아하는 책만 따로 보관할 수 있습니다. 다른 사람이 Favorite 한 책도 로비에서 확인 가능 합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://platanustree.com/&quot;&gt;플라타너스트리&lt;/a&gt;는 계속 자랍니다.&lt;/p&gt;

&lt;p&gt;즐겁게 사용하세요! ~&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Craft CMS로 콘텐츠 중심 웹사이트 만들기</title>
   <link href="/2017/09/22/building-a-content-first-website-with-craftcms/"/>
   <updated>2017-09-22T00:00:00+00:00</updated>
   <id>/2017/09/22/building-a-content-first-website-with-craftcms</id>
   <content type="html">&lt;p&gt;요즘은 웹사이트 만드는 일이 별로 어렵지 않다. 시중에는 &lt;a href=&quot;https://wordpress.org/&quot;&gt;워드프레스(WordPress)&lt;/a&gt; 처럼 쉽고 편리한 도구들이 많이 나와 있고 온라인 상에는 가입만 하면 바로바로 쓸 수 있는 웹사이트 호스팅 서비스들도 많다. 랜딩 페이지(landing page) 처럼 좀 더 가벼운 웹사이트라면 &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;지킬(Jekyll)&lt;/a&gt;이나 &lt;a href=&quot;http://gohugo.io/&quot;&gt;휴고(Hugo)&lt;/a&gt; 같은 정적 페이지 빌더를 사용하면 그만이다.&lt;/p&gt;

&lt;p&gt;이렇게 많은 도구들이 세상에 이미 존재하는데 또 무엇이 필요할까?&lt;/p&gt;

&lt;p&gt;블로그처럼 웹사이트에 담기는 내용이 간단한 글(post) 이거나 브로셔나 랜딩 페이지처럼 몇 장의 소개 페이지 정도라면 걱정할 게 없다. 워드프레스 설치하고 테마 하나 입혀 뚝딱 만들면 된다. 필요한 기능이 있다면 플러그인 몇 개 찾아 설치하면 그만.&lt;/p&gt;

&lt;p&gt;그런데 만약 좀 더 복잡하고 다양한 콘텐츠를 담아야 하는 웹사이트라면? 가령,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;다양한 유형의 미디어 콘텐츠들을 담아서 보여주는 미디어 사이트&lt;/li&gt;
  &lt;li&gt;다양한 강의 내용이 담긴 온라인 강좌 사이트&lt;/li&gt;
  &lt;li&gt;여러 종류의 음식 레시피를 담고 있는 요리 정보 사이트&lt;/li&gt;
  &lt;li&gt;다양한 제품에 대한 정보를 제공하는 리뷰 사이트&lt;/li&gt;
  &lt;li&gt;기업과 채용에 관한 정보를 모아 둔 온라인 채용 사이트&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;여기서 중요한 것은 콘텐츠(content) 다. 미디어 사이트라면 ‘미디어’가 콘텐츠가 되고 온라인 강좌 사이트는 ‘강의’가 콘텐츠이고 제품 사이트라면 ‘제품’이 요리 사이트에는 ‘레시피’가 콘텐츠인 셈이다. 결국 웹사이트는 콘텐츠를 담는 그릇이고 그 콘텐츠를 얼마나 잘 담을 수 있냐가 관건이 된다.&lt;/p&gt;

&lt;p&gt;이런 콘텐츠 중심의 웹사이트를 만들려면 어떻게 하면 좋을까?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;워드프레스를 쓰면 되지 않나?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;물론 워드프레스로도 못할 건 없다. 혹은 여력이 되면 &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;루비온레일스&lt;/a&gt;나 &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;장고&lt;/a&gt;, &lt;a href=&quot;https://laravel.com/&quot;&gt;라라벨&lt;/a&gt; 같은 웹 프레임워크를 사용해서 직접 만들어도 된다. 하지만 전자는 필요 이상으로 친절(?)하고 후자는 해야할 일이 너무 많다. 이 둘의 어느 중간 지점 쯤에 있는 도구면 좋지 않을까? 적당히 친절하면서 그렇다고 너무 버겁지도 않은.&lt;/p&gt;

&lt;h2 id=&quot;안녕하세요-craft&quot;&gt;안녕하세요, Craft!&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://craftcms.com/&quot;&gt;Craft CMS&lt;/a&gt;(이하 ‘Craft’)는 바로 그 지점, 즉 ‘콘텐츠’ 그 자체에 초점을 맞춘 웹사이트 제작 도구다. 어떻게 하면 다양한 콘텐츠들을 가장 잘 표현하고 가장 잘 담을 수 있을까에 방점을 찍었다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/22D1E3AC-A031-4164-B8BB-45D6B223EAB8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Craft는 &lt;a href=&quot;https://pixelandtonic.com/&quot;&gt;Pixel &amp;amp; Tonic&lt;/a&gt; 에서 만든 오픈소스 CMS 솔루션으로 PHP 웹 프레임워크인 &lt;a href=&quot;http://www.yiiframework.com/&quot;&gt;Yii framework&lt;/a&gt;를 기반으로 하고 있다.  2017년 9월 현재 최신 버전은 2.6.x 이며 &lt;a href=&quot;https://craftcms.com/news/craft-3-beta-update&quot;&gt;버전 3은 베타 버전&lt;/a&gt; 상태다.&lt;/p&gt;

&lt;p&gt;이 글에서는 Craft를 설치하고 음식 레시피를 만들어 올리는 간단한 레시피 사이트를 한번 만들어 보면서 Craft의 주요 개념과 기본 사용법을 소개하기로 한다. 워드프레스에 익숙한 분들을 위해 중간중간 워드프레스와 비교하면서 설명을 할 예정이니 참고 바란다.&lt;/p&gt;

&lt;p&gt;자, 그럼 시작해 보자!&lt;/p&gt;

&lt;h2 id=&quot;craft-설치하기&quot;&gt;Craft 설치하기&lt;/h2&gt;
&lt;p&gt;설치는 비교적 간단한 편이며 설치 방법도 워드프레스 비슷하다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Craft 사이트에서 소스코드를 다운로드 받아 압축을 푼다.&lt;/li&gt;
  &lt;li&gt;Craft를 위한 데이터베이스를 생성: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ mysqladmin -uroot -p create hellocraft&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;데이터베이스 연결 설정: craft/config/db.php 파일 편집&lt;/li&gt;
  &lt;li&gt;서버 실행 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ php -S 0.0.0.0:8080 -t public/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;설치 시작 URL 접속: http://localhost:8080/admin&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;시작 페이지가 나오면, “시작” 버튼을 눌러 설치를 시작한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/CF497D7C-C67D-4FCB-811F-7860FD1B6AF9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;단계별로 하라는 대로 따라 가면,&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/EF2043FF-0CD7-43A5-A4E5-8D0DFC008987.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;설치가 완료된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/62A4820B-D9F6-4B7F-B399-672977BB61D7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Craft CMS에 접속하여 ‘계기판(Control Panel)’이 나오면 설치가 끝난 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/986BE421-626D-43AE-89EA-D10DFFD986B5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;첫 느낌이 어떤가? 워드프레스와 비슷하다. 관리자 화면의 UI도 워드프레스와 비슷하지만 한눈에 봐도 메뉴가 훨씬 단촐하다.  좌측 사이드의 메뉴라고는 ‘계기판’, ‘엔트리’, ‘설정’이 전부다.&lt;/p&gt;

&lt;h2 id=&quot;테마는-없다&quot;&gt;테마는 없다&lt;/h2&gt;
&lt;p&gt;워드프레스와 달리 Craft에는 테마가 없다. 따로 테마(theme)라는 개념이 없다. 처음 설치를 완료하고 웹사이트 URL로 접속하면 아래와 같이 그냥 허접한 Welcome 페이지만 덩그러니 자리잡고 있을 뿐, 워드프레스처럼 테마를 선택하거나 교체하는 그런 건 없다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/C088C4B0-063C-4624-859D-A70ED15DCB5B.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Craft에서는 모든 것을 직접 만들어 나가야 한다. 웹사이트 레이아웃을 디자인하고 콘텐츠들을 적절하게 배치하고 하는 모든 일들을 사용자(또는 개발자)가 직접 처리해 줘야 한다. Craft는 다만 한 가지 일, 즉 콘텐츠를 만들고 관리하는 일만 할 뿐이다.&lt;/p&gt;

&lt;h2 id=&quot;사이트-디자인-변경하기&quot;&gt;사이트 디자인 변경하기&lt;/h2&gt;
&lt;p&gt;우선 몸풀기로, 사이트 디자인을 바꾸는 것부터 시작해 보자. 간단하게 &lt;a href=&quot;http://getbootstrap.com/docs/3.3/getting-started/#download&quot;&gt;Twitter Bootstrap&lt;/a&gt; 을 적용할 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/C522CA1D-A828-4C36-BEE5-114992F256BA.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;부트스트랩을 다운로드 받아 Craft의 public 폴더 아래에 복사하고, craft/templates 폴더(이하 ‘templates 폴더’) 에 있는 _layout.html 파일을 열자.&lt;/p&gt;

&lt;p&gt;기존 인라인(inline) 처리된 style 부분이 보이면 삭제하고 대신 그 자리에 부트스트랩 로딩 코드를 다음과 같이 삽입하자.&lt;/p&gt;

&lt;div class=&quot;language-twig highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/1999/xhtml&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en-US&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;defined&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt; - &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;siteName&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;home&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;siteUrl&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/css/bootstrap.min.css&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://code.jquery.com/jquery-3.2.1.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/js/bootstrap.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(여기서는 부트스트랩 소스코드를 다운로드하여 링크를 거는 방식을 택했지만, 다운로드 없이 바로 CDN 링크 방식으로 처리해도 무방하다)&lt;/p&gt;

&lt;p&gt;이제 홈페이지에 다시 접속해 보면, 부트스트랩이 적용되어 사이트 디자인이 변경되어 있음을 확인할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/EAE44DE7-C026-415E-89F7-6B6DE7E608BC.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이런 식이다. Craft에서는 웹사이트에 필요한 모든 페이지의 디자인을 하나하나 일일이 직접 만들어 줘야 한다. 지금처럼 레이아웃도 그렇고 메인 페이지와 목록 페이지, 각각의 콘텐츠를 표시하는 페이지 등 모든 페이지들을 HTML 코드부터 CSS 스타일링까지 직접 처리해야 한다. 워드프레스로 치면, 커스텀 테마를 직접 만든다고 생각하면 된다.&lt;/p&gt;

&lt;h2 id=&quot;블로그-포스트-만들기&quot;&gt;블로그 포스트 만들기&lt;/h2&gt;
&lt;p&gt;자, 그럼 이제 Craft의 핵심인 콘텐츠를 한번 만들어 보자. 우선 간단하게 블로그에서 주로 쓰이는 포스트(post)를 한번 만들어 보기로 하자.&lt;/p&gt;

&lt;p&gt;어드민 대시보드(Craft에서 이를 Control Panel이라고 하며 흔히 줄여서 ‘CP’라고도 함)에 접속하여 “엔트리” 메뉴를 클릭하면 다음과 같이 보인다. ‘싱글’이라는 게 있고, ‘채널’이라는 제목 아래 ’News’라는 것도 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/D880BCFB-90B2-46D3-8184-60AA4C829D3A.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;News는 Craft가 디폴트로 만들어 놓은 콘텐츠 유형이다.&lt;/p&gt;

&lt;p&gt;알다시피 워드프레스에는 기본적으로 2가지의 콘텐츠 유형(content types)이 있다. 포스트(Post)와 페이지(Page). 물론 커스텀 콘텐츠 유형을 추가하는 기능이 제공되지만 이 두 가지 콘텐츠 유형이 중심이며 삭제할 수도 없다.&lt;/p&gt;

&lt;p&gt;반면 Craft에는 기본 콘텐츠 유형이라는 게 없다. 사용자가 직접 콘텐츠 유형을 설계하고 만들어야 한다. 방금 전 ‘News’는 기본으로 제공되는 콘텐츠 유형이긴 하지만 Craft가 그냥 샘플로 하나 만들어 둔 것이며 삭제해도 무방하다. 사이트에서 꼭 필요한 콘텐츠 유형을 직접 만들어 사용하는 게 Craft의 기본이다.&lt;/p&gt;

&lt;h3 id=&quot;포스트-항목-만들기&quot;&gt;포스트 항목 만들기&lt;/h3&gt;

&lt;p&gt;이런 콘텐츠 유형을 Craft에서는 ‘항목(Entry)’이라고 부른다. 달리 말해 ‘항목’은 Craft에서 콘텐츠의 기본 단위다. 워드프레스에서 ‘글(Post)’이 콘텐츠의 기본 단위인 것처럼.&lt;/p&gt;

&lt;p&gt;그럼 ‘포스트’ 항목을 하나 만들어 보기로 하자.&lt;/p&gt;

&lt;p&gt;컨트롤 패널(이하 ‘CP’)에서 “설정” 메뉴를 클릭해 보자. 아래와 같은 화면이 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/FD247AFF-12BC-414C-9C76-E6D1590845C7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서 항목을 추가하면 될 것 같은데, 아무리 찾아도 ‘항목’이라는 메뉴는 보이질 않는다.  항목을 만들기 위해서는 먼저 ‘&lt;strong&gt;섹션(Section)&lt;/strong&gt;’ 이라는 개념을 알아야 한다.&lt;/p&gt;

&lt;p&gt;Craft에서는 섹션이 있고 섹션(Section) 아래에 항목(Entry)이 온다. 즉, 섹션은 항목을 담는 그릇이다. 그리고 이 섹션은 다음 3가지의 유형이 제공된다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;싱글(Singles)&lt;/li&gt;
  &lt;li&gt;채널(Channels)&lt;/li&gt;
  &lt;li&gt;구조(Structures)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;싱글(Singles)&lt;/strong&gt; 섹션은 말 그대로 한 페이지 짜리 콘텐츠를 담는데 쓰인다. 예를 들면 메인페이지나 About 페이지 같은. 워드프레스로 치면 페이지(Page) 개념에 해당된다.&lt;/p&gt;

&lt;p&gt;한편 &lt;strong&gt;채널(Channels)&lt;/strong&gt; 섹션은 일련의 콘텐츠들을 담는데 사용되는 섹션이다. 블로그나 뉴스스트림, 레시피 목록 등 유사한 콘텐츠들을 한데 담을 때 사용한다. 워드프레스의 포스트(Post) 개념과 같다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;구조(Structures)&lt;/strong&gt; 섹션은 채널과 유사하지만 일련의 콘텐츠들이 일정한 순서와 계층으로 조직된 경우에 사용되는 섹션이다. 예를 들면, 계층구조를 갖는 매뉴얼 문서라든지 조직체계 같은 콘텐츠를 표현할 때 사용할 수 있다. 워드프레스에는 이 구조 섹션과 동일한 개념은 없다. 다만 페이지를 계층형으로 구성함으로써 구조 섹션과 비슷한 것을 만들어 낼 수는 있을 것이다.&lt;/p&gt;

&lt;p&gt;앞서 Craft를 설치하면 바로 보였던 ‘News’ 항목이 무엇인지 이제 조금 이해가 될 것이다. 이 항목은 채널 섹션, 즉 채널 유형이다. 그러니 채널 섹션 아래에 놓여 있었던 것이다.&lt;/p&gt;

&lt;p&gt;Craft의 섹션 유형에 관한 더 자세한 내용은 Craft 문서를 참조하면 된다.
&lt;a href=&quot;https://craftcms.com/docs/sections-and-entries#section-types&quot;&gt;Sections and Entries | Documentation | Craft CMS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/C07216C1-A767-47FB-89AB-22CD2CA3582E.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;설명이 좀 길었다.&lt;/p&gt;

&lt;p&gt;우리가 지금 만들 블로그 포스트 역시 채널 섹션이다. 동일한 유형의 콘텐츠들을 날짜 별로 쌓는 것이니 ‘채널’ 섹션으로 처리하면 된다.&lt;/p&gt;

&lt;p&gt;새로 채널 섹션을 하나 만들자. 이름을 ‘Post’로 주고 섹션 타입은 ‘채널’로 맞추고 나머지는 그대로 둔다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/186B1A6D-F2A4-4E2B-93C0-DFB7B5FA0865.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;저장하고 밖으로 나가면 새로 Post라는 섹션이 만들어진 것을 알 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/F7750A26-5F46-4F5A-830B-25FBB7B7AFDA.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서 “엔트리 유형 편집하기”를 클릭하면 Post 항목 타입도 이미 만들어져 있음을 알 수 있다. 이 때의 Post는 ‘섹션’이 아니라 엔트리, 즉 ‘&lt;strong&gt;항목(Entry)&lt;/strong&gt;’이다. Craft가 섹션을 만들면서 그 섹션에 해당하는 항목도 자동으로 만들었다. (나중에 다시 얘기하겠지만 Craft에서 하나의 섹션에는 반드시 하나의 항목만 들어가는 게 아니다. 하나 이상의 항목을 가질 수 있다. 그래서 섹션 아래에 항목을 둔 것이다. 여기서 Post 항목은 Post 섹션을 만들 때 디폴트로 생성된 항목일 뿐이며, 원하면 얼마든지 새로운 항목을 Post 섹션 내에 추가할 수 있다)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/D14B6EA7-65A5-48AE-ADEC-0009E22835FE.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Post 항목을 클릭해 보자. Post 항목에 대한 정보가 표시될 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/79B1C532-9512-48AA-8642-0A66F8611BFA.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;항목 보기 하단에는 ‘필드 레이아웃 디자인’ 이라는 영역이 보일 것이다. 이 부분이 항목의  필드 정보를 디자인하는 부분이다. 항목을 하나의 콘텐츠라고 한다면, 바로 여기서 콘텐츠를 구성하는 필드들의 정보를 구성할 수가 있다.&lt;/p&gt;

&lt;p&gt;워드프레스에서 글과 페이지를 포함한 모든 콘텐츠의 기본 필드가 제목(title)과 본문(body) 뿐인 것과는 달리, Craft에서는 각각의 항목 별로 그에 맞는 필드를 다르게 가져갈 수 있는 것이다. 진정한 CMS의 면모다. (물론 워드프레스에서도 &lt;a href=&quot;https://codex.wordpress.org/Custom_Fields&quot;&gt;커스텀 필드 Custom Fields&lt;/a&gt;로 필드를 확장할 수 있고, &lt;a href=&quot;https://www.advancedcustomfields.com/&quot;&gt;ACF 플러그인&lt;/a&gt; 같은 확장을 사용하면 좀 더 편리하게 필드를 관리할 수 있긴 하다)&lt;/p&gt;

&lt;p&gt;그럼 필드를 한번 추가해 보자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/4630167B-C65D-4283-ADA2-A68D1E4AAEA5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;“+ 새로운 탭” 버튼을 클릭하여 새 탭을 하나 생성하고 아래와 같이 DEFAULT 레이아웃에 있는 필드들을 드래그하여 새 탭으로 가져다 놓은 다음 저장하자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/2DE3CB7F-E205-4F48-8F5D-44A527F11BE7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;방금 우리가 만든 Post 항목은 이제 ‘본문’과 ‘태그’라고 하는 2개의 필드를 갖는다. (‘제목’ 필드는 항상 따라 다닌다)&lt;/p&gt;

&lt;h2 id=&quot;엔트리-추가하기&quot;&gt;엔트리 추가하기&lt;/h2&gt;
&lt;p&gt;Post 항목을 만들었으니 이제 이 항목으로 실제 콘텐츠를 하나 만들어 보자. CP에서 “엔트리” 메뉴를 클릭하자. 채널 메뉴 아래에 ‘Post’ 채널이 추가되어 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/5AC95821-02AE-4944-87ED-B7A1DB5C81F0.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Post 라는 엔트리를 클릭해 보면 아무 것도 없는 빈 목록이 표시된다. 새로 포스트를 하나 만들어 보기로 하자. 상단의 “+새로운 항목” 버튼을 클릭하여 “Post” 를 선택하면 다음과 같이 새로운 엔트리 만들기 화면이 표시된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/386A35EE-630E-4F27-A7FD-98B05CEF4914.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 부분은 워드프레스 여타 다른 CMS의 편집기 화면과 별로 다를 게 없다. 참고로 Craft는 내부적으로 WYSIWYG 에디터로 &lt;a href=&quot;https://imperavi.com/redactor/&quot;&gt;Redactor&lt;/a&gt; 를 쓴다. (워드프레스는 디폴트로 TinyMCE를 사용)&lt;/p&gt;

&lt;p&gt;콘텐츠를 한번 입력해 보자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/2049AC38-816F-4DB8-8A5A-52178B372D63.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서 잠깐! 미리 볼 수는 없을까? Craft에는 실제로 콘텐츠 입력할 때 미리보기(Preview)를 할 수 있는 기능이 내장되어 있다. 그런데 아직 템플릿을 만들지 않았기 때문에 이 기능은 사용할 수 없다. 나중에 다시 설명한다.&lt;/p&gt;

&lt;p&gt;우선은 저장하고 나가자. 새 콘텐츠가 Post 항목으로 추가된 것을 확인할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/69BFA5F4-52C8-4CCB-A831-B955D65770C6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그럼 이게 실제 브라우저에서는 어떻게 보이는지 한번 보도록 하자. 항목 목록 맨 오른쪽에 있는 지구본 아이콘(웹페이지 방문)을 클릭하면 새 브라우저 창이 열리면서 콘텐츠의 내용이 표시될 것이다. 그런데.. 어? 페이지가 없다고 나온다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/DB6ABCD4-07A7-449D-BA26-546AB9DF59A4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;맞다. 아직 우리가 이 콘텐츠 항목과 맵핑되는 템플릿을 만들지 않았다. 앞서 말했듯 Craft에서는 모든 페이지를 직접 만들어 줘야 한다. (알다시피 워드프레스에는 템플릿 계층 개념이 있어 해당 콘텐츠 유형에 맞는 템플릿이 없을 경우 템플릿 계층의 상위에 위치한 템플릿이 자동으로 바통을 이어 받게 되어 있지만 Craft에는 이런 개념은 없다. 콘텐츠 유형에 따른 템플릿을 직접 만들어 줘야 한다)&lt;/p&gt;

&lt;h2 id=&quot;템플릿-추가하기&quot;&gt;템플릿 추가하기&lt;/h2&gt;
&lt;p&gt;템플릿을 만드는 일은 워드프레스에 테마 파일 속에서 템플릿 파일을 추가하거나 수정하는 작업과 비슷하다. 다만 워드프레스와는 달리 Craft에서는 직접 PHP를 편집하는 대신 &lt;a href=&quot;https://twig.symfony.com/&quot;&gt;Twig&lt;/a&gt;이라는 템플릿 언어를 사용한다. (워드프레스에서도 Twig을 사용할 수 있게 해주는 &lt;a href=&quot;https://www.upstatement.com/timber/&quot;&gt;Timber&lt;/a&gt; 라는 플러그인이 있긴 하다)&lt;/p&gt;

&lt;p&gt;Craft가 설치된 디렉터리로 가서 앞서 _layout.html 파일을 편집할 때 열었던 templates 폴더를 보면 그 아래에 news라는 폴더가 보일 것이다. 맞다. 이 부분이 바로 Craft 가 설치될 때 함께 만들어진 ‘News’ 항목에 대한 템플릿이 위치한 곳이다.&lt;/p&gt;

&lt;p&gt;그 속에 index.html 파일과 _entry.html 파일이 보일 것이다. 파일 이름이 말해주듯 각각 항목의 목록과 항목 그 자체의 내용을 표시해 주는 템플릿 파일들이다. 워드프레스로 치면 아카이브(archive)와 싱글(single) 템플릿인 셈이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;index.html 뉴스 목록을 표시&lt;/li&gt;
  &lt;li&gt;_entry.html 개별 뉴스 내용을 표시&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이제 templates 폴더 아래에 콘텐츠 유형에 맞는 폴더를 하나 추가하자. 여기서는 Post 항목에 대한 템플릿을 만들 것이기에 폴더명을 ‘post’로 주면 된다. (사실 더 정확하게는 앞서 섹션을 만들 때 엔트리 템플릿을 지정하는 부분이 있었다. 폴더 구성은 이 부분의 정보와 일치시키면 된다)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/7B826D34-C706-4024-80EF-0739F5C479AC.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;post 폴더를 만들었다면, 그 아래에 _entry.html 이라는 파일을 하나 추가하자.
그리고 그 내용은 우선 미리 만들어져 있는 news 폴더 속 _entry.html 파일을 그대로 복사해서 붙여 넣자.&lt;/p&gt;

&lt;div class=&quot;language-twig highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_layout&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Posts&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;News&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;craft.entries.section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'post'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.url&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Posted on &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.postDate.format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'F d, Y'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.body.getPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.url&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Continue reading&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Twig으로 작성된 이 템플릿은 상당히 직관적이다. 얼핏 봐도 post 섹션에 있는 항목들을 불러와 표시하는 것임을 알 수 있다. 워드프레스가 Loop를 자동으로 호출하는 것과 달리, Craft에서는 이렇게 명시적으로 질의(query)를 통해 데이터를 가져 온다.&lt;/p&gt;

&lt;p&gt;Twig 템플릿의 사용법과 템플릿에서 에서 사용할 수 있는 함수들에 대한 설명은 &lt;a href=&quot;https://craftcms.com/docs/templating-overview&quot;&gt;Craft Templating&lt;/a&gt; 문서를 참조하자.&lt;/p&gt;

&lt;p&gt;이제 다시 앞서 404 오류(“Page not found”)가 나왔던 페이지에 접속해 보면 이번엔 포스트의 내용이 정상적으로 표시되는 것을 확인할 수 있을 것이다. 템플릿이 만들어졌고 콘텐츠 항목이 템플릿에 반영된 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/8C5C77E4-38B2-4B8E-A98B-A6EAB078507B.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;라이브-프리뷰&quot;&gt;라이브 프리뷰&lt;/h3&gt;

&lt;p&gt;앞서 잠깐 미리보기 기능이 있다고 말했었다. 이제 다시 엔트리 목록으로 돌아와서 방금 전 만들었던 “안녕하세요” 포스트의 편집 화면으로 가보자. 우측에 “라이브 프리뷰”라는 버튼이 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/A2723CB7-EFDC-4005-AC58-6AFD4E28C222.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 버튼을 한번 클릭해 보자. 예상은 했겠지만, 화면이 전환되면서 미리보기 화면이 표시될 것이다. 이름 그대로 ‘실시간’ 미리보기이기 때문에  바로 보면서 바로 편집할 수 있는 멋진 기능이다. (물론 워드프레스에도 미리보기 기능이 있다)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/2A3E3C75-A43D-4F72-8B06-A43BA561D749.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;느꼈을지 모르지만, Craft는 워드프레스와는 다르게 초기 메뉴가 아주 간단하다. &lt;strong&gt;처음에 간단하게 시작하고 필요한 것들을 추가해 나간다&lt;/strong&gt;는 게 Craft의 발상이다. 처음부터 모든 걸 갖추고 필요없는 것을 제거해 나가는 워드프레스와는 반대 방향의 접근법이다. (얼핏 생각해 봐도 워드프레스에서 기본으로 제공되는 기능들 중에는 필요 없는 기능들이 제법 많다. 특히 워드프레스를 ‘블로깅 툴’이 아니라 ‘CMS’라는 시각에서 봤을 때 그렇다는 말)&lt;/p&gt;

&lt;h2 id=&quot;레시피-항목-만들기&quot;&gt;레시피 항목 만들기&lt;/h2&gt;
&lt;p&gt;워드프레스를 좀 써 본 분들이라면 아마 지금 쯤 이렇게 말할 것이다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;뭐야? 이런 건 워드프레스에서도 다 할 수 있는 거잖아? 그것도 더 쉽게.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;맞다. 사실 지금까지의 내용은 그저 맛보기에 불과했다. 아니 맛보기라기 보단 일부러 워드프레스를 따라 했다고 말하는 게 더 맞다. 똑같은 일을 Craft로 해 보면서 워드프레스와의 차이를 보이기 위함이었다.&lt;/p&gt;

&lt;p&gt;하지만 지금까지의 내용만으로는 Craft의 진가를 제대로 보일 수 없다. 이번엔 레시피 라는 항목을 하나 더 만들어 보자. 앞서와 마찬가지로 새로 채널 섹션을 하나 만들면 된다. 이름은 ‘Recipe’라고 주자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/28A7E53F-192C-43CC-9582-A9831F376BDC.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 우리의 Craft에는 ‘Recipe’라는 섹션이 하나 더 추가되었다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/F5D5FD33-59A9-4B2C-A128-BBA34277297B.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서 잠깐! 앞서도 잠깐 언급했지만 Craft에는 항목(엔트리) 외에 별도로 섹션(Section)이라는 개념이 있다. 그리고 &lt;strong&gt;하나의 섹션에는 하나 이상의 항목이 올 수 있다&lt;/strong&gt;. 예를 들면, 미디어(media) 라는 섹션을 하나 만들었다면 그 섹션 속에 다시 사진 미디어, 보도자료 미디어, 스페셜 미디어 등 여러 종류의 미디어 항목들이 올 수 있는 것이다.&lt;/p&gt;

&lt;p&gt;또는 레시피 섹션에서라면 그 속에 한식, 양식, 중식, 일식 등의 레시피 항목을 각각 별도로 만들어 항목별로 템플릿이나 필드 구조를 다르게 가져갈 수도 있다. 같은 섹션의 항목들은 그 항목 유형이 다르더라도 함께 취급된다.&lt;/p&gt;

&lt;p&gt;워드프레스에서 이와 유사한 개념을 찾는다면 아마도 &lt;a href=&quot;https://codex.wordpress.org/Post_Formats&quot;&gt;포스트 유형(Post Formats)&lt;/a&gt;이 될 것이다. 워드프레스에서는 글을 쓸 때 그 글의 포스트 유형을 추가정보(aside), 갤러리(gallery), 링크(link), 이미지(image), 인용(quote), 상태(status), 비디오(video), 오디오(audio), 채팅(chat) 등으로 다양하게 지정할 수 있고 각각 템플릿도 다르게 가져갈 수 있지만 그렇게 많이 쓰이지는 않는 듯 하다.&lt;/p&gt;

&lt;p&gt;Recipe 항목을 디자인하기에 앞서 우리가 만들 레시피의 레이아웃을 한번 그려 보자.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;우선 레시피 &lt;strong&gt;제목(title)&lt;/strong&gt;이 나온다.&lt;/li&gt;
  &lt;li&gt;그리고 이 레시피에 대한 간단한 &lt;strong&gt;설명(description)&lt;/strong&gt;,&lt;/li&gt;
  &lt;li&gt;이 레시피를 대표할 만한 대표 &lt;strong&gt;이미지(featured image)&lt;/strong&gt;가 보이고,&lt;/li&gt;
  &lt;li&gt;이 레시피에 사용될 &lt;strong&gt;재료(ingredients)&lt;/strong&gt; 들이 표시되고,&lt;/li&gt;
  &lt;li&gt;레시피에 대한 구체적인 &lt;strong&gt;지시(instruction)&lt;/strong&gt;가 나온다.&lt;/li&gt;
  &lt;li&gt;마지막엔 이 레시피를 직접 따라해 볼 수 있는 &lt;strong&gt;동영상(video)&lt;/strong&gt;이 제공되면 좋을 것 같다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그림으로 그려보면 대략 이렇게 될 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/63E3D0CF-C42B-482F-8350-F9844AB59159.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 이 레이아웃 대로 레시피 항목의 필드로 구성해 보기로 하자.&lt;/p&gt;

&lt;p&gt;‘굳이 이렇게 항목을 나눌 필요 있을까? 워드프레스처럼 편집기 속에서 그냥 description / instruction / video 등등의 부분으로 나눠 콘텐츠를 입력하면 되지 않을까? 혹은 &lt;a href=&quot;https://vc.wpbakery.com/&quot;&gt;Visual Composer&lt;/a&gt; 같은 페이지 빌더 플러그인을 사용하면? 페이지 빌더가 이럴 때 사용하라고 있는 것 아닌가?’ 라고 말할 수도 있을 것 같다. 그렇지만 콘텐츠 의 기본 구조 자체를 구조화시키는 것과 단순히 보이는 부분에서만 다르게 보이게끔 나누는 방법은 분명 다르다!&lt;/p&gt;

&lt;h3 id=&quot;필드-추가하기&quot;&gt;필드 추가하기&lt;/h3&gt;

&lt;p&gt;레시피 항목에 필드를 추가할 것이다. CP에서 “설정 &amp;gt; 필드” 메뉴를 선택하자.&lt;/p&gt;

&lt;p&gt;우선 설명(description) 필드 부터.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/1B722C70-E4D9-4AC1-AA89-F259C0A78765.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이어서 대표이미지(featured image) 필드.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/14188DF1-7D3A-4E5E-B3A2-0037393C729B.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서는 약간의 설명이 필요하다. 이 필드는 이미지 파일이 와야 한다.
필드 유형을 ‘에셋’으로 선택하고 허용 파일의 형식을 ‘이미지’로 제한하자.  다른 설정들도 더 있지만 우선은 이 정도만 하고 저장 버튼을 눌러 저장하자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/D0F8F77E-9270-493C-B2A4-62E205B22824.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이어서 재료(ingredients).  그냥 평문으로 처리하자.&lt;/p&gt;

&lt;p&gt;이번엔 지시(instruction).  별도 필드로 만들어도 되지만, 이 부분 그냥 기존의 body 필드를 이용하는 걸로 하자.&lt;/p&gt;

&lt;p&gt;마지막으로 video URL을 입력하는 부분. 필드 유형은 그냥 평문(디폴트)으로 두자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/2079C35F-74B9-4786-9F57-0E96F10C8811.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그러면 이제 전체 필드가 다음과 같이 추가되었다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/C1CF8500-38DB-447F-A884-45EF87B458E8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 다시 “설정” 메뉴에서 Recipe 항목 유형을 편집해 보자.&lt;/p&gt;

&lt;p&gt;앞서와는 달리 필드 레이아웃 디자인의 디폴트 탭에 방금 전 우리가 추가한 필드들이 포함되어 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/1502DEAA-FAF5-49A1-BB4F-3697A0C44747.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;새로운 탭을 하나 만들어 필드들을 추가하자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/491E3A42-B683-46EB-B8CB-BCF7D211305A.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다 되었다. 이로서 우리는 새 콘텐츠 항목인 Recipe를 하나 만든 것이다.&lt;/p&gt;

&lt;p&gt;CP에서 “엔트리” 메뉴에서 새 레시피 항목 만들기를 해 보면 다음과 같은 입력 화면이 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/900B0094-9DD5-4C27-BB9E-CFD55FE1EEB4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;앞서 포스트를 만들 때와는 완전히 다른, 레시피 항목에 딱 맞는 편집창이 눈앞에 펼쳐진다. 이 정도면 전문 쉐프가 아니라도 레시피 하나 쯤은 입력하고픈 용기가 생긴다. 요리 공부도 할 겸, 레시피를 하나 입력해 보자. 내가 좋아하는 알리오올리오 파스타! 혹은 뭐든 좋다. 입맛 돋우는 음식으로 레시피를 하나 만들어 보기 바란다.&lt;/p&gt;

&lt;p&gt;앞서도 말했듯, 워드프레스에서도 커스텀 필드를 사용하면 이렇게 다양한 필드를 구성할 수 있다. 그렇지만 그러려면 제법 많은 노력이 필요하다. 템플릿 파일도 건드려야 하고 관리자 화면에 메타박스도 만들어 넣어야 하고.&lt;/p&gt;

&lt;p&gt;참고로, 만약 위 레시피를 워드프레스로 만든다면?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;‘레시피’라는 커스텀 포스트 유형(Custom Post Type)을 하나 만들고&lt;/li&gt;
  &lt;li&gt;여기에 커스텀 필드들을 추가하고 (이때 ACF 같은 플러그인을 활용)&lt;/li&gt;
  &lt;li&gt;이 커스텀 포스트 유형에 대응하는 템플릿 파일을 작성&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;워드프레스에서 커스텀 포스트 유형을 사용하여 새로운 콘텐츠 유형을 만드는 방법에 대한 자세한 설명은 &lt;a href=&quot;https://wpguide.usefulparadigm.com/posts/110&quot;&gt;WordPress 가이드&lt;/a&gt;를 참조하자.&lt;/p&gt;

&lt;h3 id=&quot;에셋-처리하기&quot;&gt;에셋 처리하기&lt;/h3&gt;

&lt;p&gt;여기서 한 가지. 대표 이미지 부분에서 다음과 같이 오류 메시지가 뜬다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/D5A7F3FC-0541-4FB8-9BB6-36A6BB56EB5F.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Craft에서는 이미지 파일이나 PDF 파일 같은 모든 종류의 파일들을 ‘&lt;strong&gt;에셋(asset)&lt;/strong&gt;’이라고 부르고 별도 관리할 수 있게끔 하고 있다. 이 경우 우리가 만들 레시피 항목의 대표 이미지 역시 하나의 에셋이 된다.&lt;/p&gt;

&lt;p&gt;CP의 “설정 &amp;gt; 에셋” 메뉴에서 새 에셋을 추가해 보자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/63502D59-904F-4CA5-B48A-2CA82FBC5425.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;“+ 새로운 자료 소스” 버튼을 눌러 다음과 같이 새로 에셋을 추가하자. 이름은 아무렇게나 줘도 되지만 여기서는 ‘음식사진’이라고 정했다. 핸들값은 나중에 템플릿에서 이 에셋을 참조할 때 사용할 값이다. 파일 시스템 경로는 실제로 이 이미지 파일이 업로드되었을 때 저장될 경로로, 여기서는 public 폴더 아래에 있는 images/foods/ 라는 폴더에 저장할 것이기에 그렇게 지정했다(이 폴더는 실제로 지정된 위치에 존재해야 한다. 없으면 만들어 주자!) 마지막으로 URL은 이 이 에셋(이미지)이 브라우저를 통해 표시될 때 사용될 경로를 지정한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/C4825B34-E4D4-42B7-8FE9-ABCB1C833FD3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;저장하고,  다시 “설정 &amp;gt; 필드” 메뉴로 가서 ‘대표이미지’ 필드로 들어가 보자.
소스를 제한하고 기본 업로드 위치를 방금 전 만든 에셋인 ‘음식사진’으로 맞추자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/9EDA240D-CB06-4311-98D4-0D73D4418900.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 레시피 항목 편집 창으로 돌아오면 에셋 파일을 추가할 수 있게 업로드 버튼이 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/A24A89FA-0FAF-4E76-885A-B788E8380197.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;대표이미지를 한번 추가해 보자. 이미지 파일을 드래그하여 업로드 창에 드롭하면 업로드가 되고,  “선택하기”를 클릭하면 업로드한 이미지가 이 레시피의 대표 이미지가 된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/2C047A63-A215-4045-BCF9-CBAE83767984.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;템플릿에-반영하기&quot;&gt;템플릿에 반영하기&lt;/h3&gt;

&lt;p&gt;그렇지만 아직 실시간 미리보기를 해 보면 필드의 내용이 반영되지 않았을 것이다. 아직 템플릿을 만들지 않았기 때문이다. 이제 템플릿 파일을 만들 시간이다.&lt;/p&gt;

&lt;div class=&quot;language-twig highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_layout&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.title&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.description&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;featured&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.featured_image.first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Ingredients&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ingredients&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.ingredients&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Instruction&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;instruction&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.body&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.video&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;video&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.video&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Posted on &lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.postDate.format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'F d, Y'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;endblock&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;다시 미리보기 해보자. 레시피의 모든 필드들이 제대로 반영 되었을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/37D5C563-0539-41E5-9366-16C39C873CE4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;참고로, 여기에서 사용한 알리오 올리오 파스타의 내용은 다음 자료들을 참조하였다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://namu.wiki/w/%EC%95%8C%EB%A6%AC%EC%98%A4%20%EC%98%AC%EB%A6%AC%EC%98%A4&quot;&gt;알리오 올리오 - 나무위키&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Yf0LIvDo9sc&quot;&gt;알리오 올리오 파스타 만들기 : 맛있지만 간단한 오일 파스타 - YouTube&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;youtube-비디오-포함-시키기&quot;&gt;YouTube 비디오 포함 시키기&lt;/h3&gt;

&lt;p&gt;다만 한 가지가 조금 아쉽다.&lt;/p&gt;

&lt;p&gt;방금 레시피에 포함시킨 동영상의 URL은 실은 유튜브(YouTube) 사이트로의 단순 링크에 불과하다. 가능하면 동영상을 직접 레시피 내에 포함시킬 수 있으면 좋겠다.&lt;/p&gt;

&lt;p&gt;워드프레스에서라면 이건 일도 아니다. 그냥 동영상 URL을 입력하면 워드프레스가 자동으로 임베딩(embedding) 시켜 주기 때문이다.&lt;/p&gt;

&lt;p&gt;하지만 Craft라고 해서 안되는 건 아니다. 유튜브 동영상 URL을 파싱하여 동영상 ID를 추출한 다음 템플릿 속에 임베드 시키는 코드를 간단하게 직접 구현해도 되지만, 여기서는 Craft의 플러그인(Plugin) 기능도 한번 알아 볼 겸, 플러그인을 하나 사용해 보기로 하자.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://straightupcraft.com/craft-plugins/video-embed-utility&quot;&gt;Video Embed Utility&lt;/a&gt;라는 플러그인을 사용할 건데, &lt;a href=&quot;https://github.com/Staplegun-US/craft-video-embed-utility&quot;&gt;GitHub&lt;/a&gt;에서 내려 받으면 된다.&lt;/p&gt;

&lt;p&gt;플러그인을 다운로드 받아 압축을 푼 다음, craft/plugins 폴더 아래에 두자.
그런 다음, “설정 &amp;gt; 플러그인” 메뉴로 가면 방금 복사한 플러그인이 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/5E306FFA-500B-41AE-8691-ADE2BA1767C4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;“설치하기” 버튼을 누르면 설치가 끝난다. 물론 워드프레스처럼 어드민(CP) 내에서 플러그인을 검색하고 자동으로 설치하는 그런 편리한 기능은 아직 없다.&lt;/p&gt;

&lt;p&gt;템플릿 파일에서는 동영상 처리 부분에서 다음과 같이 필터로 추가해 주면 된다.&lt;/p&gt;

&lt;div class=&quot;language-twig highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;entry.video&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;| &lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;videoEmbed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;400&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 다시 레시피로 돌아와 확인하면, 동영상이 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/36C406DE-745C-41B8-87F5-507103F7321B.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;그-밖의-기능들&quot;&gt;그 밖의 기능들&lt;/h2&gt;
&lt;p&gt;오늘 소개할 내용은 여기까지다.&lt;/p&gt;

&lt;p&gt;지면(?) 관계상 다 다루지는 못했지만, Craft에는 이 밖에도 많은 기능들이 기본으로 제공되고 있다. 어떤 기능들이 더 있는지는 CP의 “설정” 메뉴에서 보면 힌트를 얻을 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/1104FBAF-B6D1-45D0-ADEA-3034A216BC87.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그 중 몇 가지만 들면, 다음과 같은 기능들이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;경로(Routing) 설정 기능&lt;/li&gt;
  &lt;li&gt;사용자(Users) 및 권한 관리&lt;/li&gt;
  &lt;li&gt;이메일 처리 기능&lt;/li&gt;
  &lt;li&gt;다국어 사이트 지원&lt;/li&gt;
  &lt;li&gt;캐싱 처리&lt;/li&gt;
  &lt;li&gt;검색 및 백업&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 모든 기능들이 기본으로 제공된다. 사실 이런 기능들 하나하나는 콘텐츠 중심의 웹사이트를 만드는 경우라면 꼭 필요한 기능들이고, 워드프레스를 이용할 경우라 해도 별도 플러그인을 설치하거나 아니면 직접 구현해서라도 만들어 넣어야 하는 것들이다.&lt;/p&gt;

&lt;p&gt;참고로, 이들 기능 중 일부는 별도의 라이선스를 구입해야 활성화된다. Craft는 PERSONAL / CLIENT / PRO 3종의 라이선스가 있는데 이 중 PERSONAL을 제외한 나머지 2개는 유료이다. 사이트 라이선스는 Craft의 비즈니스 모델이며,  주로 유료 호스팅 서비스를 통해 수익을 얻는 워드프레스 개발사 Automattic과는 조금 다른 비즈니스 모델이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/hellocraft/E29FB2EF-2B7E-49CF-AEF6-B1DB2B144354.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;어떤-cms를-선택할까&quot;&gt;어떤 CMS를 선택할까?&lt;/h2&gt;
&lt;p&gt;지금까지 이 글을 읽은 독자라면 Craft가 워드프레스와는 조금 다른 도구라는 것을 어렴풋이나마 느꼈을 것이다. (전혀 못 느꼈다면 그건 필자의 부족한 설명 탓이니 자책하지는 말기 바란다)&lt;/p&gt;

&lt;p&gt;사실 Craft로 할 수 있는 것은 워드프레스로도 할 수 있다. 그리고 방금 전 문장의 등식은 워드프레스 자리에 다른 솔루션들, 예를 들면 루비온레일스나 라라벨, 혹은 드루팔(Drupal) 같은 이름을 넣어도 마찬가지로 성립한다. 안되는 건 없다. 그렇다면 차이는 무엇일까?&lt;/p&gt;

&lt;p&gt;어느 게 좀 더 쉽게 할 수 있는가 (사용성), 어느 게 좀 더 잘 할 수 있는가 (생산성), 어느 게 좀 더 유연한가 (확장성), 어느게 좀 더 빠른가 (성능), 이런 정도의 차이 아닐까?&lt;/p&gt;

&lt;p&gt;그리고 그 물음에 한 가지 유일한 답은 없다. 내게(또는 우리 조직에) 놓인 상황과 필요에 따라 그 조건에 가장 잘 맞는 도구(솔루션)을 선택하는 게 답일 것이다.&lt;/p&gt;

&lt;p&gt;블로그(혹은 블로그와 유사한 글 중심의 웹사이트)를 만든다거나 이미 시중에 나와 있는 테마를 적용하면 되는 수준의 웹사이트라면 굳이 다른 솔루션 검토할 것도 없이 워드프레스를 집어드는 게 현재로선 최선일 것이다. 랜딩 페이지를 만들거나 간단한 브로셔 혹은 한두 페이지짜리 사이트라면 굳이 워드프레스까지도 필요 없다. 지킬(Jekyll) 같은 정적 웹사이트 저작도구를 쓰거나 그도 귀찮다면 그냥 직접 HTML로 만들면 그만이다. 웹앱(webapp)이나 웹서비스라면 레일스나 라라벨, 익스프레스(Express) 같은, 좀 더 자유도 높은 웹 프레임워크를 선택하는 게 옳은 방향일 것이고.&lt;/p&gt;

&lt;h3 id=&quot;그렇다면-craft는&quot;&gt;그렇다면 Craft는?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;단순 블로그 글이나 페이지가 아닌 콘텐츠 중심의 웹사이트를 만들어야 할 때&lt;/li&gt;
  &lt;li&gt;CMS가 필요하긴 한데 웹 프레임워크를 직접 다룰 여력은 없고 워드프레스로는 조금 부족함을 느낄 때&lt;/li&gt;
  &lt;li&gt;PHP나 기타 프로그래밍 언어에 대한 고민 없이 콘텐츠와 디자인에만 집중하고 싶을 때&lt;/li&gt;
  &lt;li&gt;보안이나 업데이트에 대한 걱정을 줄이고 콘텐츠 관리에만 신경쓰고 싶을 때&lt;/li&gt;
  &lt;li&gt;관리할 콘텐츠의 양이 상당히 많을 때&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이런 때라면 Craft를 한번 검토해 보자. 좋은 선택이 될 것이다. :)&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://craftcms.com/docs/introduction&quot;&gt;Craft CMS Documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://straightupcraft.com/&quot;&gt;Tutorials for Craft CMS - Straight Up Craft&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://craftcms.stackexchange.com/&quot;&gt;Craft CMS Stack Exchange&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.viget.com/articles/craft-vs.-wordpress-the-good-the-bad-and-the-ugly-data&quot;&gt;Craft vs. WordPress: The Good, the Bad, and the Ugly Data&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://coryetzkorn.com/blog/choosing-the-best-cms/&quot;&gt;Choosing the Best CMS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Grid layout을 만드는 몇 가지 기술들</title>
   <link href="/2017/03/31/a-few-ways-to-make-a-grid-layout/"/>
   <updated>2017-03-31T00:00:00+00:00</updated>
   <id>/2017/03/31/a-few-ways-to-make-a-grid-layout</id>
   <content type="html">&lt;p&gt;그리드 레이아웃(grid layout)은 웹사이트를 디자인할 때 가장 흔히 사용하는 레이아웃이다. 전통적으로 웹사이트 디자인이 인쇄물(브로셔나 잡지) 디자인으로부터 상당 부분 영향을 받은 탓도 있지만, 그리드를 사용하여 흩어져 있는 요소들을 일관성 있게 정렬하여 보여주는 것이 사용자들에게 훨씬 더 잘 와 닿는다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/grid-layouts-examples-2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;그리드 레이아웃으로 웹사이트를 만들 경우, 우선 웹사이트를 일정 수의 격자(grid)로 나누고 그 각각의 격자 속에 필요한 디자인 요소들을 적절하게 배치하는 방법으로 디자인을 하게 된다. 그렇지만 웹에서 그리드를 구현하는 방법은 한 가지가 아니다. 여러 가지가 있다. 이 글에서는 그 중 다음 몇 가지 대표적인 방법에 관해 소개한다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;테이블(table) 방식&lt;/li&gt;
  &lt;li&gt;CSS float 속성을 사용하는 방식&lt;/li&gt;
  &lt;li&gt;Flexbox 방식&lt;/li&gt;
  &lt;li&gt;CSS Grid 방식&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;table-방식&quot;&gt;Table 방식&lt;/h2&gt;

&lt;p&gt;HTML의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;table&amp;gt;&lt;/code&gt; 태그를 사용하여 가로 세로 테이블을 만들고 그 테이블의 행과 열 속에 디자인 요소들을 배치하는 방법으로, 웹 초창기부터 시작해서 소위 ‘웹표준’이라 일컫는 방식이 일반화 되기 전까지 주로 사용되어 왔던 방법이다. 당시의 웹사이트는 거의 데스크톱(PC) 브라우저만을 지원하면 되었고, 고정폭 레이아웃을 사용하는 경우가 대부분이었기 때문에 table 방식의 디자인이 잘 먹혔다. 아주 오래 전에 만들어진 사이트를 제외하면 요즘은 거의 사용하지 않는 ‘유물’ 방식이기 때문에 자세한 구현 방법은 생략한다.&lt;/p&gt;

&lt;h2 id=&quot;css-float-속성을-사용하는-방식&quot;&gt;CSS float 속성을 사용하는 방식&lt;/h2&gt;

&lt;p&gt;현재 가장 일반적으로 사용하는 그리드 레이아웃 구현 방법은 CSS float 속성을 사용하여 구성요소들을 배치하는 방법이다. 예를 들어, 다음과 같은 웹사이트 레이아웃을 만든다고 해 보자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/2017-03-31_grid-layout-demo.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서는 지면 관계와 설명의 편의를 위해 헤더 영역과 푸터 영역은 제외하고, 본문 영역과 그 아래 대표 이미지 영역만 그리드 레이아웃을 적용한다고 해 보자. 그러면 그리드는 다음과 같이 구성될 수 있다. (여기 소개하는 내용은 어디까지나 여러 방법들 중 하나일 뿐이며, 동일한 디자인에 대해서도 그리드 레이아웃을 적용하는 방법은 다양할 수 있음을 미리 밝힌다)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/2017-03-31_grid-layout-demo-guided.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;본문 영역은 메인 콘텐츠와 사이드바가 각각 2/3와 1/3 씩 차지하게끔 구성하였고, 그 아래 대표 이미지 영역은 4개의 이미지가 각각 1/4씩 자리를 차지하게끔 하였다.&lt;/p&gt;

&lt;p&gt;이 영역에 대한 HTML 마크업이 다음과 같을 경우,&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;wrap&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;main&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Qua ex cognitione facilior facta est investigatio rerum occultissimarum. Hoc dixerit potius Ennius: Nimium boni est, cui nihil est mali. Hoc loco tenere se Triarius non potuit. Diodorus, eius auditor, adiungit ad honestatem vacuitatem doloris. Itaque haec cum illis est dissensio, cum Peripateticis nulla sane. Contineo me ab exemplis. Sed ne, dum huic obsequor, vobis molestus sim. Multoque hoc melius nos veriusque quam Stoici. &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;aside&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;sidebar&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!--.wrap --&amp;gt;&lt;/span&gt; 
&lt;span class=&quot;nt&quot;&gt;&amp;lt;section&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;features&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;feature&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://fakeimg.pl/300x200/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;feature&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://fakeimg.pl/300x200/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;feature&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://fakeimg.pl/300x200/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;feature&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://fakeimg.pl/300x200/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;CSS float 속성을 사용하여 위 마크업을 그리드 레이아웃으로 만들려면 CSS 스타일을 다음과 같이 주면 된다.&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nc&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;67%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.sidebar&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;33%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.feature&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;25%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.features&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;:after&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;nl&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;both&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;각각의 요소에 width 값을 준 다음 float 속성을 사용하여 왼쪽과 오른쪽으로 띄웠다. 그런 다음, 마지막에서 소위 “clearfix”라고 하는 것을 적용하였는데, 이는 float 속성만 갖는 부모 요소가 영역을 차지하지 못하는 문제를 해결하기 위한 잘 알려진 핵(hack)이다. Clearfix 와 관련한 더 자세한 내용은 아래 문서를 참조하면 된다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://naradesign.net/wp/2008/05/27/144/&quot;&gt;float을 clear하는 4가지 방법&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 CSS float 속성을 이용한 그리드 레이아웃 구성 방법은 오늘날 웹에서 가장 일반적으로 사용되는 방법이다. CSS 프레임워크의 원조라 할 &lt;a href=&quot;http://blueprintcss.org/&quot;&gt;Blueprint&lt;/a&gt;부터 시작해서 요즘 가장 인기있는 &lt;a href=&quot;http://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt; 과 &lt;a href=&quot;http://foundation.zurb.com/&quot;&gt;Foundation&lt;/a&gt; 에 이르기 까지 많은 CSS 프레임워크들도 이 방법으로 그리드를 구성한다.&lt;/p&gt;

&lt;h2 id=&quot;flexbox&quot;&gt;Flexbox&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.w3.org/TR/css3-flexbox/&quot;&gt;Flexbox&lt;/a&gt;의 정식 명칭은 ‘CSS Flexible Box Layout ‘이며 이름 그대로 유연한(flex) 박스 모델을 위한 CSS 스펙이다. Flexbox는 여러 요소들을 플렉스 컨테이너(flex container)로 감싸는 방식으로 구현한다. 이 플렉스 컨테이너 속에 들어간 요소(자식 박스)들은 가로 세로 아주 유연하게 배치될 수 있는 것이 Flexbox의 장점이다.&lt;/p&gt;

&lt;p&gt;위 웹사이트 레이아웃 예제를 이번엔 Flexbox를 사용하여 다시 구성하려면 CSS 스타일을 다음과 같이 주면 된다.&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.wrap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.features&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;flex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.sidebar&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;flex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;잠깐 부연하면, .wrap과 .features 클래스를 flex 컨테이너로 만들었다. 어떤 요소가 flex 컨테이너가 되면, 그 속의 자식 요소들은 ‘flex 아이템(item)’이 되어 flex box 모델의 적용을 받는다. flexbox 모델의 기본 값은 각각의 자식 요소들이 동일한 크기의 영역을 차지하는 것이기 때문에 여기서 .content와 .sidebar는 flex 속성값을 각각 2와 1로 주어 .content 가 .sidebar 보다 2배 크기의 영역을 차지하게끔 선언하고 있다. .feature 이미지들은 각각 1/4(25%) 씩 균등하게 차지하면 되기 때문에 따로 선언해 주지 않았다(디폴트 값 적용).&lt;/p&gt;

&lt;p&gt;앞서 float 속성 방식과 비교하면 훨씬 간단하다. 핵(hack)도 필요없다. 게다가 Flexbox를 사용하면 가로 세로 아주 다양한 방식으로 레이아웃을 구성할 수도 있다. 또한 미디어 쿼리(media query)와 함께 사용하면 다양한 디바이스 폭에 맞춘 반응형 웹디자인 처리도 간단하게 해결된다.&lt;/p&gt;

&lt;p&gt;여기서는 Flexbox를 그리드 레이아웃을 만드는데 사용했지만, 사실 Flexbox는 비단 그리드 레이아웃을 구성하는 용도로만 사용되는 것은 아니다. 웹사이트 상에서 여러 요소들을 한 데 묶어 유연하게 레이아웃을 구성할 경우라면 여러 용도로 다양하게 활용할 수 있다. 브라우저 지원성도 좋아, 최신 브라우저들이라면 대부분이 지원한다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://caniuse.com/#feat=flexbox&quot;&gt;Flexbox 지원 브라우저&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;자세한 설명과 사용법, 용도(유스케이스)는 아래 자료들을 참조하자.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://ko.learnlayout.com/flexbox.html&quot;&gt;CSS 레이아웃을 배웁시다 : flexbox&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://philipwalton.github.io/solved-by-flexbox/&quot;&gt;Solved by Flexbox&lt;/a&gt; : CSS Flexbox의 다양한 유스케이스&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://css-tricks.com/snippets/css/a-guide-to-flexbox/&quot;&gt;A Complete Guide to Flexbox&lt;/a&gt; : 자세한 설명을 곁들인 레퍼런스&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;css-grid-layout&quot;&gt;CSS Grid Layout&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/css-grid/&quot;&gt;CSS Grid Layout&lt;/a&gt;은 그야말로 ‘그리드 레이아웃’만을 위한 CSS 모듈이다. 가로세로 격자를 만들어 그 속에 디자인 요소들을 배치하는 점에서는 앞서 table 방식의 레이아웃과 비슷하다 말할 수도 있지만, 그 구성 방법이나 유연성에 있어서는 차원이 다르다. 또한 Flexbox 처럼 미디어 쿼리와 함께 사용하면 반응형 웹 구성도 쉽게 처리할 수 있다.&lt;/p&gt;

&lt;p&gt;앞서 적용한 예제와 동일한 레이아웃을 이번엔 CSS Grid로 구현해 보면, 다음과 같이 할 수 있다. (여기서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grid-template-columns&lt;/code&gt;라는 속성으로 각각의 컬럼 폭을 명시하는 방법을 썼지만, CSS Grid에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grid-template-areas&lt;/code&gt;라는 방식으로 영역에 이름을 지정하여 처리하는 방식도 지원한다)&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.wrap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;67%&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;33%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.features&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;grid-template-columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto-fit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;25%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Flexbox에서는 display 속성을 ‘flex’로 주어 flex 컨테이너로 만들었다면, 이번엔 display 속성을 ‘grid’로 주어 grid 컨테이너로 만들었다. Flexbox와 마찬가지로, 이럴 경우 grid 컨테이너 속 자식 요소들은 ‘grid 아이템(item)’이 되어 그리드 모델의 적용을 받게 된다. 여기서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grid-template-columns&lt;/code&gt; 라는 속성을 사용하여, .wrap 클래스에서는 컬럼(즉 메인과 사이드바) 폭을 각각 67%와 33%로 주었고 그 아래 .features 클래스는 자식 요소들 각 컬럼의 폭을 25%씩 주어 균등하게 나누었다.&lt;/p&gt;

&lt;h3 id=&quot;css-grid-vs-flexbox&quot;&gt;CSS Grid vs. Flexbox&lt;/h3&gt;

&lt;p&gt;흔히 접하는 질문 중 하나는 CSS Grid Layout(이하 ‘CSS Grid’)이 앞서 소개한 Flexbox와 어떤 차이가 있냐 하는 것인데, 기본적으로 Flexbox가 가로 또는 세로 하나의 축(axis)을 기준으로 요소(박스)를 배열하는 개념인 반면, CSS Grid는 가로x세로 2차원 매트리스를 기준으로 그 속에 요소들을 배치한다는 점에서 접근 방식 자체가 다르다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/2017-03-31_cssgrid-vs-flexbox.png&quot; alt=&quot;&quot; /&gt;
* 그림 출처: &lt;a href=&quot;https://www.w3.org/TR/css-grid/#intro&quot;&gt;W3C CSS Grid Layout Module 명세&lt;/a&gt; (적색 선 추가)&lt;/p&gt;

&lt;p&gt;물론 앞서 소개한 예제의 경우, 간단하게 가로x세로 = 1x2의 간단한 그리드를 만들어 사용한 관계로 Flexbox와의 차이를 잘 느끼지 못할 수도 있지만, 가로 세로 행열의 개수가 많을수록 Flexbox와의 차이가 분명하게 드러난다.&lt;/p&gt;

&lt;p&gt;또한 Flexbox와 CSS Grid가 서로 대체 관계에 있는 것도 아니다. 둘은 함께 사용할 수 있고 또 함께 사용할 때 진정한 효과가 나올 수 있다. 예를 들어, 전체 사이트의 레이아웃은 CSS Grid로 잡고 그 속에 들어가는 갤러리 영역이나 카드 목록 같은 부분은 Flexbox를 써서 만드는 식이다.&lt;/p&gt;

&lt;p&gt;물론 CSS Grid는 아직 모든 브라우저에서 사용할 수 있는 것은 아니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://caniuse.com/#feat=css-grid&quot;&gt;CSS Grid 지원 브라우저&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/updates/2017/03/nic57&quot;&gt;크롬(Chrome) 57&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/Firefox/Releases/52&quot;&gt;파이어폭스(Firebox) 52&lt;/a&gt; 이상에서 지원되며, 이 글을 쓰는 시점에서 이틀 전인 2017년 3월 29일, &lt;a href=&quot;https://webkit.org/blog/7477/new-web-features-in-safari-10-1/&quot;&gt;사파리(Safari) 브라우저 10.1 버전에서 CSS Grid 지원&lt;/a&gt;이 발표되었다. 그렇지만 지금과 같은 지원 속도라면, 아마 모든 브라우저에서 CSS Grid를 쓸 수 있는 날이 머지 않을 듯 싶다.&lt;/p&gt;

&lt;h3 id=&quot;css-grid와-미래의-웹&quot;&gt;CSS Grid와 미래의 웹&lt;/h3&gt;

&lt;p&gt;인기있는 CSS 프레임워크인 Foundation을 개발하는 ZURB는 &lt;a href=&quot;http://zurb.com/article/1468/foundation-css-grid-think-beyond-the-page&quot;&gt;최근 블로그&lt;/a&gt;를 통해 CSS Grid가 가져올 미래 웹의 변화를 낙관하면서 다음과 같이 말하고 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The term “web page” is starting to feel very, very… inadequate. CSS Grid opens up layout in ways that were not possible before, and our minds are racing with the opportunity in front of us. We hope these experiments will get you as excited as we are, and demonstrate a little of what’s possible with this new tool.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;지금 당장은 아니라 할지라도, CSS Grid는 Flexbox와 함께 웹사이트와 웹서비스, 그리고 웹 애플리케이션 개발에 있어 새롭고 멋진 도구가 될 것임에 분명하다.&lt;/p&gt;

&lt;p&gt;CSS Grid와 관련해서 더 자세한 내용은 아래 자료들을 참조하자.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://gridbyexample.com/&quot;&gt;Grid by Example&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tympanus.net/codrops/css_reference/grid/&quot;&gt;A Complete Guide to CSS Grid&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://alistapart.com/article/practical-grid&quot;&gt;Practical CSS Grid: Adding Grid to an Existing Design&lt;/a&gt; : CSS 전문가 Eric Meyer가 최근 자신의 사이트에 CSS Grid를 적용한 내용을 소개한 글&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://msdn.microsoft.com/ko-kr/library/jj553856(v=vs.85).aspx&quot;&gt;CSS 그리드를 사용하여 적응 레이아웃을 만드는 방법&lt;/a&gt; : MSDN 문서. 마이크로소프트 IE 11 및 Edge 14 버전부터 CSS Grid를 지원하지만, MS 브라우저가 지원하는 CSS Grid Layout은 &lt;a href=&quot;https://www.w3.org/TR/2011/WD-css3-grid-layout-20110407/&quot;&gt;예전 버전&lt;/a&gt;이며, 이 글은 그 명세에 따른 것임에 유의하자.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Facebook Page를 RSS Feed로 받아보기</title>
   <link href="/2017/02/06/how-to-get-facebook-page-posts-as-rss-feed/"/>
   <updated>2017-02-06T00:00:00+00:00</updated>
   <id>/2017/02/06/how-to-get-facebook-page-posts-as-rss-feed</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/facebook-page-to-rss-feed.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 글은 페이스북 사용자들을 위한 간단한 팁(tip)입니다.&lt;/p&gt;

&lt;p&gt;“RSS 피드(Feed)”라고 하면 아주 오래된, 호랑이 담배 먹던 시절의 유물이라고 생각할 수도 있겠지만, 실은 아직도 RSS  피드는 많은 곳에서 사용되고 있습니다. 블로그나 웹사이트들은 여전히 RSS 피드로 내보내기 기능을 제공하는 경우가 많고 시중에는 RSS 구독기들도 여럿 존재합니다. 구글(Google)이 제공하던 대표적인 RSS 구독 서비스인 &lt;a href=&quot;https://www.google.com/reader/&quot;&gt;구글 리더(Google Reader)&lt;/a&gt;는 &lt;a href=&quot;https://googleblog.blogspot.kr/2013/03/a-second-spring-of-cleaning.html&quot;&gt;진즉에 종료&lt;/a&gt;되었지만,  구글 리더를 물러 받은 &lt;a href=&quot;feedly.com&quot;&gt;Feedly&lt;/a&gt; 같은 서비스는 여전히 성업 중입니다.&lt;/p&gt;

&lt;p&gt;– 참고: &lt;a href=&quot;http://techneedle.com/archives/10611&quot;&gt;Google Reader 서비스 중단 이유&lt;/a&gt; by &lt;a href=&quot;http://techneedle.com/&quot;&gt;techNeedle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;페이스북(Facebook)도 초창기(?)엔 서비스 곳곳에서 RSS를 지원했었죠. 하지만 어느 순간부턴가 RSS와 관련된 기능들은 서비스에서 하나씩 둘씩 사라졌습니다. 페이스북 페이지의 내용을 RSS로 구독할 수 있는 기능도 &lt;a href=&quot;https://developers.facebook.com/docs/apps/changelog#v2_3_90_day_deprecations&quot;&gt;2015년 중순부터 폐기&lt;/a&gt; 되어 이제 페이지의 피드를 RSS를 통해 받아 볼 수 없게 되었습니다.&lt;/p&gt;

&lt;p&gt;페이스북이 페이지 피드를 RSS로 제공하지 못한다 해서, 페이지 피드를 RSS로 받아볼 방법이 전혀 없는 건 아닙니다. 시중에는 페이스북 페이지를 RSS로 받아 볼 수 있도록 해주는 서비스들이 여럿 존재합니다. 아래는 그 중 몇몇 서비스들입니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://fetchrss.com/&quot;&gt;FetchRSS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.rssground.com/all-tools/facebook-rss-feeds-generator/&quot;&gt;Facebook RSS Feeds Generator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://fbrss.com/&quot;&gt;FB-RSS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.wallflux.com/&quot;&gt;Wallflux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그 밖에도 여러 방법들이 가능합니다. 예를 들면, &lt;a href=&quot;https://blog.dlvrit.com/2015/08/how-to-find-facebook-rss-feed/&quot;&gt;Zapier 같은 워크플로 자동화 도구를 이용하는 방법&lt;/a&gt;도 있고, 아래와 같은, 오픈소스로 공개된 툴들을 사용하는 방법도 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/RSS-Bridge/rss-bridge&quot;&gt;rss-bridge&lt;/a&gt; 는 RSS를 제공하지 않는 웹사이트에서 ATOM 피드를 생성해 주는 PHP 프로젝트.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/scottfalkingham/facebook-rss-parser&quot;&gt;facebook-rss-parser&lt;/a&gt; Facebook Graph API 결과를 RSS로 변환.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;물론 간단하게 직접 하나 만들어 쓰는 것도 어렵지 않습니다. 페이스북의 페이지 정보를 Graph API로 추출한 다음 그 결과를 RSS/Atom 형식으로 변환시키기만 하면 되기에 코드 몇 줄이면 간단하게 구현할 수 있습니다. 아래는 루비 언어로 구현한 예시입니다.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_page_posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;feed_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://graph.facebook.com/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page_id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/posts?access_token=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;fields=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;POST_FIELDS&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;feed_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;halt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;URI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;access_token&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;FACEBOOK_ACCESS_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%Q(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;FACEBOOK_APP_ID&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;FACEBOOK_APP_SECRET&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이렇게 만든 프로그램을 &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; 같은 클라우드 플랫폼에 설치해 두고 사용하면 별다른 비용 없이 유용하게 사용할 수 있을 것입니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://pagefeed.herokuapp.com/&quot;&gt;&lt;del&gt;PageFeed 데모&lt;/del&gt;&lt;/a&gt; (Heroku Dyno 용량 초과로 중단)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/usefulparadigm/pagefeed&quot;&gt;소스코드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>엘릭서(Elixir)로 JSON API 서버 만들기</title>
   <link href="/2017/02/03/building-a-json-api-server-using-elixir-and-plug/"/>
   <updated>2017-02-03T00:00:00+00:00</updated>
   <id>/2017/02/03/building-a-json-api-server-using-elixir-and-plug</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/elixir-plug-thumb.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://elixir-lang.org/&quot;&gt;엘릭서(Elixir)&lt;/a&gt;는 얼랭(Erlang) VM에서 작동하는 프로그램을 만드는 함수형 언어다.  스크립트 언어인 루비(Ruby)와 유사한 문법을 갖고 있지만 스크립트 방식과 컴파일 방식을 모두 지원하며, 특히 컴파일된 바이너리 코드는 얼랭과 완전히 호환되기 때문에 얼랭의 다양한 라이브러리와 도구들을 Elixir에서도 그대로 사용할 수 있는 장점이 있다. 게다가 &lt;a href=&quot;https://en.wikipedia.org/wiki/Concurrency_(computer_science)&quot;&gt;동시성(concurrency)&lt;/a&gt; 지원이나 &lt;a href=&quot;https://en.wikipedia.org/wiki/Fault_tolerance&quot;&gt;무정지(fault tolerance)&lt;/a&gt; 시스템과 같은, 얼랭 VM의 장점들도 고스란히 이어받을 수 있기 때문에 안정적이고 가용성 높은 서버 시스템을 구현하려 할 때 Elixir는 좋은 선택이 될 수 있다고 할 것이다.&lt;/p&gt;

&lt;p&gt;이 글에서는 엘릭서를 이용하여 간단한 JSON API 서버를 한번 만들어 보기로 한다(말이 ‘API 서버’지만 정말로 간단하니, 큰 기대는 접자).&lt;/p&gt;

&lt;p&gt;엘릭서를 처음 접하는 분들이라면 Elixir가 어떤 언어이고 웹에서는 어떻게 사용되는지 개념을 잡을 수 있는 글이 되었으면 좋겠고, JSON API 서버를 포함한 서버측 개발을 하는 분들이라면 엘릭서에 대해 좀 더 관심을 가질 수 있는 계기가 되면 좋겠다.&lt;/p&gt;

&lt;h2 id=&quot;프로젝트-시작하기&quot;&gt;프로젝트 시작하기&lt;/h2&gt;

&lt;p&gt;엘릭서를 설치하면 Mix라고 하는 작업 관리툴이 함께 설치된다(Node로 치면 grunt나 gulp와 비슷한 도구라고 생각하면 된다). 통상적으로 엘릭서 프로젝트는 이 Mix를 사용하여 새 프로젝트 구조를 만드는 것으로부터 시작한다. 터미널에서 다음과 같이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mix new&lt;/code&gt; 명령으로 새 프로젝트를 생성하자(Mix는 다양한 용도를 갖고 있는데 자세한 내용은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mix help&lt;/code&gt;로 확인할 수 있다).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix new my_app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;my_app 이라는 프로젝트 디렉터리가 만들어 졌으면 이 디렉터리로 들어가서 디렉터리 구조를 한번 살펴보자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/elixir-my_app-tree.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;mix.exs 파일은 프로젝트의 설정과 관련된 파일이며 lib 디렉터리 아래에 프로그램의 소스코드가 위치한다. config 디렉터리 아래의 config.exs 파일은 애플리케이션의 설정에서 사용하는 파일이다.&lt;/p&gt;

&lt;h2 id=&quot;의존-라이브러리-추가하기&quot;&gt;의존 라이브러리 추가하기&lt;/h2&gt;

&lt;p&gt;우리가 만들 프로그램은 어떤 임의의 URL을 입력하면 JSON 형식의 텍스트를 반환하는 간단한 API 서버다. 이를 위해 이 프로그램에서는 엘릭서에서 웹 애플리케이션 기능을 제공할 때 사용하는 표준 라이브러리인 &lt;a href=&quot;https://hex.pm/packages/plug&quot;&gt;Plug&lt;/a&gt;과 JSON을 처리하는 &lt;a href=&quot;https://hex.pm/packages/poison&quot;&gt;Poison&lt;/a&gt; 라이브러리를 사용할 것이다.&lt;/p&gt;

&lt;p&gt;mix.exs 파일을 열어 끝 부분에 있는 deps 함수를 다음과 같이 수정하자. 이 부분은 프로젝트에서 의존하는 라이브러리를 추가하는 부분이다. 이 때 함께 추가한 &lt;a href=&quot;https://github.com/ninenines/cowboy&quot;&gt;Cowboy&lt;/a&gt;는 실은 Erlang HTTP Server이며, Plug에서 필요로 하기 때문에 함께 추가한 것이다.&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;defp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:cowboy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~&amp;gt; 1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:plug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~&amp;gt; 1.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;~&amp;gt; 3.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 상태로 명령행에서 아래 mix 명령을 실행하면 원격의 라이브러리 소스가 로컬 프로젝트 속으로 import 된다(npm install 이나 go get 명령을 떠올리면 된다).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix deps.get
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;다음으로, 같은 파일에 있는 application 함수를 아래와 같이 수정하자. 마찬가지로 이 프로젝트에서 사용될 애플리케이션들을 선언하는 부분이다(엘릭서에서는 각각의 라이브러리가 하나의 독립된 애플리케이션이며 따라서 Elixir 프로젝트는 결국 여러 애플리케이션들이 서로 어울려 작동하는 구조가 된다).&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;applications:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:plug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;hello-elixir&quot;&gt;Hello, Elixir!&lt;/h2&gt;

&lt;p&gt;이제 프로그램을 만들기 위해 필요한 준비는 끝이 났다. 실제 API 부분을 구현하는 일만 남았다. lib 디렉터리 아래에 있는 my_app.ex 파일을 열자. 프로그램에서 필요한 코드는 이 파일 속에 추가하면 된다.&lt;/p&gt;

&lt;p&gt;여기서 잠깐! 바로 API 서버를 구현하기에 앞서, 우선 Elixir와 간단하게 인사부터 나누자!&lt;/p&gt;

&lt;p&gt;먼저 간단하게 my_app.ex 파일 속에 다음과 같이 코드를 한번 추가해 보자. MyApp이라는 모듈 내에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init/1&lt;/code&gt; 이라는 함수와 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call/2&lt;/code&gt; 라는 함수를 추가하고, call 함수 속에서 다시 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Plug.Conn.send_resp/3&lt;/code&gt; 함수를 호출하였다.&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyApp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# initialize options&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_opts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Plug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello, Elixir!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;여기까지 작성하였으면, 이제 명령행에서 다음과 같이 IEx를 통해 Elixir의 인터랙티브 환경에 접속하자. IEx는 Elixir의 대화형 콘솔이며(루비의 irb 같은), 이 때 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-S&lt;/code&gt; 옵션은 iex를 실행할 때 mix.exs 스크립트도 함께 로드하라는 의미다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ iex -S mix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;잘 따라 왔다면 다음과 같이 콘솔이 열렸을 것이다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 상태에서 앞서 mix 설정에서 추가한 웹서버인 Cowboy HTTP 서버를 실행하자.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iex(1)&amp;gt; Plug.Adapters.Cowboy.http MyApp, []
{:ok, #PID&amp;lt;0.180.0&amp;gt;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{:ok, #PID&amp;lt;xxx&amp;gt;}&lt;/code&gt; 가 떨어지면 정상이다. 앞서 우리가 만든 MyApp 모듈이 Cowboy 웹서버와 연동되어 실행되었다. 이 상태에서 웹브라우저나 curl 명령으로 http://localhost:4000/ 에 접속하여 확인해 보면 예상대로 “Hello, Elixir!”가 출력되는 것을 확인할 수 있을 것이다.&lt;/p&gt;

&lt;h2 id=&quot;웹-애플리케이션과-plug&quot;&gt;웹 애플리케이션과 Plug!&lt;/h2&gt;

&lt;p&gt;생각보다 간단하게 끝났다. 기대한 것보다 너무 시시했다면 아마도 Plug를 사용한 탓일 것이다. 지금까지는 별 말 없이 Plug 라이브러리를 사용했지만, 여기서는 잠깐 간단하게라도 Plug에 대해 소개하고 넘어가기로 하자.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/plug/readme.html&quot;&gt;Plug 소개 페이지&lt;/a&gt;에서는 Plug을 다음과 같이 소개하고 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2017/elixir-plug-is.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;즉, Plug은 1) 엘릭서 기반 웹 애플리케이션들 간 상호 호환가능한 모듈을 만들기 위한 명세이자 2) 다양한 웹서버들과의 연결을 위한 어댑터 역할을 하는 라이브러리이다.&lt;/p&gt;

&lt;p&gt;비슷한 냄새를 맡았다면, 맞다! 바로 루비의 &lt;a href=&quot;https://rack.github.io/&quot;&gt;Rack&lt;/a&gt;과 유사한 개념이다(실제로 엘릭서 언어를 만든 &lt;a href=&quot;https://github.com/josevalim&quot;&gt;José Valim&lt;/a&gt;은 Rails Contributer이기도 하다). Rack과 다른 점이라면, Plug은 라우터(router) 기능까지 제공한다는 점이다(&lt;a href=&quot;http://www.sinatrarb.com/&quot;&gt;Sinatra&lt;/a&gt;의 router 기능을 Plug에서는 기본으로 제공한다).&lt;/p&gt;

&lt;p&gt;Plug에 대한 더 자세한 설명은 &lt;a href=&quot;https://hexdocs.pm/plug/readme.html&quot;&gt;Plug 문서&lt;/a&gt;에 잘 소개되어 있으니 여기서는 생략하기로 하고, 방금 소개한 Plug의 라우터 기능을 이용해 우리의 구현 목표인 API 서버로 한 발짝 더 나가 보자.&lt;/p&gt;

&lt;h2 id=&quot;api-서버-구현하기&quot;&gt;API 서버 구현하기&lt;/h2&gt;

&lt;p&gt;우리가 만들 API 서버는 예컨대 URL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/users/tom&lt;/code&gt; 을 호출하면 사용자 프로필 정보를 JSON 형식으로 출력하는 간단한 API 서버가 될 것이다. 이제 이를 위해 my_app.ex 파일의 코드를 약간 수정하자.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/plug/readme.html#the-plug-router&quot;&gt;Plug Router&lt;/a&gt;를 사용하면 코드는 다음과 같이 간단해 진다.&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;defmodule&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MyApp&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Plug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Router&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;plug&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:match&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;plug&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:dispatch&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/users/:name&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;put_resp_content_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;send_resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Poison&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(%{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;send_resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;oops&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;코드를 잠깐 부연하면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get &quot;/users/:name&quot; do&lt;/code&gt; 부분에서 URL 맵핑을 통해 웹요청을 처리하고 있으며, 마지막 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;match _ do&lt;/code&gt; 부분은 이도 저도 아닌 나머지 요청에 대한 처리(catch-all) 루틴이다. 코드 중간의 약간 이상한 모양의 ‘&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;|&amp;gt;&lt;/code&gt;‘는 Elixir의 파이프(pipe) 연산자다(Unix의 파이프와 같은 개념이다).&lt;/p&gt;

&lt;p&gt;루비 개발자라면 코드가 왠지 좀 익숙하게 느껴질 것이다. Plug Router는 실제로 루비의 Sinatra 라우터와 상당히 유사한 &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;DSL&lt;/a&gt;을 갖는다. Elixir는 &lt;a href=&quot;http://elixir-lang.org/getting-started/meta/macros.html&quot;&gt;매크로(macro)&lt;/a&gt; 라는 방식으로 &lt;a href=&quot;https://en.wikipedia.org/wiki/Metaprogramming&quot;&gt;메타 프로그래밍&lt;/a&gt;을 지원하기 때문에 위와 같이 DSL 스타일의 코드를 간단하게 만들어 낼 수 있는 것이다.&lt;/p&gt;

&lt;h2 id=&quot;명령행에서-api-서버-실행하기&quot;&gt;명령행에서 API 서버 실행하기&lt;/h2&gt;

&lt;p&gt;이제 마무리다. 지금까지는 API 서버를 실행하려면 IEx에 접속하여 Cowboy 어댑터를 호출해야 했다. 이제 명령행에서 직접 API 서버를 실행할 수 있도록 변경해 보자.&lt;/p&gt;

&lt;p&gt;우선 mix.exs 파일을 열어 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/0&lt;/code&gt; 함수를 다음과 같이 변경하자.&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;applications:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:cowboy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:plug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:poison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;mod:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MyApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]}]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mod&lt;/code&gt; 키를 추가하여, 애플리케이션이 시작될 때 실행할 시작 모듈을 MyApp으로 지정하였다.&lt;/p&gt;

&lt;p&gt;이제 메인 코드로 와서 파일 속 적당한 곳에 다음과 같이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start/2&lt;/code&gt; 함수를 추가하자(이 함수는 애플리케이션이 시작될 때 호출되는 콜백callback 함수다).  그런 다음 이 함수 속에서 Cowboy 웹서버를 실행한다.&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Plug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Adapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Cowboy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;__MODULE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;마지막으로 터미널에서 다음과 같이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mix run&lt;/code&gt; 명령을 실행하면,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mix run --no-halt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;굳이 IEx로 접속하지 않고도 API 서버가 작동되는 것을 확인할 수 있을 것이다. 프로덕션(production) 환경에서라면 Nginx 같은 웹서버를 이 API 서버 앞단에 &lt;a href=&quot;https://en.wikipedia.org/wiki/Reverse_proxy&quot;&gt;리버스 프록시(reverse proxy)&lt;/a&gt;로 두는 방식도 가능하다.&lt;/p&gt;

&lt;p&gt;이것으로 간단한 엘릭서 기반 API 서버 구현에 대한 설명을 마친다. 이 글은 Elixir 웹 개발에 필요한 기본을 따라가려다 보니 미처 설명하지 못한 부분들이 더러 있다. 예를 들면,&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;데이터 저장소와의 연동&lt;/strong&gt;. 실제로라면 API 호출 시에 결과값을 반환하기 위해 RDBMS나 NoSQL 등 여러 유형의 데이터 저장소로부터 데이터를 추출하여 결과를 반환해야 할 것이다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Supervisor 처리&lt;/strong&gt;. Erlang/OTP에는 &lt;a href=&quot;http://erlang.org/doc/man/supervisor.html&quot;&gt;수퍼바이저(Supervisor)&lt;/a&gt; 라고 하는 기능(이를 ‘비헤비어behaviour’라 부른다)이 제공되며, Elixir에서도 이 &lt;a href=&quot;https://hexdocs.pm/elixir/Supervisor.html&quot;&gt;수퍼바이저&lt;/a&gt; 기능을 지원한다. 이를 이용하면 supervisor/worker 방식의 프로세스 구성을 쉽게 처리할 수 있지만, 여기서는 이 부분은 생략하였다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;여기서는 Elixir 웹 개발의 기본 툴이라 할 수 있는 Plug을 가지고 API 서버를 구현했지만, 만약 좀 더 다양한 기능을 갖춘 서버를 좀 더 쉽게(?) 만들려면 다음과 같은 도구들도 고려해 볼만 하다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.phoenixframework.org/&quot;&gt;Phoenix Framework&lt;/a&gt;: Ruby on Rails 같은 범용 Elixir 웹 프레임워크&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://maru.readme.io/&quot;&gt;Maru&lt;/a&gt;: Elixir REST API Framework&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 글에서 사용한 소스코드와 이렇게 만든 앱을 &lt;a href=&quot;heroku.com&quot;&gt;Heroku&lt;/a&gt;에 배포하는 방법은 &lt;a href=&quot;https://github.com/sjoonk/my_plug_app&quot;&gt;GitHub&lt;/a&gt;에서 확인할 수 있다.&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;p&gt;Elixir와 Plug에 대해 좀 더 깊게 공부해 보고 싶은 분들이라면, 앞서 본문에서 소개한 문서들 외에도 아래 자료를 참고하면 좋을 것 같다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://elixir-lang.org/crash-course.html&quot;&gt;Elixir Crash Course&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://elixirschool.com/&quot;&gt;Elixir School&lt;/a&gt; Plug 튜토리얼: &lt;a href=&quot;https://elixirschool.com/lessons/specifics/plug/&quot;&gt;영문&lt;/a&gt;, &lt;a href=&quot;https://elixirschool.com/ko/lessons/specifics/plug/&quot;&gt;국문&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>AWS Lambda와 API Gateway로 Slack Bot 만들기</title>
   <link href="/2016/04/06/creating-a-slack-bot-with-aws-lambda-and-api-gateway/"/>
   <updated>2016-04-06T00:00:00+00:00</updated>
   <id>/2016/04/06/creating-a-slack-bot-with-aws-lambda-and-api-gateway</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/serverless-slack-lambda-gateway.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;slack.com/&quot;&gt;슬랙(Slack)&lt;/a&gt;은 팀이나 프로젝트 단위에서 널리 사용되고 있는 대표적인 협업 메시징 서비스다. 통상적인 메신저 서비스들이 갖는 기본적인 메시징 기능에 더하여 자료를 저장하고 검색하는 등 협업에 필요한 여러 기능들을 갖추고 있고, 또한 모바일과 데스크톱 환경을 아우르는 편리하고 다양한 접점을 제공하기 때문에 많은 사용자층을 확보하고 있는 인기있는 서비스이기도 하다. 게다가 슬랙은 사용자나 개발자가 직접 기능을 확장하고 용도를 변경할 수 있는 다양한 통합(integration) 방법들도 제공한다.&lt;/p&gt;

&lt;p&gt;이 글에서는 슬랙이 제공하는 다양한 확장 방법들을 간단히 소개하고 그 중 하나인 슬래시 명령(slash command)을 만들어 보려 한다. 뒤에서 다시 설명하겠지만, 슬래시 명령을 만들기 위해서는 슬래시 명령을 처리할 별도의 호스팅 환경이 필요한데, 여기서는  Amazon 웹서비스(이하 ‘AWS’)에서 제공하는 &lt;a href=&quot;https://aws.amazon.com/ko/lambda/&quot;&gt;AWS Lambda&lt;/a&gt;와 &lt;a href=&quot;https://aws.amazon.com/ko/api-gateway/&quot;&gt;API Gateway&lt;/a&gt;를 사용하여 호스팅을 처리하려 한다.&lt;/p&gt;

&lt;h2 id=&quot;slack을-확장하는-방법들&quot;&gt;Slack을 확장하는 방법들&lt;/h2&gt;

&lt;p&gt;슬랙은 “&lt;a href=&quot;https://api.slack.com/custom-integrations&quot;&gt;통합(Integration)&lt;/a&gt;” 이라는 이름으로 다양한 확장 방법들을 제공한다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://api.slack.com/incoming-webhooks&quot;&gt;Incoming Webhooks&lt;/a&gt; : 외부 서비스나 앱에서 슬랙으로 웹요청을 보낼 수 있다.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://api.slack.com/outgoing-webhooks&quot;&gt;Outgoing Webhooks&lt;/a&gt; : Incoming Webook과는 반대로, 특정 슬랙 채널 또는 메시지 내에서 특정한 단어가 나올 경우 슬랙에서 외부로 웹요청을 보낼 수 있다.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://api.slack.com/slash-commands&quot;&gt;Slash Commands&lt;/a&gt; : 슬래시(/) 문자로 시작하는 슬랙 명령을 추가로 만들어 넣을 수 있다.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://api.slack.com/bot-users&quot;&gt;Bot Users&lt;/a&gt; : 제목 그대로 ‘봇 사용자’이다. 일반적인 (사람) 사용자와 마찬가지로 슬랙의 사용자 목록에 상주해 있으면서 다른 사용자의 질문에 답을 하거나 서로 대화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;기본적으로 이런 통합은 자신이 관리하는 슬랙 계정 내에 설치하여 사용할 수 있지만 필요한 경우에는 &lt;a href=&quot;https://api.slack.com/slack-apps&quot;&gt;앱(Slack App)&lt;/a&gt;으로 만들어 다른 팀 사용자들도 사용할 수 있도록 공개도 가능하며 더 나아가 슬랙의 &lt;a href=&quot;https://slack.com/apps&quot;&gt;앱 디렉터리&lt;/a&gt;에 등록할 수도 있다. 또한 슬랙에서 할 수 있는 대부분의 작업들은 별도의 &lt;a href=&quot;https://api.slack.com/web&quot;&gt;Web API&lt;/a&gt;로 공개되어 있기 때문에 이 API를 이용하면 여러 가지 더 다양한 슬랙 확장을 구현할 수도 있다.&lt;/p&gt;

&lt;h2 id=&quot;슬래시-명령slash-command-만들기&quot;&gt;슬래시 명령(Slash Command) 만들기&lt;/h2&gt;

&lt;p&gt;슬랙에서 사용자는 슬랙의 대화창에서 슬래시(/) 문자로 시작하는 명령을 호출할 수 있으며 이 때 사용하는 명령을 &lt;strong&gt;슬래시 명령&lt;/strong&gt;이라고 부른다. 예를 들어, 슬랙에서 어떤 채널에 다른 사용자를 초대할 경우 대화창에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/invite @name&lt;/code&gt; 이라고 명령하면 된다. 슬랙에서는 이런 슬랙이 기본적으로 제공하는 명령(Built-in Commands) 말고도 자신의 팀에서만 사용할 명령(Custom Commands)을 추가로 만들어 넣을 수 있는 확장 기능을 제공한다.&lt;/p&gt;

&lt;p&gt;슬래시 명령을 만들려면 다음과 같은 절차를 따르면 된다:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;슬랙에서 자신의 계정에 로그인한 다음, “&lt;a href=&quot;https://slack.com/apps/build&quot;&gt;Apps &amp;amp; Integrations&lt;/a&gt;” 메뉴로 들어가 “Build a Custom Integration” 창에서 &lt;a href=&quot;my.slack.com/services/new/slash-commands/&quot;&gt;새 슬래시 명령&lt;/a&gt;을 만든다.&lt;/li&gt;
  &lt;li&gt;이 슬래시 명령을 받아서 처리할 웹 서버를 구현한 다음, 그 URL값을 슬랙의 슬래시 명령 설정 창에 추가한다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;구현은 아주 간단하다. 예를 들어, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/hello&lt;/code&gt; 라는 슬래시 명령을 하나 추가로 만들려면 이 명령에 대응하는 웹 URL만 하나 만들어 맵핑시키면 된다. 그러면 슬랙에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/hello&lt;/code&gt; 라는 명령이 들어오면 슬랙은 해당 명령과 연결된 URL로 웹요청을 보내고 그 결과값을 받아 슬랙의 대화창에 다시 표시한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/slack-slash-commands.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 때 슬랙이 외부 URL로 HTTP 요청을 보낼 때 실어 보내는 데이터는 다음과 같은 형식이다. 아래 데이터는 슬랙의 대화창에서 ‘&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/weather 94070&lt;/code&gt;‘이라고 주었을 때 슬랙이 보내는 데이터의 샘플인데, 슬래시 명령 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/weather&lt;/code&gt; 뒤에 추가되는 값 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;94070&lt;/code&gt;이 HTTP 데이터 상에는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;text&lt;/code&gt;라는 키값으로 잡힌다는 데 유의하자(나중에 이 값을 받아 사용할 것이다).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;token=gIkuvaNzQIHg97ATvDxqgjtO
team_id=T0001
team_domain=example
channel_id=C2147483705
channel_name=test
user_id=U2147483697
user_name=Steve
command=/weather
text=94070
response_url=https://hooks.slack.com/commands/1234/5678
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 값을 전달받은 웹서버 측에서는 &lt;a href=&quot;https://api.slack.com/docs/formatting&quot;&gt;Slack의 메시지 형식&lt;/a&gt;에 맞춰 메시지를 구성하여 다음과 같이 JSON 형식으로 다시 슬랙에 반환하면 된다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
    &quot;text&quot;: &quot;I am a test message http://slack.com&quot;,
    &quot;attachments&quot;: [
        {
            &quot;text&quot;: &quot;And here's an attachment!&quot;
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 때 HTTP 요청은 GET/POST 방식 모두 가능하며(단, 슬랙 앱으로 만들 경우에는 반드시 POST 방식을 써야 함), POST 방식으로 보낼 경우 헤더의 Contet-Type은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/x-www-form-urlencoded&lt;/code&gt;로 지정된다. 더 자세한 내용은 &lt;a href=&quot;https://api.slack.com/slash-commands&quot;&gt;슬래시 명령 API 문서&lt;/a&gt;를 참조하면 된다.&lt;/p&gt;

&lt;p&gt;그럼 실제 만들어 보자. 슬래시 명령을 만들려면 우선 Slack에 로그인한 다음 Slack에서 제공하는 &lt;a href=&quot;my.slack.com/services/new/slash-commands/&quot;&gt;새 슬래시 명령 만들기&lt;/a&gt; 창에 접속하여 필요한 정보를 입력하는 것부터 시작하면 된다. 이 창에서 만들고자 하는 슬래시 명령을 입력하고 “Add Slash Command Integration” 버튼을 클릭하면 나만의 커스텀 슬래시 명령이 생성된다. 여기서는 간단하게 검색어를 &lt;a href=&quot;https://ko.wikipedia.org/&quot;&gt;위키피디어&lt;/a&gt;와 연결하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/wiki&lt;/code&gt; 라는 명령을 하나 추가해 보기로 하겠다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/create-new-slash-command.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이어 나오는 페이지에서는 슬래시 명령에 대응하는 URL을 적어주면 된다. 아직 우리는 웹서버를 만들지 않았기 때문에 일단 이 부분은 비워 두자. 나중에 채울 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/slash-commands-settings.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이걸로 끝이다. 참고로, 이 때 함께 제공되는 토큰(Token)은 등록된 URL로 들어오는 요청이 슬랙에서 보낸 것이 맞는지 확인하는 용도로 사용하면 된다.&lt;/p&gt;

&lt;h2 id=&quot;슬랙-봇-호스팅하기&quot;&gt;슬랙 봇 호스팅하기&lt;/h2&gt;

&lt;p&gt;이제 앞서 비워둔 URL 칸을 채워 보자. 이를 위해서는 어딘가에 웹서버를 하나 만들어 두고 슬랙에서 넘어오는 슬래시 명령을 받아서 슬랙 메시지 형태로 반환하는 코드를 작성해야 한다. 웹서버는 웹요청을 받아 처리할 수 있는 환경이라면 뭐든 상관 없지만, 여기서는 아마존 웹서비스에서 제공하는 &lt;a href=&quot;https://aws.amazon.com/ko/lambda/&quot;&gt;AWS 람다(Lambda)&lt;/a&gt;를 사용하여 슬래시 명령을 호스팅해 보기로 한다.&lt;/p&gt;

&lt;h3 id=&quot;lambda-함수-만들기&quot;&gt;Lambda 함수 만들기&lt;/h3&gt;

&lt;p&gt;AWS Lambda는 “&lt;a href=&quot;https://aws.amazon.com/ko/lambda/details/&quot;&gt;이벤트에 응답하여 코드를 실행하고 자동으로 기본 컴퓨팅 리소스를 관리하는 컴퓨팅 서비스&lt;/a&gt;“라고 소개되어 있다. 지금과 같이 경량의 함수 수준의 간단한 로직을 만들어 올리고 즉시 실행하는데는 제격인 서비스다. 그럼 &lt;a href=&quot;https://console.aws.amazon.com/lambda/home&quot;&gt;AWS Lambda Console&lt;/a&gt;에 접속하여 새로운 람다 함수(Lambda function)를 하나 만들어 보자(Lambda는 현재 US East와 EU를 포함한 몇몇 리전에서만 제공된다). Lambda에는 슬랙 앱을 만들 때 사용할 템플릿(Blueprint)도 제공되지만, 여기서는 템플릿 없이 직접 만들기로 한다.&lt;/p&gt;

&lt;p&gt;“Create a Lambda function” 버튼을 눌러 시작하고 “Select blueprint” 창은 그냥 Skip 하면 다음과 같이 Lambda 함수를 추가하고 설정할 수 있는 창이 나온다. 여기서 적당한 함수 이름을 주고 코드를 추가한 다음 저장하면 람다 함수가 만들어 진다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/aws-lambda-configure.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 코드를 작성할 차례다. 2016년 4월 현재 AWS Lambda는 3개의 프로그래밍 언어(Node.js, Python, Java)만 지원한다. 여기서는 그 중 Node.js를 사용하기로 한다. 다음에서 보듯 코드는 아주 간단하다. 요청을 받아 응답을 반환하는 게 전부다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// The entry point of this lambda function.
exports.handler = function(event, context) {
  console.log(event);

  context.succeed({
    &quot;response_type&quot;: &quot;in_channel&quot;,
    &quot;text&quot;: &quot;I found some about \&quot;&quot; + event.text + &quot;\&quot;&quot;,
    &quot;attachments&quot;: [
        {
            &quot;text&quot;: &quot;For more info please visit to \nhttps://ko.wikipedia.org/wiki/&quot; + event.text,
            &quot;color&quot;: &quot;#7CD197&quot;
        }
    ]
  });

};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;앞서 설명한 대로 슬랙에서 넘어오는 값인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;text&lt;/code&gt;를 받아서 메시지를 구성하였다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;context.succeed()&lt;/code&gt; 함수는 AWS Lambda에서 사용하는 반환 함수이며, 이 함수의 인자로 슬랙의 메시지를 담아 반환하면 된다. 이 때 반환값은 JSON 형식으로 작성하면 되고, &lt;a href=&quot;https://api.slack.com/docs/formatting&quot;&gt;슬랙의 메시지 형식&lt;/a&gt;에 맞추면 된다. 슬랙에서는 메시지 출력을 미리 보고 테스트해 볼 수 있도록 &lt;a href=&quot;https://api.slack.com/docs/formatting/builder&quot;&gt;Message Builder&lt;/a&gt;도 제공하기 때문에 더 쉽게 메시지를 테스트해 볼 수 있다.&lt;/p&gt;

&lt;p&gt;Lambda에 관한 더 자세한 내용은 &lt;a href=&quot;http://aws.amazon.com/documentation/lambda/&quot;&gt;AWS Lambda 문서&lt;/a&gt;를 참조하면 된다.&lt;/p&gt;

&lt;h3 id=&quot;api-gateway-연동하기&quot;&gt;API Gateway 연동하기&lt;/h3&gt;

&lt;p&gt;Lambda 함수는 기본적으로 이벤트에 반응한다. 여기서 말하는 이벤트는 아마존 웹서비스에서 발생하는 어떤 것이다(예를 들면 S3에 어떤 파일을 추가하는 것과 같은 이벤트). 그렇지만 우리에게 필요한 것은 웹 URL이다. AWS Lambda를 웹 호출을 통해 실행시키려면 또다른 아마존 웹서비스 중 하나인 &lt;a href=&quot;https://aws.amazon.com/ko/api-gateway/&quot;&gt;Amazon API Gateway&lt;/a&gt;를 연결해야 한다.&lt;/p&gt;

&lt;p&gt;역시 이번에도 &lt;a href=&quot;https://console.aws.amazon.com/apigateway/home&quot;&gt;AWS API Gateway Console&lt;/a&gt;로 접속하여 새 API를 하나 만들자. “Create API” 버튼을 누르고 새로 만들 API의 이름을 입력하면 API 리소스(Resources) 설정 창이 나온다. 이 때 새로 Resource와 Method를 추가해 주면 간단하게 지금 사용할 API가 만들어진다. 여기서 말하는 리소스와 메서드는 흔히 사용하는 &lt;a href=&quot;https://ko.wikipedia.org/wiki/REST&quot;&gt;REST&lt;/a&gt; 방식의 API에서 말하는 그 리소스와 메서드 개념을 생각하면 된다. 앞서 우리는 Slack에서 슬래시 명령을 설정할 때 POST 방식으로 호출하기로 정했기 때문에 여기서 메서드도 POST로 맞춰 생성하였다. 그런 다음, Integration Type을 “Lambda Function”으로 맞추고 방금 전 만든 람다 함수를 연결시켜 주면 API Gateway와 Lambda 함수 간의 연결이 완료된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/api-gateway-lambda-mapping.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기까지 하면 API와 람다 함수 간의 연결 작업은 완료되지만, 한 가지 남은 일이 있다. Slack이 API를 통해 보낸 값을 람다 함수가 제대로 받아서 처리하게 하려면 약간의 데이터 변환이 필요하다. Slack은 API를 호출할 때 HTML Form 형식으로 데이터를 전달하지만  API Gateway를 통해 람다함수로 전해지는 데이터는 기본적으로 JSON 형식이기 때문에 Slack으로부터 받은 POST 데이터를 Lambda 함수가 처리할 수 있도록 변환하는 작업을 해 줘야 한다. 이 작업은 API Gateway의 Method Execution 설정 창에서 할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/api-gateway-method-execution.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 Method Execution 창에 나와 있는 4가지 변환 과정 중 우리가 건드릴 부분은 “Integration Request” 영역이다. 이 단계는 API로 들어온 요청을 Lambda 함수로 보내기 직전 단계이며, 이 단계에서 다음과 같이 “Mapping Template”을 추가해 주면 된다. 이 때 Content-Type을 “application/x-www-form-urlencoded” 로 설정한 이유는, 앞서 잠깐 언급했듯이, Slack이 슬래시 명령을 호출할 때 이 방식을 사용하기 때문이며, 아직 Amazon API Gateway에서는 폼 방식의 데이터를 JSON 형식으로 변환하는 부분을 제공하지 않기 때문에 &lt;a href=&quot;https://gist.github.com/sjoonk/20ae13e5cd8be88e9824e3bad11b2859&quot;&gt;폼 방식의 POST 데이터를 JSON으로 변환시키는데 필요한 맵핑 루틴&lt;/a&gt;을 직접 만들어서 추가한 것이다(아마 조만간 API Gateway에서 이 부분은 자동화시킬 것으로 예상되지만). API Gateway의 Mapping Template과 관련된 더 자세한 내용은 &lt;a href=&quot;http://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html&quot;&gt;Amazon API Gateway 문서&lt;/a&gt;를 참조하자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/api-gateway-mapping-template.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;지금까지의 모든 작업을 완료했으면 이제 API를 배포하는 일만 남았다. (물론 그 전에 API가 제대로 작동하는지 테스트하는 일이 남았지만 테스트 단계 부분의 설명을 생략한다) API의 배포는 AWS 콘솔에서 Deploy API 메뉴를 실행하면 된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/agi-gateway-deploy-api.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;배포가 성공적으로 완료되면 API의 URL이 발급된다. 이 URL을  앞서 만든 슬랙의 슬래시 명령 설정 창의 URL 입력란에 붙여 넣으면 하나의 슬래시 명령이 완성되는 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/api-gateway-invoke-url.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;hello-슬랙-봇&quot;&gt;Hello, 슬랙 봇!&lt;/h3&gt;

&lt;p&gt;이제 이 모든 작업이 끝났으면 Slack으로 돌아오자. 슬랙의 대화창에서 다음과 같이 방금 우리가 만든 슬래시 명령을 입력하면 Slack 봇이 반갑게 우리를 맞아 줄 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/slack-wiki-alphago.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;add-to-slack-버튼-만들기&quot;&gt;Add to Slack 버튼 만들기&lt;/h2&gt;

&lt;p&gt;Slack 봇(이 경우 슬래시 명령)을 내 슬랙 계정의 팀 내에서만 사용한다면 여기까지가 끝이다. 그렇지만 공들여 만든 Slack 봇을 세상에 공개하여 다른 팀에서도 활용할 수 있게 하고 싶은 경우에는 지금까지 만들었던 슬랙 봇을 앱(Slack Apps)으로 만들어 공개할 수도 있다. 이 때 다른 팀에서 자신의 슬랙 계정에 내 슬랙 봇(앱)을 쉽게 추가할 수 있도록 해 주는 방법이 바로 “Add to Slack” 버튼을 만들어 웹사이트나 서비스 홈페이지에 공개하는 것이다. (아마 웹을 돌아다니다 보면 이 버튼이 달려 있는 사이트나 서비스들을 종종 보게 될 것이다. 앞으로 점점 더 많이^^)&lt;/p&gt;

&lt;p&gt;슬랙은 Add to Slack 버튼(이하 ‘슬랙 버튼’)을 간단하게 만들어 사이트에 붙일 수 있도록 해 주는 &lt;a href=&quot;https://api.slack.com/docs/slack-button&quot;&gt;자동 코드 생성기&lt;/a&gt;를 제공하기 때문에 슬랙 버튼을 만들어 붙이는 일은 전혀 어려울 게 없다. 그저 복사해서 붙여 넣으면 그만이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2016/add-to-slack-button.png&quot; alt=&quot;Add to Slack 버튼&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다만 이 슬랙 버튼이 제대로 작동하려면 OAuth 인증을 거쳐야 한다. 슬랙 앱은 &lt;a href=&quot;https://api.slack.com/docs/oauth&quot;&gt;OAuth 2.0&lt;/a&gt; 기반의 인증을 사용하며 인증 플로(flow)는 OAuth 2.0의 &lt;a href=&quot;https://tools.ietf.org/html/rfc6749#section-4.1&quot;&gt;코드 기반 인증 방식&lt;/a&gt;을 따른다. 그러므로 슬랙 버튼을 만들기 위해서는 이 OAuth 인증 처리 부분을 별도로 만들어 주어야 한다.&lt;/p&gt;

&lt;p&gt;이 부분도 물론 앞서 사용했던 AWS Lambda와 API Gateway를 이용해 만들 수도 있겠지만, OAuth 인증을 통해 받은 액세스 토큰(Access Token) 값이나 기타 다른 정보들을 저장하였다가 다시 사용하고 하기 위해서는 Lambda 보다는 &lt;a href=&quot;https://aws.amazon.com/ko/ec2/&quot;&gt;EC2&lt;/a&gt;나 &lt;a href=&quot;https://cloud.google.com/&quot;&gt;구글 클라우드&lt;/a&gt; 또는 &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; 같은 전통적인(?) 호스팅 플랫폼을 사용하는 것이 더 좋을 것 같다.&lt;/p&gt;

&lt;p&gt;OAuth 인증의 처리는 Google이나 Facebook, Twitter 등 여타 다른 OAuth 기반의 서비스에서 사용하는 방식과 크게 다르지 않고 이미 많은 자료들이 공개되어 있기 때문에 여기서 구현 설명은 생략하기로 한다.&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://api.slack.com/&quot;&gt;Slack API 문서&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.aws.amazon.com/lambda/latest/dg&quot;&gt;AWS Lambda Developer Guide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://docs.aws.amazon.com/apigateway/latest/developerguide/&quot;&gt;Amazon API Gateway Developer Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>모바일 웹사이트에 구글 AMP 적용하기</title>
   <link href="/2016/02/24/adding-the-google-amp-to-mobile-website/"/>
   <updated>2016-02-24T00:00:00+00:00</updated>
   <id>/2016/02/24/adding-the-google-amp-to-mobile-website</id>
   <content type="html">&lt;p&gt;최근 모바일 콘텐츠 플랫폼을 둘러 싼 속도(speed) 경쟁이 뜨겁다. 작년 초 페이스북(Facebook)이 자사의 모바일 앱에 최적화된 콘텐츠를 제공하는 &lt;a href=&quot;https://instantarticles.fb.com/&quot;&gt;인스턴트 아티클&lt;/a&gt;(Instant Articles)을 출시한 것을 시작으로, 이어 애플이 &lt;a href=&quot;https://www.apple.com/news/&quot;&gt;애플뉴스&lt;/a&gt;를, 그리고 지난해 하반기에 구글이 &lt;a href=&quot;https://www.ampproject.org/&quot;&gt;AMP&lt;/a&gt;(Accelerated Mobile Pages, 우리말로는 “빠른 게재 모바일 페이지”)라는 모바일 콘텐츠 최적화 표준을 들고 나오면서 소위 “인스턴트(instant)”한 콘텐츠를 앞세운 플랫폼 간의 경쟁이 가속화된 듯 하다.&lt;/p&gt;

&lt;p&gt;이 중 구글이 제시한 모바일 콘텐츠 최적화 표준인 AMP에 대해 조금 알아보기로 하자.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/google-amp-project.png&quot; alt=&quot;Google AMP Project&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;amp란&quot;&gt;AMP란?&lt;/h2&gt;

&lt;p&gt;AMP는 한마디로 말해 모바일 콘텐츠 최적화 표준이다. 뉴스나 블로그 같은 정적인 콘텐츠를 만들어 배포하는 온라인 매체가 이 AMP 표준에 맞춰 콘텐츠를 작성하여 게시하면 기존의 모바일 콘텐츠보다 &lt;a href=&quot;https://www.ampproject.org/how-it-works/&quot;&gt;약 15% ~ 85%의 성능 향상을 가져올 수 있다&lt;/a&gt;고 구글은 주장한다. 이를 위해 AMP는 웹 콘텐츠 제작에 사용되는 기술에 제약을 가한다. 한마디로 속도를 떨어뜨리는 기술의 사용을 배제함으로써 속도의 향상을 꽤하는 방법인 셈이다.&lt;/p&gt;

&lt;p&gt;예를 들어, 아래 2개의 링크는 같은 워싱턴포스트의 기사를 각각 일반적인 HTML 페이지와 AMP로 나눠 보여준 것이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.washingtonpost.com/lifestyle/style/six-ways-the-martian-subverts-expectations/2015/10/05/6bba4d42-6873-11e5-8325-a42b5a459b1e_story.html&quot;&gt;일반적인 HTML 페이지&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.washingtonpost.com/amphtml/lifestyle/style/six-ways-the-martian-subverts-expectations/2015/10/05/6bba4d42-6873-11e5-8325-a42b5a459b1e_story.html&quot;&gt;AMP 페이지&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;보면 알 수 있듯, AMP 페이지는 일반적인 HTML 페이지에서 광고나 자바스크립트, CSS 애니메이션 등과 같은 동적인 요소들을 제거하여 “알맹이”만 남겨 둔다. 물론 그렇다고 광고나 자바스크립트를 삽입하지 못한다는 의미는 아니고, 구글 AMP에서 정한 규약에 맞춰야 한다는 말이다. 통상적으로 웹사이트에서 속도를 느리게 만드는 요소들에 제약을 가하니 당연히 속도는 빨라 질 밖에 없다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/normal-html-vs-amp.png&quot; alt=&quot;일반 웹문서 vs. AMP 문서&quot; /&gt;
– 출처: Washington Post&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.ampproject.org/docs/get_started/about-amp.html&quot;&gt;구글 공식 문서&lt;/a&gt;에 다르면 AMP는 다음 3가지 요소로 구성된다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;AMP HTML&lt;/li&gt;
  &lt;li&gt;AMP JS&lt;/li&gt;
  &lt;li&gt;Google AMP Cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 중 AMP HTML은 기존의 HTML 문서에서 속도에 부담을 주는 요소를 배제하고 몇몇 확장 속성들을 추가한 일종의 HTML 확장이고, AMP JS는 이런 AMP HTML을 읽고 렌더링하는 런타임(Runtime) 이다. 그리고 Google AMP Cache는 구글이 제공하는 AMP HTML 문서의 캐싱 서비스이다. 즉 AMP 문서를 만들어 올리면 구글이 자체 CDN을 통해 더 빠른 액세스를 할 수 있게 해주는 것이다.&lt;/p&gt;

&lt;p&gt;이렇게 작성된 AMP, 즉 “빠른 게재 모바일 페이지”는 모바일 디바이스 환경에서 구글 검색(Google Search)을 수행할 경우 기존의 웹페이지를 대체하여 보여지게 되고, 따라서 사용자는 보다 빠른 모바일 사용자 경험을 얻게 되는 것이다.&lt;/p&gt;

&lt;p&gt;물론 속도를 얻기 위해 희생해야 하는 것들도 많다. 예를 들어, 외부 자바스크립트를 사용할 수 없다거나 &lt;a href=&quot;https://www.ampproject.org/docs/guides/responsive/style_pages.html&quot;&gt;CSS&lt;/a&gt;도 하나만 링크를 걸 수 있고 인라인 스타일이나 속도에 부담을 주는 요소들을 쓸 수 없다. 또한 이미지나 미디어 파일의 경우 기존의 HTML 방식과는 다른 AMP 표준에서 제시하는 &lt;a href=&quot;https://www.ampproject.org/docs/guides/amp_replacements.html&quot;&gt;별도의 커스텀 요소&lt;/a&gt;를 써야 하는 식이다.&lt;/p&gt;

&lt;p&gt;AMP에 대한 더 자세한 내용은 아래 참고자료를 참고하면 되며, 특히 구글 AMP가 어떤 방식으로 웹페이지의 속도를 개선하는지에 대한 더 자세한 내용은 구글이 공개한 &lt;a href=&quot;https://www.ampproject.org/docs/get_started/technical_overview.html&quot;&gt;How AMP Speeds Up Performance&lt;/a&gt; 문서를 참고하면 좋을 것이다.&lt;/p&gt;

&lt;h2 id=&quot;amp-문서-만들기&quot;&gt;AMP 문서 만들기&lt;/h2&gt;

&lt;p&gt;AMP 문서는, 그 문서만도 만들 수 있지만, 통상적인 경우 기존 웹문서(원본 문서)가 있고 그에 대한 대응으로, 별도 문서 즉 원본 문서에 대한 모바일 최적화된 버전의 문서로 만드는 것이 일반적일 것이다. 예를 들어 기존에 온라인 매체가 있어서 콘텐츠를 게시하고 있는 경우 이들 각각의 콘텐츠에 대해 AMP 문서를 만들어 기존의 문서와 1:1로 대응하는 AMP 문서를 한 벌로 만드는 방식이다.&lt;/p&gt;

&lt;p&gt;AMP 문서는 &lt;a href=&quot;https://github.com/ampproject/amphtml/blob/master/spec/amp-html-format.md&quot;&gt;AMP HTML 규격&lt;/a&gt;을 따라야 하며 AMP HTML은 다음과 같은 형식을 갖는다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html amp lang=&quot;en&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
    &amp;lt;link rel=&quot;canonical&quot; href=&quot;http://example.com/original-article.html&quot; &amp;gt;
    &amp;lt;meta name=&quot;viewport&quot;
          content=&quot;width=device-width,minimum-scale=1,initial-scale=1&quot;&amp;gt;
    &amp;lt;style&amp;gt;body {opacity: 0}&amp;lt;/style&amp;gt;
    &amp;lt;noscript&amp;gt;
      &amp;lt;style&amp;gt;body {opacity: 1}&amp;lt;/style&amp;gt;
    &amp;lt;/noscript&amp;gt;
    &amp;lt;script async src=&quot;https://cdn.ampproject.org/v0.js&quot;&amp;gt;
    &amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    Hello, Mobile World!
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;HTML 문서의 형식은 일반적인 문서와 다를 게 없어 보이지만 html 태그에 커스텀 속성으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amp&lt;/code&gt;(또는 이모지 ⚡)가 추가되어 이 문서가 일반 HTML 문서가 아닌 AMP HTML 문서임을 표현하고 있으며, 공식 링크(canonical link) 값을 원래의 웹문서로 향하게 만들어 이 AMP 문서의 원 출처와 연결시키고 있다. style 부분에서는 AMP 문서 렌더링 과정에서 발생할 수 있는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Flash_of_unstyled_content&quot;&gt;FOUC&lt;/a&gt;를 방지하기 위해 시작 시점의 opacity 값을 0으로 두고 있다. 마지막으로 script 태그에서 AMP 런타임 자바스크립트 모듈을 비동기 방식으로 호출하면 AMP JS에 의해 문서가 처리된다. 그 밖에도 여러 가지 마크업에 대한 제약사항들이 있는데 더 자세한 내용은 &lt;a href=&quot;https://www.ampproject.org/docs/get_started/create/basic_markup.html&quot;&gt;구글의 공식 문서&lt;/a&gt;를 참조하면 된다.&lt;/p&gt;

&lt;p&gt;이미지 파일 같은 경우는 다음과 같이 amp-img 라고 하는 AMP 표준에서 제공하는 별도의 커스텀 태그를 사용해야 하고 width값과 height값을 반드시 명시해야 한다. AMP 런타임이 이미지의 렌더링 위치와 시점을 정확하게 제어할 수 있게 하기 위함이다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;amp-img src=&quot;welcome.jpg&quot; alt=&quot;Welcome&quot; height=&quot;400&quot; width=&quot;800&quot;&amp;gt;&amp;lt;/amp-img&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;비디오나 트위터 박스, 또는 구글 분석기 코드나 광고 태그 같은 것들도 마찬가지로 AMP 표준에서 제공하는 커스텀 태그를 이용하여 처리하여야 한다. 예를 들어, 동영상 파일을 웹페이지 속에 삽입할 경우에는 다음과 같이 amp-video 태그를 써야 하며,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;amp-video width=400 height=300 src=&quot;https://yourhost.com/videos/myvideo.mp4&quot;
    poster=&quot;myvideo-poster.jpg&quot;&amp;gt;
  &amp;lt;div fallback&amp;gt;
    &amp;lt;p&amp;gt;Your browser doesn’t support HTML5 video&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;source type=&quot;video/mp4&quot; src=&quot;foo.mp4&quot;&amp;gt;
  &amp;lt;source type=&quot;video/webm&quot; src=&quot;foo.webm&quot;&amp;gt;
&amp;lt;/amp-video&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;트위터 트윗을 임베드시킬 경우는 &lt;a href=&quot;https://www.ampproject.org/docs/guides/third_party_components.html&quot;&gt;써드파티 컴포넌트인 amp-twitter 태그를 사용&lt;/a&gt; 하는 식이다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;amp-twitter width=390 height=50
    layout=&quot;responsive&quot;
    data-tweetid=&quot;638793490521001985&quot;&amp;gt;
&amp;lt;/amp-twitter&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;문서-간-연결&quot;&gt;문서 간 연결&lt;/h2&gt;

&lt;p&gt;앞서도 잠깐 언급 했듯이 AMP 문서와 기존 웹문서 간에는 공식 링크(canonical link)를 통해 서로 연결된다. 예를 들어, AMP 문서에서는 다음과 같이 link 태그를 이용해 공식 문서(원본 문서)로의 링크를 삽입하고,&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;link rel=&quot;canonical&quot; href=&quot;https://www.example.com/url/to/full/document.html&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;원본 문서에는 다음과 같이 amphtml 문서의 위치를 지정함으로써 서로 연결된다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;link rel=&quot;amphtml&quot; href=&quot;https://www.example.com/url/to/amp/document.html&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/amphtml-canonical-link.png&quot; alt=&quot;원본문서와 AMP문서 간 연결&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;amp-문서-검증하기&quot;&gt;AMP 문서 검증하기&lt;/h2&gt;

&lt;p&gt;이렇게 만든 AMP 문서는 구글 크롬 브라우저의 개발자 도구 콘솔을 통해 검증(validation)할 수 있다. AMP 문서 URL 뒤에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#development=1&lt;/code&gt; 해시문자열을 추가하면 검증 결과가 콘솔에 표시된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/Web_Image_2016-02-24_16-53-32.png&quot; alt=&quot;AMP Validation&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;cms에-amp-적용하기&quot;&gt;CMS에 AMP 적용하기&lt;/h2&gt;

&lt;p&gt;CMS를 사용하고 있는 경우라면, 아마도 곧 많은 CMS가 AMP를 지원하는 모듈을 만들어 제공하지 않을까 싶다. 여기서는 전세계 25% 이상의 CMS 점유율을 자랑하는 [워드프레스(WordPress)][https://wordpress.org/]와 인기있는 정적(static) 웹사이트 저작도구인 &lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;에서 AMP를 적용하는 방법만 간단히 소개한다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jekyll&lt;/strong&gt;의 경우는 플러그인을 통해 사이트를 빌드하는 과정에서 AMP를 적용할 수 있다. 구글의 AMP 프로젝트 공식 문서 사이트가 Jekyll을 사용하여 작성되었기 때문에 이를 참조하면 좋을 것이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/juusaw/amp-jekyll&quot;&gt;amp-jekyll&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/ampproject/docs&quot;&gt;ampproject/docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;워드프레스&lt;/strong&gt;는 AMP가 출시된 이후로 계속해서 &lt;a href=&quot;https://vip.wordpress.com/2015/10/07/mobile-web/amp/&quot;&gt;AMP 프로젝트와 보조를 맞추어 오고 있다&lt;/a&gt;. 워드프레스 개발사인 Automattic이 참여하여 최근 출시한 &lt;a href=&quot;https://wordpress.org/plugins/amp/&quot;&gt;AMP 플러그인&lt;/a&gt; 같은 경우, 플러그인을 설치하는 것만으로 AMP 문서를 자동 생성해 준다. 또한 워드프레스닷컴(wordpress.com) 사이트의 경우 &lt;a href=&quot;https://en.blog.wordpress.com/2016/02/24/amp-for-wordpress-dot-com/amp/&quot;&gt;워드프레스가 이미 자동으로 AMP 문서를 생성&lt;/a&gt;하기 때문에 사용자가 별도로 할 일은 없다.&lt;/p&gt;

&lt;p&gt;또한 일반적인 워드프레스 사용자들이라면 구글 AMP 뿐 아니라 페이스북 Instant Articles와 애플의 Apple News 포맷까지 모두 지원하는 &lt;a href=&quot;http://pagefrog.com/&quot;&gt;PageFrog&lt;/a&gt;라는 플러그인도 이미 나와 있기 때문에 이를 검토해 봐도 좋을 듯 싶다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/pagefrog-screenshot-1.png&quot; alt=&quot;PageFrog&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;amp의-현재와-미래&quot;&gt;AMP의 현재와 미래&lt;/h2&gt;

&lt;p&gt;구글 검색엔진은 어떤 웹문서가 AMP 버전의 문서를 가질 경우 이 문서를 처리하여 모바일 웹 검색결과에 AMP 문서임을 표시하고 사용자가 AMP 문서가 딸린 웹문서를 모바일 디바이스를 통해 클릭했을 경우 기존 웹문서가 아닌 AMP 문서를 보여준다(2016-02-24 현재, &lt;a href=&quot;http://searchengineland.com/live-google-launches-amp-results-in-mobile-search-results-243147&quot;&gt;구글 검색에 이미 적용되었다고 보도&lt;/a&gt;되고 있지만, 아직 국내에는 적용되지 않은 듯 하다). 번개마크 달린 AMP 아이콘이 표시(아래 그림) 되는데, 공교롭게도 페이스북의 인스턴트 아티클도 포스팅 위에 번개마크를 표시하고 있어 재밌다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/Web_Image_2016-02-24_17-09-37.png&quot; alt=&quot;AMP 적용 예제&quot; width=&quot;300px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;아직 국내에서는 AMP를 적용한 사례는 없어 보이지만 아마도 &lt;a href=&quot;http://www.bloter.net/archives/250056&quot;&gt;곧 많은 언론사 사이트와 온라인 매체가 AMP를 적용할 것&lt;/a&gt;으로 보인다. 게다가 페이스북이 &lt;a href=&quot;http://media.fb.com/2016/02/17/opening-up-instant-articles/&quot;&gt;올 4월에 있을 F8 컨퍼런스에서 인스턴트 아티클을 모든 매체에 개방&lt;/a&gt;하기로 이미 선언한 상태이기에 두 “빠름” 간의 경쟁도 더욱 가속화될 듯 싶다.&lt;/p&gt;

&lt;p&gt;다만 AMP가 W3C 표준은 아니라는 점, 다른 콘텐츠 관련 벤더들의 참여와 지원이 얼마나 되느냐 하는 점, 원본 문서와는 별개로 또 하나의 문서를 만들어야 한다는 온라인 매체(콘텐츠 제공자)들의 부담 등은 AMP가 앞으로 풀어야 할 숙제로 보인다. 물론 앞으로 모바일 디바이스 성능이 더 좋아져 AMP 같은 해법이 필요 없어질 날이 오면 더 좋겠지만.&lt;/p&gt;

&lt;p&gt;마침 지난 해 가을에 서울에서 열린 “&lt;a href=&quot;https://www.youtube.com/watch?v=3omUr_q_wz0&amp;amp;list=PL6OeXcmhVzfSsbqs0hAfOnRuSFulsfopX&quot;&gt;Google for Mobile 2015&lt;/a&gt;” 컨퍼런스 동영상이 최근 공개가 되었다. 그 날 세션 중 AMP를 소개한 세션 영상이 들어 있으니, 시간나는 분들은 한번 보는 것도 좋을 듯 싶다.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; style=&quot;width: 100%&quot; src=&quot;https://www.youtube.com/embed/mrjzoH-rvjI&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ampproject.org/&quot;&gt;Accelerated Mobile Pages Project&lt;/a&gt; (프로젝트 공식 웹사이트)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://d2.naver.com/news/7976742&quot;&gt;AMP: Accelerated Mobile Pages&lt;/a&gt; 네이버 D2 News&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Calypso와 WordPress의 미래</title>
   <link href="/2015/11/25/calypso-and-the-future-of-wordpress/"/>
   <updated>2015-11-25T00:00:00+00:00</updated>
   <id>/2015/11/25/calypso-and-the-future-of-wordpress</id>
   <content type="html">&lt;p&gt;엊그제(2015/11/23), &lt;a href=&quot;https://wordpress.com/&quot;&gt;WordPress.com&lt;/a&gt;의 개발사이자 운영사인 &lt;a href=&quot;https://automattic.com/&quot;&gt;Automattic&lt;/a&gt;에서 코드명을 ‘&lt;a href=&quot;https://developer.wordpress.com/calypso/&quot;&gt;칼립소(Calypso)&lt;/a&gt;‘로 명명한 새로운 워드프레스 어드민 인터페이스를 선보였습니다. 이미 WordPress.com에 적용되었고 설치형 워드프레스를 사용하는 경우도 &lt;a href=&quot;http://jetpack.me/&quot;&gt;JetPack 플러그인&lt;/a&gt;을 연동한 사이트라면 마찬가지로 이 새 인터페이스를 사용할 수 있습니다. 여기에 더해 칼립소 코드 자체는 오픈소스로 &lt;a href=&quot;https://github.com/Automattic/wp-calypso&quot;&gt;GitHub&lt;/a&gt;에 공개하였고 &lt;a href=&quot;https://desktop.wordpress.com/&quot;&gt;맥 사용자들을 위한 데스크톱용 앱&lt;/a&gt;도 함께 출시하였습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/introducing-wp-calypso.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;얼핏 생각하면, 하루가 멀다하게 새로운 기능과 업데이트들을 쏟아내고 있는 워드프레스가 새 인터페이스를 하나 선보인 게 뭐 그리 대수로운 일일까 생각할 수 있습니다. 혹은 갑작스런 인터페이스의 변화에 짜증이 나거나 조금 당황스러워하는 사용자들도 있을 것입니다. 인터페이스가 좀 변하긴 했지만 예전보다 기능도 좋아졌고 또 더 빨라졌다고 하니 그냥 새 인터페이스에 적응하면서 쓰면 되지 하고 생각하면 그만입니다.&lt;/p&gt;

&lt;p&gt;그런데 워드프레스라는 하나의 플랫폼(platform) 입장에서 바라보면 이번의 이 변화는 기존의 여느 판올림들과는 성격이 조금 다른, “제법 중요한” 시도입니다. 왜 그런지, 그리고 이번의 이 칼립소 프로젝트가 &lt;a href=&quot;http://w3techs.com/technologies/history_overview/content_management/all/y&quot;&gt;이미 전 세계 웹사이트의 약 25%를 장악&lt;/a&gt;하고 있는 워드프레스의 미래에 어떤 영향을 미칠 수 있을지 한번 생각해 보기로 하겠습니다.&lt;/p&gt;

&lt;p&gt;우선 칼립소 프로젝트가 무엇인지부터 정확하게 알 필요가 있습니다. 오픈소스로 공개된 &lt;a href=&quot;https://github.com/Automattic/wp-calypso&quot;&gt;칼립소 프로젝트의 GitHub&lt;/a&gt;에는 칼립소를 다음과 같이 소개하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/what-is-calypso.png&quot; alt=&quot;About Calypso&quot; /&gt;&lt;/p&gt;

&lt;p&gt;즉, 칼립소는 싱글페이지 웹앱(Single Page Webapp) 방식으로 제작된 WordPress.com의 새로운 관리자 대시보드로, WordPress.com의 &lt;a href=&quot;https://developer.wordpress.com/docs/api/&quot;&gt;REST API&lt;/a&gt;를 기반으로 동작합니다. 기술적으로는 &lt;a href=&quot;https://nodejs.org/en/&quot;&gt;Node&lt;/a&gt;나 &lt;a href=&quot;http://expressjs.com/&quot;&gt;Express&lt;/a&gt;, &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt;와 &lt;a href=&quot;https://facebook.github.io/flux/&quot;&gt;Flux&lt;/a&gt; 같은 최근 프론트엔드 중심의 웹개발에서 흔히 사용하는 인기있는 오픈소스 기술들을 사용하였습니다.&lt;/p&gt;

&lt;p&gt;그럼 뭐가 바뀐걸까요? 알다시피 기존의 워드프레스는 PHP 기반이었습니다. 물론 프로그램 여기저기에서 자바스크립트(특히 jQuery)가 사용되고 있었지만, 주는 어디까지나 서버측 웹 개발 언어인 PHP를 기반으로 하고 있었습니다. 그런데 이번의 칼립소 프로젝트에는 PHP가 단 한줄도 사용되지 않았습니다. 대신 서버측 구현에는 Node/Express를 사용하여 thin 서버 방식으로 처리하고 실제 모든 기능들은 React와 JavaScript, 그리고 워드프레스의 REST API를 사용하여 클라이언트 측에서 처리하는 것으로 바뀌었습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/wp-calypso-languages.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;얼핏 생각하기엔, 최근 새로운 블로깅 플랫폼으로 각광받는 &lt;a href=&quot;https://medium.com/&quot;&gt;미디엄&lt;/a&gt;이나 워드프레스의 대안으로 떠오르는 Node 기반의 CMS 플랫폼인 &lt;a href=&quot;https://ghost.org/&quot;&gt;ghost&lt;/a&gt;를 따라한건가 하는 생각도 들 것입니다. 워드프레스가 지금껏 10년 넘게 써오던 PHP를 버리고 Node 기반으로 갈아탄 건가하는 의문도 생길 수 있습니다. 물론 전혀 아닙니다. 워드프레스(엔진) 자체는 여전히 PHP 기반으로 동작하고 그 사실은 앞으로도 변화가 없을 것입니다. 다만 이번 칼립소 프로젝트의 시도는 워드프레스가 기존의 웹사이트 제작 도구에서 한걸음 더 나아가 웹애플리케이션을 위한 기반 플랫폼으로서의 변화를 시도한 것이라고 보는 것이 맞을 것입니다.&lt;/p&gt;

&lt;p&gt;즉, 지금까지의 워드프레스가 PHP를 기반으로, 어드민 대시보드와 플러그인 시스템, 그리고 테마가 모두 한데 결합되어 있는 방식이었다면(아래 그림),&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/wp-architecture-asis.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;앞으로의 워드프레스는 아마도 이런 그림이 될 듯 싶습니다. 즉 워드프레스는 콘텐츠를 저장하고 관리하는 API 서버로 동작하고, 대시보드와 테마를 포함한 모든 프론트엔드는 이 API 서버의 클라이언트로서 독립해서 동작하는 방식입니다. 이번의 칼립소 프로젝트는 이에 기반한 워드프레스의 공식적인 첫 번째 시도구요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/wp-architecture-future.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;어떻게 보면 이번 실험은 이미 시장을 완전히 장악한 벤더가 시도하기엔 조금 무모한 실험 같아 보이기도 합니다. 그래서인지 Automattic의 CEO인 매트 뮬렌웨그((Mattew Mullenweg)는 &lt;a href=&quot;http://ma.tt/2015/11/dance-to-calypso/&quot;&gt;칼립소 프로젝트를 소개하는 그의 블로그&lt;/a&gt;를 다음과 같은 말로 시작하고 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;One of the hardest things to do in technology is disrupt yourself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;스스로를 뒤엎는 일. 아마도 쉬운 결정은 아니었을 것입니다. 이미 10년의 역사를 가진, 게다가 지금 현재 세상에서 가장 높은 시장점유율과 인기를 구가하고 있는 제품이 채택하기엔 더더군다나 쉬운 결정이 아니었으리라 짐작됩니다. 그렇지만 변화하는 웹과 기술 환경에서 오래도록 살아남기 위해 워드프레스가 취한 이번 결정은 아마도 워드프레스, 그리고 워드프레스 생태계에 속해 있는 많은 개발사들과 개발자들에게 새로운 도전과 함께 새로운 기회들을 던져 줄 것이라 생각이 듭니다.&lt;/p&gt;

&lt;p&gt;물론 여러 가지 해결할 문제들도 남아 있습니다. 얼핏 생각해도 PHP 기반으로 되어 있는 워드프레스의 확장시스템을 어떻게 새 시스템으로 교체할 건지, 아직 SEO 측면에서 완전한 해결책이 제시되고 있지 않은 SPA환경을 워드프레스가 어떤 식으로 해결할지, 기존의 플러그인과 테마 시스템과의 관계는 어떻게 가져갈지 등등. 하지만 칼립소가 세상에 나오기 훨씬 이전부터 워드프레스를 웹 애플리케이션 개발을 위한 도구로 활용하려는 움직임들이 워드프레스 개발자들 사이에는 여기저기서 있어 왔고, 이제 워드프레스에서 조차 공식적으로 ‘새로운 방향’을 제시한 셈이니, 앞으로는 지금까지와는 완전히 차원이 다른 새로운 생각 더 좋은 시도와 실험들이 워드프레스와 오픈소스 커뮤니티에서 생겨날 것은 분명해 보입니다.&lt;/p&gt;

&lt;p&gt;아래 표는 &lt;a href=&quot;https://developer.wordpress.com/blog/&quot;&gt;워드프레스 개발자 블로그&lt;/a&gt;에서 제공하는, 칼립소가 기존의 WordPress.com과 비교해 무엇이 바뀌었는지를 보여주는 표입니다. 정말이지, 누구 말처럼, “바뀐 건 오직 하나, 전부!” 이로군요.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://developer.files.wordpress.com/2015/11/whats-new-wpcom2x2.png&quot; alt=&quot;&quot; /&gt;
출처: &lt;a href=&quot;https://developer.wordpress.com/2015/11/23/the-story-behind-the-new-wordpress-com/&quot;&gt;The Story Behind the New WordPress.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;공교롭게도 이번에 칼립스가 발표된 날이 &lt;a href=&quot;https://en.blog.wordpress.com/2005/11/23/opening-it-up/&quot;&gt;WordPress.com이 세상에 나온지 꼭 10년이 되는 날&lt;/a&gt;이라는군요. 10년이면 긴 세월이죠. 오랜 시간을 워드프레스와 함께 해 온 워드프레스 개발자들에겐 새로운 숙제와 먹거리가 가득 생긴 날이기도 합니다. :)&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>워드프레스로 웹서비스(온라인 모임) 만들기</title>
   <link href="/2015/10/21/creating-the-online-meetup-site-with-wordpress/"/>
   <updated>2015-10-21T00:00:00+00:00</updated>
   <id>/2015/10/21/creating-the-online-meetup-site-with-wordpress</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/usefulpablog/2015/10/moiming-featured-cover.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;통상적으로 워드프레스는 웹사이트를 만드는 도구로 알려져 있으며 지금도 개인이나 기업의 블로그나 정적인 웹사이트를 만드는데 주로 쓰이고 있는 것이 사실입니다. 그렇지만 최근 워드프레스는 강력한 CMS 기능과 유연한 확장성 등을 기반으로 사용자 기반 웹서비스나 동적인 웹애플리케이션 개발에도 사용되고 있습니다. 특히 최근 업데이트된 &lt;a href=&quot;http://v2.wp-api.org/&quot;&gt;WP REST API&lt;/a&gt;는 워드프레스를 웹서비스의 기반 플랫폼으로도 사용할 수 있는 가능성을 분명하게 보여줍니다.&lt;/p&gt;

&lt;strike&gt;유스풀패러다임에서는 워드프레스로 웹서비스 만들기 튜토리얼을 수 회에 걸쳐 저희 [디지털 마케팅의 기술](http://blog.usefulparadigm.com/) 블로그를 통해 연재하려고 합니다. 연재 순서는 아래와 같으며 글이 올라오는대로 이 페이지는 계속해서 업데이트할 예정입니다. 많은 관심 부탁 드립니다.&lt;/strike&gt;

&lt;h4 id=&quot;1-모임목록-만들기&quot;&gt;1. &lt;a href=&quot;http://blog.usefulparadigm.com/archives/286&quot;&gt;모임목록 만들기&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;워드프레스의 커스텀 포스트 유형(Custom Post Type) 기능을 활용하여 “모임” 유형을 만들고 메인 화면에 모임 목록을 표시합니다.&lt;/p&gt;

&lt;h4 id=&quot;2-새-모임-개설하기&quot;&gt;2. &lt;a href=&quot;http://blog.usefulparadigm.com/archives/290&quot;&gt;새 모임 개설하기&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;사용자가 프론트엔드(frontend)에서 직접 모임을 만들고 저장할 수 있는 기능을 구현합니다.&lt;/p&gt;

&lt;h4 id=&quot;3-사용자-로그인하기&quot;&gt;3. &lt;a href=&quot;http://blog.usefulparadigm.com/archives/291&quot;&gt;사용자 로그인하기&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;로그인한 사용자만 모임을 만들 수 있도록 사용자 로그인 기능을 추가합니다.&lt;/p&gt;

&lt;h4 id=&quot;4-모임-참가신청-받기&quot;&gt;4. &lt;a href=&quot;http://blog.usefulparadigm.com/archives/292&quot;&gt;모임 참가신청 받기&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;사용자가 모임에 참가 신청을 하고 참가신청자 목록을 볼 수 있는 기능을 구현합니다.&lt;/p&gt;

&lt;h4 id=&quot;5-지도와-지역별-메뉴&quot;&gt;5. &lt;a href=&quot;http://blog.usefulparadigm.com/archives/300&quot;&gt;지도와 지역별 메뉴&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;모임에 날짜와 장소 정보를 추가하고 장소 정보에 기반한 지역별 메뉴를 구현합니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;UPDATE(2016-06-30)&lt;/strong&gt; 워드프레스로 모임서비스 만들기는 &lt;a href=&quot;https://wpguide.usefulparadigm.com/&quot;&gt;WordPress 가이드&lt;/a&gt;로 자리를 옮겼습니다.&lt;/p&gt;

&lt;h4 id=&quot;소스코드&quot;&gt;소스코드:&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/usefulparadigm/moiming-twentyfifteen&quot;&gt;https://github.com/usefulparadigm/moiming-twentyfifteen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>웹앱을 위한 REST API 서버 솔루션들</title>
   <link href="/2015/09/08/rest-api-server-solutions-for-web-app/"/>
   <updated>2015-09-08T00:00:00+00:00</updated>
   <id>/2015/09/08/rest-api-server-solutions-for-web-app</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/rest-api-server-solutions.png&quot; alt=&quot;REST API Server Solutions&quot; /&gt;&lt;/p&gt;

&lt;p&gt;모바일 환경이 사용자 경험의 중심으로 자리잡으면서 애플리케이션 개발에서도 프론트엔드(frontend) 영역이 차지하는 비중이 갈수록 커지고 있습니다. iOS나 Android 같은 모바일앱은 말할 것도 없고 웹앱 영역에서도 ‘한페이지 앱(&lt;a href=&quot;https://en.wikipedia.org/wiki/Single-page_application&quot;&gt;Single Page Application&lt;/a&gt;)’의 필요성은 점점 증가하고 있습니다. 이런 추세는 당연히 프론트엔드 웹개발 프레임워크들에도 반영이 되어 &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt; 를 필두로 &lt;a href=&quot;https://angularjs.org/&quot;&gt;Angular&lt;/a&gt;나 &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember&lt;/a&gt;, 그리고 최근 hot한 바람몰이를 하고 있는 &lt;a href=&quot;https://facebook.github.io/react/index.html&quot;&gt;React&lt;/a&gt;에 이르기까지 대부분의 프레임워크들이 모두 한페이지 내에서 처리되는 웹앱을 만드는데 초점이 맞춰져 있습니다.&lt;/p&gt;

&lt;p&gt;이런 프론트엔드 중심 개발 흐름은 기존의 서버 중심 웹개발을 상당 부분 ‘무력화’시킵니다. 웬만한 렌더링(rendering)은 서버에서 모두 처리되어 클라이언트는 그저 서버로부터 받은 “화면”을 잘 뿌리기만 하면 되던 때는 이제 아련한 옛추억이 되어가고 있습니다. 오늘날 서버는 갈수록 API 서버, 특히 REST 기반의 API 서버로 탈바꿈하여 클라이언트의 요청에 맞춰 JSON 데이터를 제공하는 역할을 담당하는 쪽으로 변했습니다.&lt;/p&gt;

&lt;p&gt;사실 서버를 개발하는 입장에서는 웹 브라우저나 여러 가지 렌더링 이슈들에 신경쓸 필요 없이 단순하게 데이터를 클라이언트로 넘기기만 하면 되기 때문에 예전보다 훨씬 할일이 줄어들었다고도 할 수 있습니다. 그렇지만 다양한 프론트엔드 측의 처리를 효과적으로 지원하기 위해서는 REST API의 비중 또한 커지기 마련입니다. ‘그저’ JSON 데이터를 보내는데 그치는 게 아니라 API의 설계부터 HTTP 연동, 데이터 패킷 구성이나 API 인증과 같은 다양한 이슈들의 처리가 중요해집니다.&lt;/p&gt;

&lt;p&gt;그렇다면 이런 프론트엔드 웹앱을 지원하기 위한 REST API 서버로 사용할 수 있는 솔루션에는 어떤 것들이 있을까요? 더 다양한 방법들이 많이 있겠지만 여기서는 크게 구축형과 설치형, 그리고 클라우드 서비스로 나눠 간단하게 몇 가지만 소개해 보기로 합니다. 웹앱이 중심이지만 여기서 소개한 REST API 서버 솔루션들은 모바일앱의 백엔드(backend)로도 동일하게 사용될 수 있습니다.&lt;/p&gt;

&lt;h2 id=&quot;구축형-솔루션&quot;&gt;구축형 솔루션&lt;/h2&gt;

&lt;p&gt;구축형 솔루션은 말 그대로 API 서버를 직접 구축하는 것입니다. 지구 상에 존재하는 거의 대부분의 프로그래밍 언어는 웹개발을 지원하기 때문에 그 중 선호하는 언어를 사용하여 API 서버를 구성할 수 있겠지만, 그 전에 시중에 나와있는 툴킷(toolkit)이나 프레임워크(framework)들은 없는지 먼저 검토하는 것이 “바퀴를 새로 만들지 않는” DRY한 방법입니다. 저희는 주로 서버측 API 개발에 루비(ruby)를 사용하기 때문에 루비를 중심으로 소개하면 다음과 같은 솔루션들이 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;sinatra&quot;&gt;&lt;a href=&quot;http://www.sinatrarb.com/&quot;&gt;Sinatra&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;시나트라(Sinatra)는 간단한 웹 애플리케이션을 신속하게 만들 수 있게 해주는 루비기반 웹개발 툴킷입니다. 시나트라 자체는 특별히 API 서버를 염두에 두고 만들어지지 않았지만 웹요청의 결과물을 JSON으로 출력하기만 하면 바로 간단한 JSON 서버가 됩니다. 비슷한 개념의 도구로 파이썬 기반의 &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;Flask&lt;/a&gt;나 PHP 기반의 &lt;a href=&quot;http://www.slimframework.com/&quot;&gt;Slim&lt;/a&gt; 같은 도구들이 있습니다.&lt;/p&gt;

&lt;h3 id=&quot;grape&quot;&gt;&lt;a href=&quot;http://www.ruby-grape.org/&quot;&gt;Grape&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;다른 많은 프로그래밍 언어들과 마찬가지로 루비에서도 API 서버 구현을 도와주는 많은 오픈소스 라이브러리들이 있으며 Grape도 그 중 하나 입니다. Grape는 앞서 소개한 Sinatra를 비롯한 &lt;a href=&quot;http://www.ruby-grape.org/examples/&quot;&gt;다양한 웹 개발 환경에서 사용&lt;/a&gt; 가능 합니다. 그 밖에 &lt;a href=&quot;https://github.com/nesquena/rabl&quot;&gt;Rabl&lt;/a&gt;, &lt;a href=&quot;http://praxis-framework.io/&quot;&gt;Praxis&lt;/a&gt;, &lt;a href=&quot;https://github.com/thestorefront/FastAPI&quot;&gt;FastAPI&lt;/a&gt; 등도 검토해볼만 합니다.&lt;/p&gt;

&lt;h3 id=&quot;rails&quot;&gt;&lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;루비온레일스(Ruby on Rails)는 별도의 설명이 필요없는 인기있는 웹 개발 프레임워크입니다. 레일스는 오래 전부터 REST를 지원해 왔고 &lt;a href=&quot;https://en.wikipedia.org/wiki/Content_negotiation&quot;&gt;컨텐츠 협상(content negotiation)&lt;/a&gt;을 통해 다양한 포맷으로 데이터를 내보낼 수 있습니다. 레일스를 웹앱이 아닌 REST API 서버로만 사용하도록 해주는 &lt;a href=&quot;https://github.com/rails-api/rails-api&quot;&gt;Rails API&lt;/a&gt; 프로젝트도 있으며 이 프로젝트는 &lt;a href=&quot;http://wyeworks.com/blog/2015/4/20/rails-api-is-going-to-be-included-in-rails-5/&quot;&gt;Rails 5에서 Rails Core 속에 통합될 예정&lt;/a&gt; 입니다.&lt;/p&gt;

&lt;h2 id=&quot;설치형-솔루션&quot;&gt;설치형 솔루션&lt;/h2&gt;

&lt;p&gt;구축형 솔루션이 API 설계부터 구현까지 직접 처리해야 하는 솔루션이라면 설치형 솔루션은 이미 갖춰진 API 서버를 설치하여 사용하기만 하면 되는 솔루션입니다. 물론 입맛에 맞게 사용하려면 약간의 ‘양념(customizing)’이 필요할 수 있지만, 바로 설치해서 신속하게 사용할 수 있는 점은 큰 장점입니다.&lt;/p&gt;

&lt;h3 id=&quot;loopback&quot;&gt;&lt;a href=&quot;http://loopback.io/&quot;&gt;LoopBack&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;엄밀히 말해 LoopBack은 Node.JS 기반의 웹 프레임워크입니다. Node 기반에서 작동하는 &lt;a href=&quot;http://loopback.io/resources/#compare&quot;&gt;다양한 웹 프레임워크들&lt;/a&gt;이 있지만, 특히 LoopBack은 다른 웹 프레임워크들과는 달리 REST API 서버 개발에 그 용도가 특화되어 있고 또 CLI를 통해 간단한 명령만으로 바로 API를 구성할 수 있다는 점에서 설치형 솔루션이라고 해도 무방할 듯 합니다.&lt;/p&gt;

&lt;h3 id=&quot;wordpress&quot;&gt;&lt;a href=&quot;https://wordpress.org/&quot;&gt;WordPress&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;워드프레스가 REST API 서버라구요? 맞습니다. 워드프레스는 주로 웹사이트 제작에 사용하는 CMS 도구입니다. 그렇지만 최근 워드프레스의 인기와 함께 활용도가 높아지면서 &lt;a href=&quot;http://wptavern.com/decoupling-wordpress&quot;&gt;워드프레스를 웹사이트 제작 이외의 용도로 사용하려는 움직임&lt;/a&gt;이 커지고 있습니다. (어쩌면 웹개발의 자연스런 흐름을 반영한 것이겠지만) 최근 출시된 &lt;a href=&quot;http://v2.wp-api.org/&quot;&gt;WP REST API&lt;/a&gt; 는 왠만한 REST API 서버로 쓰기에도 손색 없는 수준입니다.&lt;/p&gt;

&lt;h2 id=&quot;클라우드-솔루션&quot;&gt;클라우드 솔루션&lt;/h2&gt;

&lt;p&gt;구축도 설치도 필요 없고 그저 가입만 하고 인증절차만 거치면 바로 사용할 수 있는 솔루션이 클라우드 솔루션입니다. 소위 “&lt;a href=&quot;https://ko.wikipedia.org/wiki/PaaS&quot;&gt;Paas&lt;/a&gt;” 또는 “&lt;a href=&quot;https://en.wikipedia.org/wiki/Mobile_Backend_as_a_service&quot;&gt;Baas&lt;/a&gt;“라고 불리우는 이들 솔루션들은 REST API 서버 개발의 부담은 줄이면서 프론트엔드 개발에만 집중할 수 있다는 점에서 특히 모바일앱 개발자들에게 인기가 많은 솔루션입니다.&lt;/p&gt;

&lt;p&gt;대표적인 서비스로 페이스북이 인수하여 운영하는 &lt;a href=&quot;https://www.parse.com/&quot;&gt;Parse&lt;/a&gt;와 구글이 인수한 &lt;a href=&quot;https://www.firebase.com/&quot;&gt;Firebase&lt;/a&gt;가 있습니다. 국내에서도 KT에서 운영하던 ‘바스아이오’(bass.io) 라는 서비스가 있었고 저희 블로그에서도 한번 &lt;a href=&quot;http://www.usefulparadigm.com/2013/05/23/some-thought-about-baasio/&quot;&gt;소개한&lt;/a&gt; 적이 있지만 현재는 &lt;a href=&quot;https://www.imaso.co.kr/news/article_view.php?article_idx=20150523141832&quot;&gt;서비스가 종료된&lt;/a&gt; 상태입니다.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;최근의 웹개발 흐름이 모바일앱과 웹앱 등 주로 프론트엔드 부분에 많은 초점이 맞춰진 것이 사실이고 또 사용자 UI의 중요성이 커짐에 따라 갈수록 프론트엔드 개발의 중요성은 더 커지겠지만 이런 프론트엔드는 탄탄한 백엔드의 뒷받침 없이는 지속가능한 서비스로 이어질 수 없다는 점에서 ‘묵묵히(?)’ 뒤에서 떠받치는 REST API 서버는 없어서는 안 될 웹서비스의 진정한 핵심입니다. 또한 이미 완성되어 더 이상 풀어야할 문제가 남지 않은 영역이 아니라 계속해서 새로운 시도와 혁신들이 이뤄지고 있는 ‘진화하는’ 영역이기도 합니다. 최근 페이스북이 공개한 &lt;a href=&quot;https://facebook.github.io/graphql/&quot;&gt;GraphQL&lt;/a&gt;이나 Netflix의 데이터 추출 도구인  &lt;a href=&quot;http://netflix.github.io/falcor/&quot;&gt;Falcor&lt;/a&gt;, API를 위한 토큰인증 표준인 &lt;a href=&quot;http://jwt.io/&quot;&gt;JWT(JSON Web Tokens)&lt;/a&gt; 등은 모두 이런 진화의 반증일테죠.&lt;/p&gt;

&lt;p&gt;다음에 기회가 되면 이들 솔루션들도 하나하나 소개해 나가기로 하겠습니다.
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; 마침 서점에 REST API를 다룬 좋은 책이 한권 나왔네요. 비록 번역서이긴 하지만, 프론트엔드 개발 일변의 책들이 쏟아지는 속에서 반가운 소식이 아닐 수 없습니다(저희는 이 책의 역자 또는 이 책의 출판사와는 아무런 이해관계도 없답니다. 그저 반가운 마음에^^).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.insightbook.co.kr/post/9865&quot;&gt;RESTful Web API (웹 API를 위한 모범 전략 가이드)&lt;/a&gt;&lt;br /&gt;
레오나르드 리처드슨, 마이크 애먼슨 외 1명 저 | 박세현 외 1명 역 | 인사이트 | 2015.09.09&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2015/restful-web-api-cover.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Backbone 앱에 React 컴포넌트 추가하기</title>
   <link href="/2015/07/31/adding-react-component-to-backbone-app/"/>
   <updated>2015-07-31T00:00:00+00:00</updated>
   <id>/2015/07/31/adding-react-component-to-backbone-app</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/backbone-plus-react.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;알다시피 &lt;a href=&quot;https://facebook.github.io/react/index.html&quot;&gt;React&lt;/a&gt;는 페이스북에서 공개한 오픈소스 자바스크립트 UI 라이브러리다. &lt;a href=&quot;https://angularjs.org/&quot;&gt;Angular&lt;/a&gt; 또는 &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember&lt;/a&gt;와 같은 다른 자바스크립트 라이브러리들이 주로 UI와 데이터 처리, 그리고 URL 라우팅까지 아우르는 소위 “풀스택(full stack)”의 프레임워크 구성을 가져가는 반면, React는 사용자 인터페이스 부분만 다룬다는 점에서 이들 프레임워크와 차이가 있다. 게다가 컴포넌트(web components) 개념을 갖추고 가상 DOM(Virtual DOM)을 이용한 렌더링 방식을 사용하는 탓에 사용하기 쉽고 UI 처리 속도도 빨라, 아직 v0.13.x 라는 낮은 버전임에도 이미 많은 저변을 확보하고 있다.&lt;/p&gt;

&lt;p&gt;이에 비하면 &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone&lt;/a&gt;은 제법 오래된 축에 속한다. 웹 개발에서 프론트엔드와 자바스크립트의 비중이 커지고 SPA(Single Page App) 개념이 일반화될 무렵, 그때까지 주로 jQuery로만 작업하던 “기존의 방식”에서 한걸음 더 나아가 프론트엔트 측에도 서버 측의 웹개발과 유사한 MVC(Model-View-Controller) 기반의 패턴을 적용한 시도 중 가장 성공한 케이스 중 하나다. 그러다보니 이미 많은 적용 사례를 갖고 있고 또 Angular나 Ember 같은 다른 프레임워크들에 비해 상대적으로 관례가 적고 “가벼워서” 요즘도 계속 사용되고 있는 자바스크립트 라이브러리의 “고전(classic)”이다.&lt;/p&gt;

&lt;p&gt;그렇지만 Backbone 라이브러리가 그 자체로는 너무 “기본적인” 내용들만 담고 있다 보니 종종 까다로운 문제를 처리해야 할 때는 여러 가지 직접 해결해야 할 문제들이 생기곤 할 때가 많다. 특히 뷰 처리와 관련해서는, 뷰 템플릿(template)을 처리하거나 중첩된 뷰(nested view)를 다룰 때 또는 뷰와 연결된 여러 이벤트들을 관리하거나 뷰의 상태를 다룰 때 등에서 종종 복잡한 문제와 맞닥뜨릴 때가 있다. 이럴 경우 Backbone 앱의 기본 구조는 그대로 남겨두고 뷰(View) 부분만 React로 교체해 보는 것도 좋은 방법이다. &lt;a href=&quot;http://backbonejs.org/#View-rendering&quot;&gt;Backbone의 뷰는 렌더링(rendering)에 있어 특별한 관례를 갖고 있지 않기 때문에&lt;/a&gt; React와 연동하여 가상돔(Virtual DOM)을 렌더링하는 것도 얼마든지 가능하기 때문이다.&lt;/p&gt;

&lt;p&gt;알다시피 Backbone 앱은 모델(Model)과 뷰(View)를 중심으로 구성된다. Backbone 모델에서 발생한 변경 사항은 Backbone의 자체 이벤트 시스템을 통해 뷰에서 받아서 처리(render)하고, 반대로 사용자 입력은 뷰를 통해 모델로 전달하는 구조다(아래 그림 참조). 다만 Angular나 Ember에서와 같은 소위 ‘2-way binding’은 지원하지 않는다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/backbone-model-view.png&quot; alt=&quot;&quot; /&gt;
(그림 출처: &lt;a href=&quot;http://backbonejs.org/&quot;&gt;http://backbonejs.org/&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;Backbone 앱에 React를 적용하려면 기존에 Backbone 뷰로 작성한 부분을 React 컴포넌트로 교체하면 된다. 아래 코드에서는 기존의 Backbone 뷰 골격은 그대로 두고 뷰의 render 메서드 부분만 React#render 호출로 변경하였다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// home_view.js

var HomeView = Backbone.View.extend({
  el: '#home',

  initialize: function() {
    this.render();
  },
  
  render: function() {
    var entryList = React.createElement(EntryList, {collection: this.collection});
    React.render(entryList, this.el);
    return this;
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;실제 UI 처리는 모두 React 컴포넌트에서 이루어진다. 아래 코드는 위의 HomeView#render 메서드 속에서 사용한 EntryList의 예제이며, React의 프로퍼티(property)로 Backbone의 컬렉션(Collection) 데이터를 받아 React 컴포넌트의 렌더링을 처리하는 간단한 JSX 파일이다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// entry_list.jsx

var EntryList = React.createClass({

  render: function() {
    return (
      &amp;lt;div className=&quot;entry-list&quot;&amp;gt;
        &amp;lt;h1&amp;gt;Listing Entries&amp;lt;/h1&amp;gt;
        &amp;lt;EntryForm collection={this.props.collection} /&amp;gt;
        &amp;lt;hr /&amp;gt;
        &amp;lt;ul className=&quot;entries&quot;&amp;gt;
        {this.props.collection.sort().map(function(entry) {
          return &amp;lt;li key={entry.cid}&amp;gt;{entry.get('title')}&amp;lt;/li&amp;gt;;
        })}
        &amp;lt;/ul&amp;gt;
      &amp;lt;/div&amp;gt;
    );
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 남은 문제는, Backbone의 모델(또는 컬렉션)에서 발생한 변경을 어떻게 하면 React 컴포넌트에서 받아 (자동으로) 렌더링되게 하냐 하는 것이다. 얼핏 모델이나 컬렉션이 변경되는 부분에서 React#render 메서드를 명시적으로 호출해 주면 간단할 듯 보인다. 다행히 React에서는 이를 위해 &lt;a href=&quot;https://facebook.github.io/react/docs/component-api.html#forceupdate&quot;&gt;React#forceUpdate&lt;/a&gt;라는 메서드를 제공한다. 따라서 &lt;a href=&quot;https://facebook.github.io/react/docs/component-specs.html&quot;&gt;React 컴포넌트의 라이프사이클(Life-cycle)&lt;/a&gt; 콜백 함수 속에서 다음과 같이 Backbone의 모델/컬렉션의 변경 이벤트를 바인딩(binding)하여 React#forceUpdate를 호출해주면 모델/컬렉션의 변경 사항이 자동으로 React UI에 반영된다.&lt;/p&gt;

&lt;p&gt;아래에서는 React의 componentDidMount와 componentWillUnmount 콜백에서 각각 컬렉션의 이벤트를 바인딩/언바인딩 처리하고 있다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// entry_list.jsx

var EntryList = React.createClass({

  componentDidMount: function() {
    this.props.collection.on('add remove change', this.forceUpdate.bind(this, null));
  },

  componentWillUnmount: function () {
    this.props.collection.off(null, null, this);
  },
  
  render: function() {
    return (
      // 생략
    );
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;물론 React는 선언적(declarative) 방식으로 렌더링을 처리하기 때문에 지금처럼 React#forceUpdate를 호출하는 방식보다는 모델이나 컬렉션의 변경이 이루어지는 부분에서 “변동이 생겼음”을 React에게 넌지시 알려 주어 React가 “알아서” 렌더링하게 하는 게 더 좋은 방법이긴 하다. 이 점은 &lt;a href=&quot;https://facebook.github.io/react/docs/component-api.html#forceupdate&quot;&gt;React API 문서&lt;/a&gt;에도 나와 있다:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component “pure” and your application much simpler and more efficient.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;그렇지만 지금과 같이 Backbone 앱에 React를 적용할 때에는 Backbone의 구조도 고려할 필요가 있기 때문에 앞에서처럼 직접 React#forceUpdate를 호출하는 방식이 유용할 수 있으며 또한 가장 간단한 방법이기도 하다.&lt;/p&gt;

&lt;p&gt;물론 여기서는 설명의 편의를 위해 React 컴포넌트 속에 직접 콜백을 두는 방식을 사용했지만, 실제로는 React의 &lt;a href=&quot;https://facebook.github.io/react/docs/reusable-components.html#mixins&quot;&gt;믹스인(mixin)&lt;/a&gt;으로 처리하는 것이 더 편리할 것이다. 물론 이미 이 기능을 (믹스인으로) 구현해 놓은 많은 솔루션(플러그인)들이 나와 있기 때문에 굳이 “바퀴를 직접 만들” 필요는 없을 듯 하다. 이들 중 대표적인 것 몇몇만 소개하면 다음과 같다:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/clayallsopp/react.backbone&quot;&gt;ReactBackbone&lt;/a&gt; 앞서 소개한 React#forceUpdate 방식을 사용한 Mixin&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://magalhas.github.io/backbone-react-component/&quot;&gt;Backbone React Component&lt;/a&gt; Wrapper를 사용하여 백본 모델/컬렉션의 상태를 React state와 맵핑&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/andrejewski/reactbone&quot;&gt;ReactBone&lt;/a&gt;  React 컴포넌트와 연동할 수 있게 Bakbone 모델/컬렉션을 확장&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;panel panel-default&quot;&gt;
  &lt;div class=&quot;panel-body&quot; style=&quot;background: #7FDBFF; color: hsla(197, 100%, 20%, 1.0);&quot;&gt;
이 글에서 사용한 예제의 전체 소스코드는 &lt;a href=&quot;https://github.com/usefulparadigm/backbone-reactjs&quot;&gt;Github&lt;/a&gt;에서 내려 받을 수 있습니다. 
  &lt;/div&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>워드프레스와 Cron</title>
   <link href="/2015/03/24/understanding-wordpress-cron/"/>
   <updated>2015-03-24T00:00:00+00:00</updated>
   <id>/2015/03/24/understanding-wordpress-cron</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/wordpress_wp_cron.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://unixhelp.ed.ac.uk/CGI/man-cgi?crontab+5&quot;&gt;cron&lt;/a&gt;은 시스템의 백그라운드에서 정해진 시간 또는 시간 간격으로 어떤 작업을 처리할 때 사용하는 UNIX 명령이다. 주기적으로 반복해서 수행해야 하는 작업들을 미리 스케줄링(scheduling)해 두면 지정된 시간에 해당 작업이 자동으로 실행되기 때문에, 백업이나 시스템 업데이트 같은 반복 작업이나 이메일 발송 등 시간이 제법 오래 걸리는 배치(batch) 작업 등에 폭넓게 사용되는 요긴한 명령이다.&lt;/p&gt;

&lt;p&gt;워드프레스(WordPress)를 사용하거나 관리하는 경우에도 이런 cron과 유사한 작업들이 필요한 경우가 알게 모르게 생긴다. 예를 들어 포스팅 시간을 예약해 둔 글을 배포(publish)하거나 새 글이 올라오면 뉴스레터를 발송하거나 테마나 플러그인의 새로운 업데이트가 있는지 검사하는 것과 같은. 이런 경우에 사용할 목적으로 워드프레스도 UNIX의 cron과 유사한 개념의 도구를 제공하고 있는데, UNIX의 cron과 비교하는 의미로 흔히 ‘&lt;a href=&quot;https://codex.wordpress.org/Category:WP-Cron_Functions&quot;&gt;WP-Cron&lt;/a&gt;‘이라 불린다.&lt;/p&gt;

&lt;h3 id=&quot;wp-cron의-동작&quot;&gt;WP-Cron의 동작&lt;/h3&gt;

&lt;p&gt;통상적인 cron이 스케줄에 맞춰 지정된 시간에 정확하게 수행되는 것과 달리 WP-Cron은 PHP기반의 웹기반 시스템인 워드프레스의 특성 상, 웹요청이 들어 올 경우에만 실행된다. 즉 사용자가 워드프레스 사이트를 방문할 경우에 매번 cron이 실행되는데, 이 때 워드프레스는 자체 cron 스케줄 시스템에서 현재 수행해야 할 cron 작업이 있는지 검사하고 있으면 해당 작업을 백그라운드로 실행시키게 된다. 따라서 만약 (관리자를 포함) 아무런 방문도 없는 사이트라면 WP-Cron은 ‘결코’ 실행되지 않는다 (이렇게 실행되지 않는 cron 작업들은 계속 모였다가 언젠가 한 사람의 방문자가 방문했을 때 그동안 미뤄 뒀던 cron 작업들이 모조리 한번에 실행되어 접속속도가 느려 보이는 결과를 초래하기도 한다).&lt;/p&gt;

&lt;p&gt;워드프레스 내부적으로 cron은 다음 2개의 파일이 담당한다:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/WordPress/WordPress/blob/master/wp-includes/cron.php&quot;&gt;/wp-includes/cron.php&lt;/a&gt; : 모든 cron 처리 관련 API 함수들이 들어 있음&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/WordPress/WordPress/blob/master/wp-cron.php&quot;&gt;/wp-cron.php&lt;/a&gt; : cron 호출에 사용되는 스크립트 파일&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WP-Cron의 내부 작동 메커니즘은 위 소스코드를 참조하기로 하고, 여기서는 이들 WP-Cron 관련 API의 간단한 사용법만 소개하기로 한다.&lt;/p&gt;

&lt;h3 id=&quot;wp-cron-사용하기&quot;&gt;WP-Cron 사용하기&lt;/h3&gt;

&lt;p&gt;WP-Cron은 크게 &lt;strong&gt;cron 이벤트(event)&lt;/strong&gt;라고 부르는 cron 작업 부분과 이들 작업을 실행하는 주기인 &lt;strong&gt;스케줄(schedule)&lt;/strong&gt; 부분으로 나눠 볼 수 있는데, cron 이벤트 처리와 관련된 API 함수에는 다음과 같은 것들이 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/Function_Reference/wp_schedule_event&quot;&gt;wp_schedule_event()&lt;/a&gt; : cron 이벤트 추가&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/Function_Reference/wp_schedule_single_event&quot;&gt;wp_schedule_single_event()&lt;/a&gt; : 1회 실행 cron 이벤트 추가&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/Function_Reference/wp_next_scheduled&quot;&gt;wp_next_scheduled()&lt;/a&gt; : cron 이벤트의 다음 번 수행시간&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/Function_Reference/wp_unschedule_event&quot;&gt;wp_unschedule_event()&lt;/a&gt; : cron 이벤트 제거&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;예를 들어, 1시간 간격으로 수행해야 할 어떤 작업을 cron 이벤트로 추가하려면 다음과 같이 그 작업을 액션 훅(hook)으로 처리한 다음 wp_schedule_event()로 추가하면 된다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 새 cron 이벤트 생성
add_action( 'prefix_hourly_event_hook', 'prefix_do_this_hourly' );
function prefix_do_this_hourly() {
	// 1시간 간격으로 수행될 어떤 작업
}
// 앞의 cron 이벤트를 스케줄에 추가
wp_schedule_event( time(), 'hourly', 'prefix_hourly_event_hook' );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 때 wp_schedule_event()의 두 번째 인자로 전달된 ‘hourly’는 cron의 실행간격을 의미하는데, 워드프레스에는 기본으로 hourly, twicedaily, 및 daily의 3가지 간격(intervals)이 등록되어 있으며, &lt;a href=&quot;https://codex.wordpress.org/Plugin_API/Filter_Reference/cron_schedules&quot;&gt;cron_schedules&lt;/a&gt; 필터 훅을 통해 얼마든지 확장 가능하다. 다음은 cron 스케줄에 새로 weekly라는 스케줄을 추가하는 코드다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function my_add_weekly( $schedules ) {
	// 새로 'weekly' 스케줄을 추가
	$schedules['weekly'] = array(
		'interval' =&amp;gt; 604800,
		'display' =&amp;gt; __('Once Weekly')
	);
	return $schedules;
}
add_filter( 'cron_schedules', 'my_add_weekly' ); 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;참고로, 워드프레스 사이트 내에서 실제로 어떤 cron 작업들이 등록되어 어떻게 실행되고 있는지를 확인해 보려면 &lt;a href=&quot;https://wordpress.org/plugins/wp-crontrol/&quot;&gt;WP Crontrol&lt;/a&gt; 같은 플러그인을 사용하면 편리하다. 이 플러그인은 실행 중인 cron 작업을 확인할 뿐 아니라 변경/삭제할 수 있는 기능도 제공한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://usefulpa.s3.amazonaws.com/images/2014/screenshot-1.png&quot; alt=&quot;WP Crontrol&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;wp-cron-죽이기&quot;&gt;WP-Cron 죽이기&lt;/h3&gt;

&lt;p&gt;앞서도 말했지만 WP-Cron은 이름은 같은 ‘cron’이긴 하지만 ‘토종 cron(UNIX cron)’과는 다른 성격의 cron이다. 따라서 다음과 같은 경우에는 제대로 작동하지 않을 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;방문자가 거의 없는 사이트(앞서 설명)&lt;/li&gt;
  &lt;li&gt;캐시(cache) 시스템이 적용된 사이트&lt;/li&gt;
  &lt;li&gt;인증, IP 필터링, 쿠키 필터링 등으로 wp-cron.php 호출 자체가 차단된 사이트&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;또한 방문자가 아주 많아 트래픽이 높은 사이트인 경우에도 마찬가지로 WP-Cron은 문제가 될 수 있다. 방문자가 사이트를 방문할 때마다 매번 실행되는 cron의 성격 상, 동시에 여러  사용자가 접속하면 여러 개의 프로세스가 동시에 백그라운드에서 실행될 수 있기 때문이며, 이는 사이트의 리소스를 차지하고 성능에도 영향을 미칠 수 있다. 물론 워드프레스가 기본적으로 cron 처리에 락(lock) 시스템을 적용해 두고 있기 때문에 지나친 우려는 하지 않아도 되겠지만.&lt;/p&gt;

&lt;p&gt;그렇다면 아예 WP-Cron을 죽이는 건 어떨까? 좋은 방법은 아니다. 왜냐면 cron은 워드프레스 속 여러 군데에서 사용되고 있기 때문에 이 기능을 완전히 끄게 되면 cron이 필요한 기능들은 동작하지 않게 되기 때문이다.&lt;/p&gt;

&lt;p&gt;이런 경우에 우리는 WP-Cron에서 벗어나 진짜 cron으로 갈아탈 수 있다. 우선 WP-Cron은 끄자. /wp-config.php 파일에 다음 상수를 추가하면 된다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 내부 WP-Cron 비활성화
define('DISABLE_WP_CRON', true);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;그런 다음, 진짜 cron을 깨우자. 만약 5분 단위로 호출하려면, crontab에 다음과 같이 wp-cron.php를 호출하는 스크립트를 추가하면 된다. (crontab의 사용법은 생략한다)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;*/5 * * * * wget -q -O - http://www.your-site.com/wp-cron.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이 때 wget 명령에서 사용한 -O 옵션은 출력 결과를 파일이 아닌 표준출력(STDOUT)으로 보내는 옵션이며, wget 대신 예를 들면 curl 같은, HTTP 웹요청을 수행하는 명령이면 어떤 것을 사용하든 무방하다.&lt;/p&gt;

&lt;h3 id=&quot;참고자료&quot;&gt;참고자료&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://ben.lobaugh.net/blog/20787/wordpress-how-to-use-wp-cron&quot;&gt;WordPress: How to use WP-Cron&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tommcfarlin.com/wordpress-cron-jobs/&quot;&gt;Properly Setting Up WordPress Cron Jobs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.lucasrolff.com/wordpress/why-wp-cron-sucks/&quot;&gt;Why WP-Cron sucks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>반응형웹과 Responsive Image 처리</title>
   <link href="/2014/11/03/processing-images-on-responsive-web/"/>
   <updated>2014-11-03T00:00:00+00:00</updated>
   <id>/2014/11/03/processing-images-on-responsive-web</id>
   <content type="html">&lt;p&gt;반응형웹(responsive web)이 대세가 된지 오래다. 국내외를 막론하고 새로 만들어지는 웹사이트 중 반응형웹을 지원하지 않는 곳은 찾아보기 힘들 정도다. 알다사피 반응형웹 혹은 &lt;a href=&quot;http://en.wikipedia.org/wiki/Responsive_web_design&quot;&gt;반응형웹 디자인(responsive web design, 줄여서 RWD)&lt;/a&gt;이란, 마치 예전에 Ajax가 그랬듯, 기존에 나와 있던 몇몇 개념들이 결합되어 만들어진 개념으로, 하나의 웹페이지만으로 모바일과 데스크톱을 아우르는 다양한 디바이스에 효과적으로 대응하기 위해 만들어진 프론트엔트 웹개발 방법이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://usefulpa.s3.amazonaws.com/images/2014/econo-is-responsive.png&quot; srcset=&quot;http://usefulpa.s3.amazonaws.com/images/2014/econo-is-responsive.png 644w, http://usefulpa.s3.amazonaws.com/images/2014/econo-is-responsive_2x.png 1288w&quot; alt=&quot;retina devices&quot; /&gt;&lt;/p&gt;

&lt;p&gt;알다시피 이런 “반응형”의 웹사이트를 만들기 위해서는 주로 다음 3가지 기술(기법)을 사용하게 된다. 물론 이 외에도 여러 가지 기법들과 핵(hack)이 적용되기는 하지만 기본적으로는 아래 3가지가 반응형웹의 토대를 이룬다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;유동 레이아웃(flexible layout)&lt;/li&gt;
  &lt;li&gt;CSS3 미디어쿼리(media query)&lt;/li&gt;
  &lt;li&gt;반응형 이미지(responsive image)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 셋 중 유동 레이아웃이나 미디어 쿼리 부분은 CSS 명세에 맞게 사용하면 크게 문제될 게 없지만, 유독 이미지를 처리하는 부분은 조금 까다롭다. 왜 까다로운지 그리고 어떤 해결책들이 있는지 지금부터 알아보기로 하자.&lt;/p&gt;

&lt;h2 id=&quot;반응형-이미지-처리&quot;&gt;반응형 이미지 처리&lt;/h2&gt;

&lt;p&gt;2010년의 어느 날 웹 디자이너인 Ethan Marcotte가 처음 &lt;a href=&quot;http://alistapart.com/article/responsive-web-design&quot;&gt;반응형웹이란 개념을 소개&lt;/a&gt;했을 때만 해도 반응형웹에서 이미지를 어떻게 다루어야 할지에 대해서는 크게 문제가 되지 않는 듯 했다. 통상적으로 반응형웹은 유동(fluid) 레이아웃에 기반하고 유동 레이아웃에서 어떤 요소를 가변적으로 구성하려면 비율값 즉 퍼센트(%) 값을 사용하는게 일반적이므로, 흔히 (그리고 지금까지도) 반응형웹에서 이미지 처리의 기본패턴은 CSS 스타일시트에 다음과 같이 비율폭을 추가하는 것이다.&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;100%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;사실 반응형 이미지를 위해 처리해줘야 할 부분은 이게 전부이기도 하다. 이렇게만 해도 하나의 이미지가 웹사이트의 가로폭에 맞춰 크기가 가변적으로 조정되고 당연히 페이지의 최대폭을 넘지 않기 때문에 모든 디바이스에서 이미지가 “제대로(넘치지 않고)” 표시되는 것을 보장할 수 있다. 여기에 페이지 레이아웃에 맞춰 미디어별로 이미지 크기를 다르게 설정하는 미디어쿼리(media query)를 가미하면 좀 더 나은 반응형웹을 구현할 수 있다.&lt;/p&gt;

&lt;h2 id=&quot;몇-가지-문제들&quot;&gt;몇 가지 문제들&lt;/h2&gt;

&lt;p&gt;그런데 위의 방식만으로 반응형 이미지를 처리할 경우 다음과 같이 몇 가지 문제가 남는다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;이미지 크기(size)와 관련한 성능/속도 및 대역폭 문제&lt;/li&gt;
  &lt;li&gt;고밀집도(High-DPI) 디바이스 대응&lt;/li&gt;
  &lt;li&gt;소위 “아트 디렉션(art direction)” 처리&lt;/li&gt;
  &lt;li&gt;다양한 이미지 포맷 대응&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;하나씩 살펴 보기로 하자.&lt;/p&gt;

&lt;p&gt;우선 &lt;strong&gt;이미지 크기(size)와 관련한 문제&lt;/strong&gt;다. 반응형웹에서는 디바이스에 따라 레이아웃이 달라지고 이에 맞춰 이미지 크기 또한 가변적으로 변하기 때문에 통상 가장 큰 사이즈의 이미지를 하나 만들어 모든 디바이스에 대응하는 경우가 많다. 이럴 경우 굳이 그럴 필요가 없는 작은 사이즈의 화면을 가진 디바이스에도 똑같이 큰 사이즈의 이미지를 불러와야 하기 때문에 불필요한 대역폭의 낭비가 생기고 또 결과적으로 페이지 로딩 속도도 디바이스에 맞는 적은 용량의 이미지를 썼을 때보다 떨어지게 된다. 데스크톱에서 잘 보이게 만든 큰 용량의 이미지를 굳이 작은 화면의 아이폰에도 똑같이 불러올 필요는 없다.&lt;/p&gt;

&lt;p&gt;실제로 2014년 10월 현재 HTTP Archive에 집계된 통계 상으로 웹 페이지 용량에서 이미지가 차지하는 부분은 절반을 훨씬 넘는 것으로 나타났다. 아무런 다른 조치 없이 단지 이미지 용량만 줄이더라도 웹사이트의 속도가 크게 개선될 수 있다는 말이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/Web_Image.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;( * 출처: &lt;a href=&quot;http://httparchive.org/interesting.php?a=All&amp;amp;l=Oct%201%202014&amp;amp;s=All&quot;&gt;HTTP Archive&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;두 번째 문제는 이른바 “레티나(Retina)” 디스플레이라고도 불리는 &lt;strong&gt;고밀집도 디바이스에 대한 대응&lt;/strong&gt; 이다. 요즘 새로 출시되는 디바이스들 중에는 밀집도(density)가 높은 디스플레이를 장착한 디바이스가 많고 그러다보니 이미지 처리도 이들 고밀집도(high-density) 디바이스에 대응해야 하는 문제가 생기게 된다. 아래 그림처럼 통상적인 밀집도의 디바이스에서 정상적으로 보이던 이미지가 레티나 기반의 디바이스에서는 흐릿하게 보이게 된다. 레티나를 필두로 한 고밀집도 디바이스에 대한 문제와 이에 대한 대응에 관한 더 자세한 내용은 참고자료를 참조하면 좋겠다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/standard-vs-retina.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(* 사진출처: &lt;a href=&quot;http://greatfridays.com/blog/images-in-responsive-web-development/&quot;&gt;http://greatfridays.com/blog/images-in-responsive-web-development/&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;소위 &lt;strong&gt;“아트 디렉션(art direction)” 처리&lt;/strong&gt;도 문제가 될 수 있다. 이미지를 일률적으로 배율에 맞춰 확대/축소할 경우 데스크톱에서는 분명한 의미를 전달하던 이미지가 화면 크기가 적은 모바일 디바이스에서는 도무지 무슨 이미지인지 알아보지 못해 의미 전달을 놓치게 되는 경우가 많다. 이 경우 해결책은 디바이스 특성에 맞춰 크기 뿐 아니라 이미지의 내용도 다른 이미지를 제공하는 것이다. 예를 들어 아래 사진 이미지의 경우 배율에 맞춰 크기를 줄이기보다는(우측 상단)  이미지가 표시되는 상황(context)에 맞게 잘라진 사진을 사용하는 것이(우측 하단) 더 효과적으로 의미를 전달할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/artdirection.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;( * 사진출처: &lt;a href=&quot;http://24ways.org/2012/responsive-images-what-we-thought-we-needed/&quot;&gt;http://24ways.org/2012/responsive-images-what-we-thought-we-needed/&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;마지막으로 고려할 문제는 &lt;strong&gt;다양한 이미지 형식(format)에 대한 대응&lt;/strong&gt; 문제다. 전통적으로 웹 상에서 사용하는 이미지 파일의 형식은 주로 GIF, JPEG, PNG 인 경우가 대부분이었지만 최근에는 좀 더 효율적이고 압축률을 높인 다양한 유형의 이미지 파일 형식들이 나오고 있고 이들 새로운 형식을 지원하는 브라우저들도 속속 등장하고 있기 때문에, 새로운 이미지 파일 형식에 대한 대응도 문제가 된다. 이미 대부분의 브라우저에서 지원하고 있는 SVG나 구글에서 제안한 &lt;a href=&quot;https://developers.google.com/speed/webp/&quot;&gt;WebP&lt;/a&gt;, 마이크로소프트의 &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/hh707223.aspx&quot;&gt;JPEG-XR&lt;/a&gt;, 그리고 &lt;a href=&quot;http://en.wikipedia.org/wiki/FlashPix&quot;&gt;FlashPix&lt;/a&gt; 같은 형식이 대표적이다.&lt;/p&gt;

&lt;h2 id=&quot;해결책들&quot;&gt;해결책들&lt;/h2&gt;

&lt;p&gt;웹커뮤니티, 특히 그 중에서도 프론트엔드 개발자들은 이 문제에 대해 이미 “반응형웹”이란 말이 세상에 나오기 전부터 많은 고민을 해왔고 그만큼 많은 해법과 트릭들을 만들어 왔다. 그렇지만 이 모든 방법들을 여기서 전부 소개하기는 쉽지도 않을 뿐더러 이미 어느 정도 표준적인 방법이 등장한 이후인지라 여기서는 현재의 모습을 중심으로 몇 가지 대안들만 소개하려 한다.&lt;/p&gt;

&lt;h3 id=&quot;srcset과-sizes-속성&quot;&gt;srcset과 sizes 속성&lt;/h3&gt;

&lt;p&gt;처음 소개할 방법은 srcset 과 sizes 속성이다. 이 방식은 HTML의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 태그에 새로운 속성을 추가하여 반응형 이미지를 처리하는 방식으로 Apple이 처음 제안하여 현재의 웹표준에 이른 방식이며, 예제는 다음과 같다.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;small.jpg&quot;&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;srcset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;large.jpg 1024w, medium.jpg 640w, small.jpg 320w&quot;&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;sizes=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(min-width: 36em) 33.3vw, 100vw&quot;&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;A rad wolf&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(* 예제 출처: &lt;a href=&quot;http://responsiveimages.org/&quot;&gt;RICG&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 태그는 이미 기존부터 사용해오던 그 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 태그지만 여기에 새로 srcset과 sizes 속성이 덧붙었다. 여기 예제의 srcset 속성에서는 각각 가로폭 1024px, 640px, 320px인 3개의 이미지를 쉼표로 분리된 문자열 형식으로 적었다. 이럴 경우 브라우저(srcset을 지원하는 브라우저)는 이 값을 읽어 현재의 화면 상태에 맞는 적절한 이미지를 불러오게 된다. sizes 속성도 추가할 수 있는데, 이 속성은 미디어쿼리의 중단점(breakpoint) 별로 필요한 이미지의 정보를 추가로 제공함으로써 역시 브라우저로 하여금 현재의 상태에 가장 잘 맞는 이미지를 불러오는데 도움을 주게 된다. 위 예제에서는 미디어쿼리의 중단점으로 가로폭이 36em 이상인 경우에는 33.3vw (‘viewport width’를 의미)의 이미지가 필요함을 브라우저에 알리고 있으며 뒤의 100vw는 디폴트값이다. 물론 srcset과 sizes를 지원하지 않는 브라우저에서는 기존의 src 속성이 폴백(fallback)으로 사용된다.&lt;/p&gt;

&lt;p&gt;srcset과 sizes 속성을 사용하면 앞에서 제기한 네 가지 문제들 중 적어도 처음 두 가지 문제는 손쉽게 해결된다. 브라우저가 화면 크기에 맞춰 적절한 용량의 이미지를 불러오고 또한 고밀집도 디스플레이 화면에 대한 대응도 브라우저가 판단하여 대응하기 때문이다(여기서 소개하진 않았지만 srcset에는 w 대신 x 속성으로 밀집도를 지정하는 옵션도 있는데, 아래의 예제에 나온다).&lt;/p&gt;

&lt;h3 id=&quot;picture-엘리먼트&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트&lt;/h3&gt;

&lt;p&gt;srcset/sizes 속성만으로 해결할 수 없는 문제들, 예컨대 아트 디렉션 처리나 여러 이미지 포맷 지원 등은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트로 해결할 수 있다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트는 &lt;a href=&quot;http://alistapart.com/article/responsive-images-how-they-almost-worked-and-what-we-need&quot;&gt;Mat Marquis&lt;/a&gt;에 의해 처음 제안되어 현재 W3C의 &lt;a href=&quot;http://responsiveimages.org/&quot;&gt;Responsive Images Community Group&lt;/a&gt;에 의해 관리되는 웹표준에 이른 반응형 이미지 처리 방법이다. (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트가 오늘에 이르기까지의 우여곡절과 웹커뮤니티의 노력은 참고자료 참조)&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;source&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;media=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(min-width: 40em)&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;srcset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;big.jpg 1x, big-hd.jpg 2x&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;source&lt;/span&gt; 
    &lt;span class=&quot;na&quot;&gt;srcset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;small.jpg 1x, small-hd.jpg 2x&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fallback.jpg&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(* 예제 출처: &lt;a href=&quot;http://responsiveimages.org/&quot;&gt;RICG&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트는 하위 요소로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;source&amp;gt;&lt;/code&gt; 엘리먼트를 두어 각각의 이미지 소스를 처리한다. 위 예제에서는 미디어쿼리로 min-width값이 40em 이상인 경우는 big.jpg 파일을, 그 이하인 경우는 small.jpg 파일을 각각 로드하게끔 설정되어 있다. 이 때 각각의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;source&amp;gt;&lt;/code&gt; 엘리먼트 내에는 srcset 속성을 추가하여 밀집도(여기서는 1x와 2x를 사용했는데, 2x는 196 DPI 이상을 일컫는다)에 따라 각기 다른 이미지 파일을 로드하게끔 설정하는데, 이 부분은 앞서의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 태그에 붙은 srcset 속성과 동일하다.&lt;/p&gt;

&lt;p&gt;이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트를 이용하면 앞서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 태그에 붙여 사용했던 srcset/sizes 방식보다 조금 더 다양한 처리가 가능해 진다. 예를 들어, 아트디렉션(art direction) 은 다음과 같이 처리할 수 있다. 여기서는 미디어쿼리로 width값이 800px 이상인 경우(lighthouse-landscape)와 그 이하인 경우(lighthouse) 각각 다른 이미지를 사용하며 그 결과 좁은 폭의 화면에서는 넓은 폭과는 다른 모양의 이미지가 보여짐을 알 수 있다.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;source&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;media=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(min-width: 800px)&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;sizes=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;80vw&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;srcset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lighthouse-landscape-640.jpg 640w,
                  lighthouse-landscape-1280.jpg 1280w,
                  lighthouse-landscape-2560.jpg 2560w&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lighthouse-160.jpg&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lighthouse&quot;&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;sizes=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;80vw&quot;&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;srcset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;lighthouse-160.jpg 160w,
               lighthouse-320.jpg 320w,
               lighthouse-640.jpg 640w,
               lighthouse-1280.jpg 1280w&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/lighthouse-example-picture2X.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(* 예제 출처: &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/responsive/picture-element/&quot;&gt;HTML5Rocks&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트는 다양한 이미지 형식을 처리하는 데도 사용될 수 있다.  아래 예제를 보면 webp를 지원하는 브라우저인 경우 jpg 파일이 아닌 webp 파일을 표시하도록 하고 있다.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;picture&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;source&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;image/webp&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;srcset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;images/butterfly.webp&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;images/butterfly.jpg&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a butterfly&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트 관련 더 자세한 내용은 &lt;a href=&quot;http://www.w3.org/TR/html-picture-element/&quot;&gt;W3C Draft 문서&lt;/a&gt; 참조.&lt;/p&gt;

&lt;h3 id=&quot;브라우저-지원과-폴리필polyfill&quot;&gt;브라우저 지원과 폴리필(polyfill)&lt;/h3&gt;

&lt;p&gt;웹에서는 아무리 좋은 기능이라도 브라우저에서 그 기술을 지원하지 않으면 무용지물이다. 다행히 &lt;a href=&quot;http://blog.chromium.org/2014/08/chrome-38-beta-new-primitives-for-next.html&quot;&gt;크롬(Chrome)&lt;/a&gt;, &lt;a href=&quot;https://www.webkit.org/blog/2910/improved-support-for-high-resolution-displays-with-the-srcset-image-attribute/&quot;&gt;사파리(Safari)&lt;/a&gt; 등 주요 브라우저들이 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;엘리먼트와 srcset/sizes 속성을 지원하거나 또는 지원을 준비 중이다(아래 표 참조).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/resp-images-browser-supports.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;(* 출처: &lt;a href=&quot;http://responsiveimages.org/&quot;&gt;RICG&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;또한 IE 등 아직 이 기능을 지원하지 않는 브라우저를 위한 폴리필(polyfill) 자바스크립트 라이브러리도 나와 있기 때문에 지금 당장 프로젝트에 적용하더라도 크게 무리는 없을 듯 하다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://caniuse.com/#search=srcset&quot;&gt;srcset 속성 브라우저 지원 현황&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://caniuse.com/#search=picture&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;엘리먼트 브라우저 지원 현황&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://scottjehl.github.io/picturefill/&quot;&gt;Picturefill - A responsive image polyfill&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/aFarkas/respimage&quot;&gt;respimage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;그-밖의-방법들&quot;&gt;그 밖의 방법들&lt;/h2&gt;

&lt;p&gt;지금까지는 주로 클라이언트(브라우저)측 기술, 즉 웹표준으로 자리잡은 srcset/sizes 속성과 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; 엘리먼트를 중심으로 소개했지만 이게 전부는 아니다. 다른 방법들도 존재하고 또 여전히 새로운 방식들이 시도되고 있다. 그 중 몇 가지만 소개하면 다음과 같다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://adaptive-images.com/&quot;&gt;Adaptive Image&lt;/a&gt; 이 방식은 방문자의 웹요청으로부터 디바이스 정보를 감지하여 그에 알맞는 적절한 이미지를 서버측에서 제공하는 서버측 반응형 이미지 처리 방식이다. &lt;a href=&quot;https://github.com/lencioni/SLIR&quot;&gt;SLIR (Smart Lencioni Image Resizer)&lt;/a&gt; 도 이와 유사한 방식이다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/igrigorik/http-client-hints&quot;&gt;HTTP Client-Hints&lt;/a&gt; HTTP 요청 헤더에 브라우저 정보를 실어보내 서버측에서 적절한 이미지를 내보낼 수 있게 하는 일종의 콘텐츠 협상(content negotiation) 방식으로 현재 draft RFC 상태다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://github.com/teleject/hisrc&quot;&gt;HiSRC&lt;/a&gt; 네트워크 속도를 감지하여 서로 다른 이미지를 취하는 조금 독특한 adaptive image 솔루션이다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그 밖에 &lt;a href=&quot;http://jquerypicture.com/&quot;&gt;jQuery Picture&lt;/a&gt;, &lt;a href=&quot;http://www.grahambird.co.uk/lab/doubletake/&quot;&gt;Doubletake&lt;/a&gt;, &lt;a href=&quot;http://foundation.zurb.com/docs/components/interchange.html&quot;&gt;Foundation Interchange&lt;/a&gt;, &lt;a href=&quot;http://imulus.github.io/retinajs/&quot;&gt;Retina.js&lt;/a&gt;, &lt;a href=&quot;http://responsejs.com/&quot;&gt;Response&lt;/a&gt; 등도 참고할만 하다.&lt;/p&gt;

&lt;p&gt;최근 애플(Apple)이 &lt;a href=&quot;https://www.apple.com/imac-with-retina/&quot;&gt;레티나 디스플레이가 장착된 새로운 데스크톱용 PC를 발표&lt;/a&gt;하면서 앞으로 모바일 디바이스 뿐 아니라 데스크톱 PC에도 레티나와 같은 고화질 디스플레이를 장착한 제품들이 늘어날 것으로 보인다. 또한 모바일 디바이스도 더욱 다양한 크기와 화질을 가진 디바이스들이 등장함에 따라 웹에서 이미지를 처리하는 방법은 더욱 다양해질 것 같다. 이 말은 곧 이제 더 이상 예전의 그 익숙한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; 태그 하나만으로 이미지를 처리하던 시대가 끝나가고 있다는 말이기도 하다.&lt;/p&gt;

&lt;p&gt;이미지 파일 하나 하나까지도 다양한 디바이스와 다양한 화면 상황을 고려하여 처리해야 하는 일은 웹 개발자들에겐 쉽지 않은 도전이다. 물론 포토샵(Photoshop)이나 스케치(Sketch) 같은 이미지 편집 도구들은 이미 이런 점들을 고려한 기능들을 갖추고 있고 또 시중에는 다양한 크기의 이미지를 처리할 수 있는 유틸리티 도구들도 여럿 나와 있긴 하지만, 무엇보다도 변하는 기술에 대한 이해를 바탕으로 적절히 도구를 사용하는 것이 도전에 대한 대응책이 될 것 같다.&lt;/p&gt;

&lt;p&gt;끝으로 CMS에 대해 한마디. 요즘 웹사이트는 CMS로 만드는 게 보통이다. 그러니 CMS가 이들 반응형웹과 반응형 이미지에 대한 처리를 많은 부분 자동화시켜 주어야 한다. 예를 들어 워드프레스를 사용한다면, 워드프레스의 다양한 &lt;a href=&quot;https://codex.wordpress.org/Post_Thumbnails&quot;&gt;썸네일(thumbnail) 생성 기능&lt;/a&gt;을 이용하면 쉽게 반응형 이미지 처리에 대응할 수 있을 것이다. &lt;a href=&quot;https://wordpress.org/plugins/hammy/&quot;&gt;Hammy&lt;/a&gt;나 &lt;a href=&quot;https://wordpress.org/plugins/simple-responsive-images/&quot;&gt;Simple Responsive Images&lt;/a&gt; 같은 플러그인들도 참고할만 하다.&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.opera.com/articles/responsive-images/&quot;&gt;Responsive Images: Use Cases and Documented Code Snippets to Get You Started&lt;/a&gt; by Andreas Bovens&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://usecases.responsiveimages.org/&quot;&gt;Use Cases and Requirements for Standardizing Responsive Images&lt;/a&gt; by RICG&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://ericportis.com/posts/2014/srcset-sizes/&quot;&gt;Srcset and sizes&lt;/a&gt; by Eric&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://longhandpixels.net/blog/2014/02/complete-guide-picture-element&quot;&gt;A Complete Guide to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Picture&amp;gt;&lt;/code&gt; Element&lt;/a&gt; by Scott Gilbertson&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.html5rocks.com/en/tutorials/responsive/picture-element/&quot;&gt;Built-in Browser Support for Responsive Images&lt;/a&gt; by Pearl Chen (&lt;a href=&quot;http://www.html5rocks.com/ko/tutorials/responsive/picture-element/&quot;&gt;우리말 번역&lt;/a&gt; by 도창욱)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://css-tricks.com/on-responsive-images/&quot;&gt;On Responsive Images&lt;/a&gt; by Chris Coyier&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.smashingmagazine.com/2013/05/29/the-state-of-responsive-web-design/&quot;&gt;The State Of Responsive Web Design&lt;/a&gt; by Stephanie Walter (우리말 번역: &lt;a href=&quot;http://www.webactually.co.kr/archives/12875&quot;&gt;반응형 웹 디자인의 현재&lt;/a&gt; by Webactually)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://uxd.so/h/retina-web-raster/&quot;&gt;레티나 웹(Retina Web)에 대응하는 우리들의 자세 : “래스터 이미지 편”&lt;/a&gt; by UXD&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://arstechnica.com/information-technology/2014/09/how-a-new-html-element-will-make-the-web-faster/&quot;&gt;How a new HTML element will make the Web faster&lt;/a&gt; by Scott Gilbertson&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>워드프레스에 카카오 계정 로그인 추가하기</title>
   <link href="/2014/07/15/adding-kakao-login-to-wordpress/"/>
   <updated>2014-07-15T00:00:00+00:00</updated>
   <id>/2014/07/15/adding-kakao-login-to-wordpress</id>
   <content type="html">&lt;div class=&quot;panel panel-default&quot;&gt;
  &lt;div class=&quot;panel-body&quot; style=&quot;background: #eee;&quot;&gt;
    &lt;p&gt;  
    &lt;strong&gt;UPDATE(2016-01-19)&lt;/strong&gt; &lt;a href=&quot;https://disqus.com/by/thisgun/&quot; target=&quot;_blank&quot;&gt;thisgun&lt;/a&gt;님이 별도의 코딩 작업 없이 카카오와 네이버 로그인 기능을 추가할 수 있는 Wordpress Social Login 확장 플러그인을 개발하셨다고 댓글로 알려 주셨습니다. 감사드리며, 필요하신 분들은 참고 바랍니다: 
    &lt;a href=&quot;http://sir.co.kr/gnucommerce_tip/6&quot; target=&quot;_blank&quot;&gt;워드프레스에서 네이버 와 카카오 로그인 사용하기&lt;/a&gt;
    &lt;/p&gt;
    &lt;p&gt;  
    &lt;strong&gt;UPDATE(2015-06-12)&lt;/strong&gt; &lt;a href=&quot;https://disqus.com/by/kuthia/&quot; target=&quot;_blank&quot;&gt;Inho Ahn&lt;/a&gt;님이 Wordpress Social Login 플러그인에서 사용하고 있는 라이브러리인 hybridauth의 Kakao Provider와 Naver Provider를 구현한 소스를 댓글로 알려 주셔서 공유합니다. 
    카카오와 네이버 로그인 연동이 필요하신 분들은 참고 바랍니다:
    &lt;a href=&quot;https://github.com/jinseokoh/additional-providers&quot; target=&quot;_blank&quot;&gt;hybridauth providers for Kakao and Naver&lt;/a&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;!-- &lt;div class=&quot;panel panel-default&quot;&gt;
  &lt;div class=&quot;panel-body&quot; style=&quot;background: #eee;&quot;&gt;
    &lt;strong&gt;UPDATE(2015-05-26)&lt;/strong&gt; Kakao 로그인이 제대로 작동하지 않는다고 문의주시는 분들이 계셔서, 아래 포스팅의 내용대로 저희 사이트에 &lt;a href=&quot;http://blog.usefulparadigm.com/wp-login.php&quot; target=&quot;_blank&quot;&gt;DEMO&lt;/a&gt;를 적용해 두었으니 참고 바랍니다. DEMO 테스트로 로그인한 사용자 정보는 주기적으로 삭제 처리됩니다.
  &lt;/div&gt;
&lt;/div&gt; --&gt;

&lt;p&gt;간혹 워드프레스에 카카오(톡)이나 네이버 계정을 이용한 로그인을 추가하려면 어떻게 해야하는지 문의 주시는 분들이 계셔서 오늘은 카카오 계정 로그인 연동하는 법을 간단하게 소개합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/kakao_account_login_btn_large_narrow_ov.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;소셜-로그인-플러그인&quot;&gt;소셜 로그인 플러그인&lt;/h2&gt;

&lt;p&gt;우선 워드프레스에 소셜 로그인(social login) 기능을 추가해주는 플러그인을 하나 설치합니다. 여기서는 &lt;a href=&quot;http://wordpress.org/plugins/wordpress-social-login/&quot;&gt;WordPress Social Login&lt;/a&gt; 이라는 플러그인을 사용하기로 하며, 플러그인은 이미 설치되어 있다고 가정합니다.&lt;/p&gt;

&lt;p&gt;이제 이 플러그인에 카카오톡 로그인 부분을 추가해 보기로 하겠습니다. 우선 아래의 다운로드 URL로 접속하여 Kakao.php 라는 파일을 찾아 다운로드하여 WordPress Social Login 플러그인(이하 ‘WSL’)이 설치된 디렉터리 아래의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hybridauth/Hybrid/Providers&lt;/code&gt; 디렉터리에 복사해 넣습니다.&lt;/p&gt;

&lt;div class=&quot;panel panel-default&quot;&gt;
  &lt;div class=&quot;panel-body&quot;&gt;
		&lt;a href=&quot;https://github.com/usefulparadigm/hybridauth-kakao&quot;&gt;Kakoa.php 다운로드 바로가기&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;그 다음으로  워드프레스 테마의 functions.php 파일에 다음 코드를 추가합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;add_action( 'init', 'my_add_kakao_provider_to_wsl' );

function my_add_kakao_provider_to_wsl() {

    //if ( function_exists ('wsl_version') ) {

        global $WORDPRESS_SOCIAL_LOGIN_PROVIDERS_CONFIG;

        $WORDPRESS_SOCIAL_LOGIN_PROVIDERS_CONFIG[] = ARRAY(
            &quot;provider_id&quot;       =&amp;gt; &quot;Kakao&quot;,
            &quot;provider_name&quot;     =&amp;gt; &quot;Kakao&quot;,
            &quot;require_client_id&quot; =&amp;gt; true,
            &quot;callback&quot;          =&amp;gt; true,
            &quot;new_app_link&quot;      =&amp;gt; &quot;https://developers.kakao.com/apps/new&quot;,
            &quot;cat&quot;               =&amp;gt; &quot;socialnetworks&quot;,
        );
    //}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 워드프레스의 어드민 대시보드에서 Settings &amp;gt; WP Social Login 메뉴에 접속하면 아래 그림과 “Add more providers” 창에 Kakao 버튼이 추가된 것을 확인할 수 있습니다(이 때 버튼의 이미지가 깨지는 이유는 버튼 이미지 파일을 따로 만들지 않은 탓입니다. 적절한 크기의 Kakao버튼 이미지를 만들어 WSL 플러그인의 assets 폴더 아래에 있는 img 폴더에 넣어주면 됩니다).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/add-more-providers.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 이 버튼을 클릭하면 아래와 같이 카카오 계정을 설정하는 부분이 추가된 것을 확인할 수 있을 것입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/wsl-dashboard-kakao-login.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기에 나온 내용 대로 빈칸만 채워주면 설정은 끝입니다. 나와있는 내용 대로 &lt;a href=&quot;https://developers.kakao.com/apps/new&quot;&gt;Kakao Developers 페이지&lt;/a&gt;로 가서 새 앱을 하나 만들고 필요한 정보를 추가한 다음 Application Key 값(REST API 키)을 받아 빈칸에 넣어주면 됩니다(아래 그림 참고).&lt;/p&gt;

&lt;p&gt;계정의 설정 방법은 페이스북이나 트위터 등 다른 SNS 서비스들과 다르지 않기 때문에 큰 어려움은 없을 것입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/hybridauth-kakao-settings.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이것으로 끝입니다. 이제 워드프레스 로그인 창에 다음과 같이 카카오 로그인 아이콘이 추가된 것을 확인할 수 있습니다. 물론 로그인도 되구요!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/wp-login-kakao-icon.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;몇-가지-유의사항&quot;&gt;몇 가지 유의사항&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;카카오 서비스는 &lt;a href=&quot;http://oauth.net/2/&quot;&gt;OAuth 2.0&lt;/a&gt; 인증방식을 따릅니다만 통상적인 OAuth2 기반 서비스들과는 달리 Application Secret 값을 요구하지 않습니다. 그렇지만 WSL 플러그인에서는 이 값을 반드시 필요로 하기 때문에 아무 값으로라도 하나 채워주어야 합니다. 공란만 아니라면 어떤 값이든 상관 없습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;카카오 서비스에서는 통상적으로 실명을 사용하고 이 값은 한글 이름인 경우가 많습니다만 WSL 플러그인에서는 사용자 등록을 하는 과정에서 한글이름을 제대로 처리하지 못합니다. 이 문제는 테마의 functions.php 파일 속에 다음 코드를 추가하면 해결됩니다.&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  add_filter( 'validate_username', 'usefulpa_validate_username_fix' );
  function usefulpa_validate_username_fix( $valid, $username ) {
      if ( empty($username) ) return false;
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;로그인 아이콘 (또는 어드민 대시보드에 들어가는 아이콘)은 &lt;a href=&quot;https://developers.kakao.com/buttons&quot;&gt;카카오 사이트&lt;/a&gt;에서 내려받아 WSL 플러그인 디렉터리 내의 아이콘 이미지 디렉터리 속에 이름을 맞춰 넣어 주면 됩니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;여기서는 카카오 서비스를 이용한 로그인 방법을 소개하였지만 &lt;a href=&quot;http://developer.naver.com/wiki/pages/OAuth2&quot;&gt;네이버&lt;/a&gt;나 &lt;a href=&quot;http://dna.daum.net/apis/oauth&quot;&gt;다음&lt;/a&gt; 같은 국내 다른 포털 서비스의 계정을 이용한 로그인도 이와 같은 식으로 처리하면 어렵지 않게 추가할 수 있으리라 생각됩니다.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>워드프레스 기반 안드로이드 앱 만들기</title>
   <link href="/2014/02/13/building-wordpress-backed-android-app/"/>
   <updated>2014-02-13T00:00:00+00:00</updated>
   <id>/2014/02/13/building-wordpress-backed-android-app</id>
   <content type="html">&lt;div class=&quot;alert alert-info&quot;&gt;
  이 글은 같은 제목으로 &lt;a href=&quot;http://www.bloter.net/archives/181062&quot; target=&quot;_blank&quot;&gt;블로터닷넷&lt;/a&gt;에 게재된 글의 원문입니다.
&lt;/div&gt;

&lt;p&gt;아직도 &lt;a href=&quot;http://wordpress.org/&quot;&gt;워드프레스(WordPress)&lt;/a&gt;를 그저 블로그 만드는 툴 쯤으로 생각하고 계신 분들이 계실지 모르지만, 워드프레스는 이미 블로깅 도구를 넘어 범용 콘텐트 관리 시스템(Content Management System)으로 자리매김한지 오래입니다. 해외는 물론 국내에서도 워드프레스를 기반으로 자사의 홈페이지나 웹사이트를 제작하려는 곳이 늘고 있다는 것은 이미 오래 전에 &lt;a href=&quot;/2012/03/17/creating-static-website-with-wordpress/&quot;&gt;소개&lt;/a&gt;해 드린 적이 있습니다만, 최근엔 여기서 한발 더 나아가 단순 웹사이트 용도가 아니라 일정한 기능을 갖추고 온라인 서비스를 제공하는 웹 애플리케이션으로까지 그 용도가 확장되는 추세입니다. 아예 워드프레스를 웹 개발 프레임워크(framework)로 사용하는 케이스도 생기고 있구요. 맞습니다. 흔히 사용되고 있는 &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;레일스(Ruby on Rails)&lt;/a&gt; 나 &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;장고(Django)&lt;/a&gt;와 같은 바로 그 프레임워크입니다.&lt;/p&gt;

&lt;h2 id=&quot;워드프레스와-모바일&quot;&gt;워드프레스와 모바일&lt;/h2&gt;

&lt;p&gt;요즘은 모바일 세상입니다. 워드프레스라고 예외가 될 순 없겠죠. 그래서인지 최근 워드프레스의 행보도 모바일을 지원하는 방향으로 발빠르게 움직이고 있습니다. 물론 워드프레스는 아주 오래 전부터 모바일 환경에 대응해 왔습니다. 모바일 페이지 전용 플러그인부터 반응형웹(responsive web)을 지원하는 테마까지 즐비합니다. iOS나 Android 운영체제에서 워드프레스 사이트를 손쉽게 관리할 수 있도록 모바일 앱들이 이미 출시되어 있고, 최근의 워드프레스 판올림(3.8버전)에서는 어드민 페이지까지 모바일 환경에 맞춰 최적화시켜 두고 있으니(아래 사진) 아마도 워드프레스는 현존하는 콘텐트 관리 도구들 중 모바일 환경을 가장 잘 지원하는 도구라 해도 거짓은 아닐 정도입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/Screenshot_20140213_113109.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기에 반응형웹 테마도 빠질 수 없겠죠. 반응형웹 기반 테마를 사용하면 소위 “One Source Multi Use” 가 쉬워집니다. 요즘 나오는 거의 모든 워드프레스 테마들이 반응형웹 지원을 기본으로 하고 있으니 워드프레스에서 모바일 디바이스를 지원하는 웹사이트를 제작하는 것은 일도 아닙니다. 그만큼 쉽고 이보다 더 간단할 수 없습니다. 더 이상 뭐가 필요할까요?&lt;/p&gt;

&lt;h2 id=&quot;워드프레스와-안드로이드가-만나면&quot;&gt;워드프레스와 안드로이드가 만나면?&lt;/h2&gt;

&lt;p&gt;그럼에도 가끔은 이런 니즈(needs)가 생길 때도 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“지금 우리가 사용하는 이 워드프레스 사이트의 콘텐트를 기반으로 안드로이드 앱을 만들 순 없을까?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;네, 물론 가능합니다. &lt;a href=&quot;http://premium.wpmudev.org/blog/5-plugins-to-turn-wordpress-into-a-mobile-app/&quot;&gt;플러인들&lt;/a&gt;도 있고 이미 해외에는 (자동화 서비스를 포함) 이 작업을 대행해주는 서비스들도 여럿 있습니다. 그렇지만 직접 만드는 것도 별로 어려운 일은 아닙니다. 쓸 수 있는 도구들이 이미 다 갖춰져 있기 때문에 간단한 안드로이드앱 정도라면 별로 어렵지 않게 뚝딱 만들어 &lt;a href=&quot;https://play.google.com/store&quot;&gt;Google Play 스토어&lt;/a&gt;에 바로 올릴 수 있습니다. 이게 오늘 소개하려는 내용입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/Screenshot_20140213_113936.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;워드프레스를 기반으로 안드로이드(Android) 앱을 만드는 방법에는 여러 가지가 있습니다만, 여기서는 다음과 같은 방식(+단계)로 만들어 나가기로 하겠습니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;워드프레스에서 API 공개하기&lt;/li&gt;
  &lt;li&gt;간단한 모바일 웹 페이지 만들기&lt;/li&gt;
  &lt;li&gt;사용자 인터페이스 꾸미기&lt;/li&gt;
  &lt;li&gt;하이브리드 앱으로 변경하기&lt;/li&gt;
  &lt;li&gt;Play 스토어에 올리기&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이 중 4번(하이브리드 앱으로 변경)과 5번(Play 스토어 올리기) 부분은 이미 다른 곳에 많은 자료들이 나와 있고 또 별로 설명할 부분이 없기 때문에 주로 1~3번 중심으로 설명을 이어 가도록 하겠습니다.&lt;/p&gt;

&lt;h2 id=&quot;워드프레스-api-공개하기&quot;&gt;워드프레스 API 공개하기&lt;/h2&gt;

&lt;p&gt;워드프레스로부터 안드로이드나 iOS같은 모바일 앱을 만들기 위해서는 우선 워드프레스로부터 콘텐트만을 추출해 낼 수 있어야 합니다. 이 작업은 주로 API라는 방식을 통해 이루어지게 되는데, 워드프레스는 이미 공개할 수 있는 API를 갖추고 있습니다. 워드프레스에서는 XML-RPC라는 방식을 사용하는데 주로 이 기능은 외부 블로깅 도구에서 워드프레스를 액세스할 때 많이 사용됩니다. 워드프레스 3.5 버전 부터는 디폴트로 켜져있기 때문에 사용자가 따로 설정하거나 할 부분은 없습니다. &lt;a href=&quot;http://codex.wordpress.org/XML-RPC_Support&quot;&gt;XML-RPC의 자세한 내용&lt;/a&gt;은 워드프레스 문서 저장소인 Codex에서 확인할 수 있습니다.&lt;/p&gt;

&lt;p&gt;다만 이 XML-RPC 방식은 웹 페이지에서 사용하기엔 조금 까다롭습니다. 그래서 웹 상에서 API를 다룰 때는 이 XML 방식보단 JSON 포맷으로 데이터를 받을 수 있는 방식을 주로 사용하게 됩니다. 워드프레스는 아직 자체적으로는 이 JSON 방식의 API는 제공하지 않지만, 워드프레스 플러그인들 중에는 이미 이 기능을 제공하는 것들이 많이 나와 있습니다. 여기서는 그 중 하나인 &lt;a href=&quot;http://wordpress.org/plugins/json-api/&quot;&gt;JSON API 플러그인&lt;/a&gt;을 사용하기로 하겠습니다. 플러그인 설치는 여타 다른 플러그인들과 다를 게 없으므로 생략합니다. 이 플러그인을 설치한 후 API를 호출하면 워드프레스의 포스트들이 다음과 같이 JSON 형식으로 추출됩니다. 이 플러그인이 공개하는 JSON API의 자세한 사용법은 아래 참고자료의 문서를 참조하면 됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/Screenshot_20140213_115801.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;프론트-페이지-구성하기&quot;&gt;프론트 페이지 구성하기&lt;/h2&gt;

&lt;p&gt;워드프레스로부터 JSON 데이터를 추출하였으면, 이제 이 데이터를 읽어서 보여줄 페이지가 필요합니다. 하이브리드(hybrid) 방식의 모바일 앱으로 만들 것이기 때문에 여기서 만든 웹 페이지가 앱의 화면이 됩니다. 모바일웹 페이지를 만드는 방식은 워드프레스라고 해서 다를 게 없습니다. 일반적으로 모바일웹(앱)을 만드는 방식 대로 만들어 주면 됩니다. 여기서는 자바스크립트 라이브러리 중 &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt;를 사용하여 워드프레스로부터 JSON API를 불러 화면에 표시하는 방법을 썼지만, 이 부분은 어디까지나 취향 문제입니다. 여러분 취향에 맞게 가져가면 됩니다. 굳이 Backbone.js를 쓴 까닭은 이 라이브러리가 비교적 간단하게 모듈화된 구조를 만들 수 있는 &lt;a href=&quot;http://todomvc.com/&quot;&gt;자바스크립트 MVC 프레임워크&lt;/a&gt; 중 하나이기 때문입니다.&lt;/p&gt;

&lt;p&gt;웹페이지의 구조나 내용은 아래 참고자료의 데모 소스를 참고하면 되니, 사용법만 간단히 소개합니다. 아래 코드는 이 프로그램의 시작 부분인 &lt;a href=&quot;https://github.com/usefulparadigm/chocosteak/blob/master/app/scripts/main.js&quot;&gt;main.js&lt;/a&gt; 파일인데, 이 부분에서 apiURL 값만 변경해 주면 됩니다. 여기서는 저희가 운영 중인 워드프레스 사이트인 &lt;a href=&quot;http://cookinfacebook.com/&quot;&gt;쿠킹페이스북&lt;/a&gt; 으로부터 API를 불러오고 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;window.chocosteak = {
    Models: {},
    Collections: {},
    Views: {},
    Routers: {},
    appConfig: {
        // Your WordPress Home URL
        apiURL: 'http://cookinfacebook.com/api'
    },
    init: function () {
        'use strict';
        this.appRouter = new this.Routers.AppRouter();
        Backbone.history.start();
    }
};

$(document).ready(function () {
    'use strict';
    chocosteak.init();
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ui-프레임워크-적용&quot;&gt;UI 프레임워크 적용&lt;/h2&gt;

&lt;p&gt;뼈대를 만들었으니 예쁘게 꾸미는 일만 남았습니다. 디자인 작업입니다. 물론 직접 그래픽 도구로 디자인 시안을 작성하고 이 시안에 맞춰 UI를 만들어 내는 게 정석(?) 이겠지만, 여기서는 오픈소스 UI 프레임워크 중 하나인 &lt;a href=&quot;http://www.chocolatechip-ui.com/&quot;&gt;ChocolateChip-UI&lt;/a&gt; 를 사용하기로 하겠습니다. 앞서와 마찬가지로, 이번에도 꼭 ChocolateChip-UI를 사용할 필요는 없습니다. 다른 좋은 UI 프레임워크 도구들도 많이 나와 있으니 그 중 취향에 맞는 것으로 골라 쓰면 됩니다. 저희가 ChocolateChip-UI를 선택한 이유는 무엇보다 제목이 달콤해 보였기 때문입니다.^^&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/chocochipuishot.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;ChocolateChip-UI는 npm을 제공하고 &lt;a href=&quot;http://gruntjs.com/&quot;&gt;Grunt&lt;/a&gt;나 &lt;a href=&quot;http://gulpjs.com/&quot;&gt;Gulp&lt;/a&gt; 같은 빌드 도구들도 지원하기 때문에 자바스크립트에 익숙한 분들이라면 조금 더 쉽게 설치하고 구성할 수 있습니다. &lt;a href=&quot;http://bower.io/&quot;&gt;Bower&lt;/a&gt;로도 설치할 수도 있구요. 안드로이드 뿐 아니라 iOS와 Windows Phone 8의 룩앤필에 맞는 각각의 UI 스타일도 제공하기 때문에 이들 디바이스에 맞는 UI를 구성하는 일도 어렵지 않습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/chocochipuidemo.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서는 이 UI 프레임워크를 Backbone.js의 템플릿으로 사용하였습니다. 템플릿 적용 방법은 아래 참고자료에 나와 있는 문서와 소스코드를 참고하면 될 것입니다.&lt;/p&gt;

&lt;h2 id=&quot;하이브리드-앱으로-포장하여-play-스토어로&quot;&gt;하이브리드 앱으로 포장하여 Play 스토어로!&lt;/h2&gt;

&lt;p&gt;여기까지 작업이 끝나면 이제 이렇게 만든 웹페이지(모바일웹앱)을 하이브리드(hybrid) 앱으로 만들어 앱스토어에 올리기만 하면 됩니다. 하이브리드 앱을 만드는 도구들 역시 여럿 나와 있기 때문에 그 중 하나를 사용하면 되지만, 여기서는 그 중 오픈소스 &lt;a href=&quot;http://cordova.apache.org/&quot;&gt;Apache Cordova&lt;/a&gt;(흔히 PhoneGap이라 불리웠고, 지금은 조금 다른 길을 걷고 있는)를 사용하였습니다.  이미 모바일웹앱으로 만들어 놓은 코드를 Cordova 에서 지정한 디렉터리로 복사하여 안드로이드 앱으로 빌드한 다음 테스트하고 Play 스토어에 올리면 되는 과정입니다. 작업이 다소 복잡할 수도 있지만, 이미 이에 관한 부분들은 인터넷 상에 좋은 문서들이 많이 나와 있기 때문에 지면관계상 설명은 생략합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/cookinfbongoogleplay.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;사실 이런 생각을 가질 수도 있습니다. 반응형웹을 지원하는 웹사이트 정도면 충분하지 않을까? 굳이 이렇게 하이브리드 형태로 앱을 만들 필요가 있을까? 그렇지만 워드프레스를 일종의 콘텐트 “플랫폼(platform)”이라고 생각하고 모바일 디바이스들을 하나의 “브랜치(branch)” 개념으로 본다면, 디바이스마다 그에 적합한 별도의 앱을 만들어 사용자 저변을 확대하고 사용자들의 다양한 니즈에 부합하는 것도 좋은 전략이라 생각이 듭니다. 특히 지금처럼 별로 어렵지 않게 디바이스를 확장해 나갈 수 있다면 말이죠. 게다가 여기서는 어디까지나 모바일웹을 하이브리드 형태로 옮기는 부분까지만 소개했지만, 하이브리드 앱에서는 그 밖에도 모바일 디바이스에서만 사용할 수 있는 다양한 기능들을 추가해 나갈 수 있기 때문에 모바일 앱만의 특유한 방식으로 사용자 경험을 확장해 나갈 수도 물론 있구요.&lt;/p&gt;

&lt;p&gt;여기서부터 시작입니다!&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/plugins/json-api/other_notes/&quot;&gt;JSON API 문서&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js 사이트&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.chocolatechip-ui.com/documentation&quot;&gt;ChocolateChip-UI 문서&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://cordova.apache.org/docs/en/3.3.0/&quot;&gt;Apache Cordova 문서&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/usefulparadigm/chocosteak&quot;&gt;데모 소스&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>OSX에서 Docker로 개발환경 구성하기</title>
   <link href="/2014/02/10/building-devenv-on-osx-using-docker/"/>
   <updated>2014-02-10T00:00:00+00:00</updated>
   <id>/2014/02/10/building-devenv-on-osx-using-docker</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.docker.io/&quot;&gt;Docker&lt;/a&gt;는 리눅스 기반의 가상화 솔루션입니다. Docker가 다른 가상화 솔루션들과 다른 점은 &lt;a href=&quot;http://linuxcontainers.org/&quot;&gt;리눅스 LXC&lt;/a&gt;를 기반으로 가상화 환경을 구성하는 탓에 기존 가상화 솔루션에 비해 훨씬 가볍게 가상화 환경을 구성할 수 있다는 점입니다. Docker에서는 이 가상화 공간을 “컨테이너(container)”라고 부르는데, &lt;a href=&quot;https://www.docker.io/the_whole_story/&quot;&gt;Docker 소개 페이지&lt;/a&gt;에도 나와 있듯 마치 물류 환경에서의 화물 컨테이너와 같은 역할을 합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/Screenshot_20140210_140908.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Docker가 아직 세간에 소개된지 얼마 안되는 솔루션이긴 하지만 하루가 다르게 업데이트가 이루어지고 있는 “인기있는” 솔루션이다 보니 Docker의 모든 면면을 여기서 다 소개할 수는 없고, 대신 여기서는 저희 유스풀패러다임에서 주로 사용하는 개발환경인 OSX에서 Docker로 개발환경을 구성하는 방법만 간단하게 소개할까 합니다. OSX를 주 타겟으로 하지만 Windows 환경에서도 거의 똑같이 적용됩니다.&lt;/p&gt;

&lt;h2 id=&quot;docker의-기본-개념&quot;&gt;Docker의 기본 개념&lt;/h2&gt;

&lt;p&gt;Docker는 기본적으로 클라이언트/서버 아키텍처로 동작합니다. 서버측에 docker 데몬(daemon)이 떠 있고, 클라이언트 측에서 tcp 프로토콜로 서버에 액세스하는 구조입니다. 이 때 서버(데몬)는 앞서 말한 가상화 컨테이너(“docker container”) 들을 관리합니다. REST API도 제공하기 때문에 REST 방식으로 컨테이너를 관리할 수도 있습니다.&lt;/p&gt;

&lt;p&gt;가상화 컨테이너는 “이미지(image)” 형태로 저장되고 관리됩니다. 이 때의 이미지는 프로그램이 동작하는 환경이 저장된 바이너리 이미지이며, Docker가 LXC 기반 위에서 작동하기 때문에 기존 VM 방식의 가상화 이미지들과는 다른 경량의 이미지입니다. 예를 들어, 기존 VM방식에서 이미지는 프로그램 + 라이브러리 + OS 까지 모두 저장되는 형태지만, Docker 이미지는 프로그램 (및 라이브러리)만 저장한 작은 이미지입니다. Docker에서 이 이미지들은 통상적으로 &lt;a href=&quot;http://docs.docker.io/en/latest/reference/builder/&quot;&gt;Dockerfile&lt;/a&gt;이라는 설정파일로부터 빌드되어 만들어지게 되고 빌드 시에는 git과 유사한 형태로 증감분만 저장되는 방식을 따릅니다. 이들 컨테이너 이미지는 &lt;a href=&quot;https://index.docker.io/&quot;&gt;Docker에서 공개한 퍼블릭 저장소&lt;/a&gt;에 저장할 수도 있고 또한 &lt;a href=&quot;http://blog.docker.io/2013/07/how-to-use-your-own-registry/&quot;&gt;private 공간에 저장&lt;/a&gt; 할 수도 있습니다.&lt;/p&gt;

&lt;p&gt;이렇게 빌드한 컨테이너 이미지는 어디에서나 실행 가능합니다. 예를 들어, OSX에서 만든 앱서버 docker 이미지를 그대로 Ubuntu에 올려 사용할 수 있습니다. 이미지가 경량이다 보니 이미지를 새로 만들거나 구성하는데 시간이 거의 걸리지 않기 때문에 가볍게 만들고 쉽게 붙였다 뗐다 할 수 있습니다.그러다 보니 Docker를 기반으로 한 PaaS 형태의 서비스들도 벌써 &lt;a href=&quot;https://orchardup.com/&quot;&gt;여럿&lt;/a&gt; &lt;a href=&quot;http://www.tutum.co/&quot;&gt;생기고&lt;/a&gt; 있구요. 한마디로 &lt;a href=&quot;http://git-scm.com/&quot;&gt;git&lt;/a&gt;이 소프트웨어 개발 환경을 변화시킨 것과 유사하게 docker가 또 한번 그 길에 도전장을 내밉니다.&lt;/p&gt;

&lt;h2 id=&quot;osx에서-docker-사용하기&quot;&gt;OSX에서 Docker 사용하기&lt;/h2&gt;

&lt;p&gt;앞서도 얘기했듯 Docker는 리눅스 컨테이너(LXC)를 기반으로 하기에 LXC를 사용할 수 없는 OSX이나 Windows 환경에서는 결국 &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;VirtualBox&lt;/a&gt;나 &lt;a href=&quot;http://www.vmware.com/kr/&quot;&gt;VMware&lt;/a&gt; 같은 다른 가상화 머신을 먼저 설치하고 그 위에 docker 환경을 구성할 수 밖에 없습니다. OSX에서 가장 많이 사용되는 방법은 VirtualBox와 &lt;a href=&quot;http://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt;를 사용하여 리눅스 환경을 구성하고 그 환경 위에 docker 컨테이너들을 올리는 방법입니다. 최근(지난 주) Docker가 &lt;a href=&quot;http://blog.docker.io/2014/02/docker-0-8-quality-new-builder-features-btrfs-storage-osx-support/&quot;&gt;0.8 버전으로 업데이트&lt;/a&gt;되면서 boot2docker 라는 OSX을 지원하는 좀 더 간단한 방법을 소개하고 있지만 이 역시 기본적으로는 VirtualBox나 VMware 위에서 작동할 수 밖에 없습니다. 현재 시점에서 OSX에서 Docker를 사용하는 방법에는 대체로 다음과 같은 것들이 있습니다:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Vagrant 방식&lt;/strong&gt;: Vagrant로 가상화 머신을 띄우고 그 위에 Ubuntu 또는 LXC가 지원되는 리눅스 OS를 설치한 다음 그 속에 docker를 설치하여 사용하는 방법입니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;docker-osx&lt;/strong&gt;: &lt;a href=&quot;https://github.com/noplay/docker-osx&quot;&gt;docker-osx&lt;/a&gt;은 위의 Vagrant 방식을 조금 더 자동화시켜 OSX에서 쉽게 사용할 수 있도록 만들어주는 도구입니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;boot2docker&lt;/strong&gt;: &lt;a href=&quot;https://github.com/steeve/boot2docker&quot;&gt;boot2docker&lt;/a&gt; 는 docker에 최적화된 &lt;a href=&quot;http://tinycorelinux.net/&quot;&gt;Tiny Core Linux&lt;/a&gt; 기반의 VM을 만들어 OSX에서 쉽게 docker에 액세스할 수 있게 도와주는 도구입니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;어느 방법을 쓰던 작동 원리는 동일합니다. 즉, OSX에 docker 클라이언트를 설치하고 docker CLI로 VM 상의 docker 데몬과 통신하는 방식으로 docker 컨테이너들을 관리하는 형태를 취합니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/Screenshot_20140210_140819.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;참고로, Homebrew를 사용한다면 docker 클라이언트는 brew 명령으로 간단하게 설치할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ brew tap homebrew/binary
$ brew install docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;docker로-nodejs-개발환경-구성하기&quot;&gt;Docker로 Node.js 개발환경 구성하기&lt;/h2&gt;

&lt;p&gt;Docker의 용도는 한 가지가 아니며, 사용하기에 따라 여러 형태로 사용될 수 있습니다. 아직 버전이 낮은 관계로 production 환경에서는 사용이 권장되지 않지만 이미 docker를 production 환경에서 사용하는 곳도 여럿 있을 정도입니다. 그렇지만 가장 대표적인 Docker의 유스케이스는 뭐니뭐니해도 개발환경을 구성하는 것일 겁니다. Docker를 이용하면 production 환경과 동일한 환경을 쉽게 만들고 변형하면서 소프트웨어를 테스트해 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;여기서는 간단한 Node.js 앱을 하나 빌드하여 docker 컨테이너에 올려 실행해 보겠습니다. VirtualBox와 Vagrant는 이미 설치되어 있다고 가정합니다.&lt;/p&gt;

&lt;p&gt;우선 Vagrant로 VirtualBox에 Ubuntu OS를 설치하고 그 속에 docker를 설치합니다. 이 작업은 Vagrant를 이용하면 간단하게 처리할 수 있습니다. 이 작업에 사용된 Vagrantfile은 소스코드를 참고  바랍니다. 완료되면 vagrant box를 띄웁니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ vagrant up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Docker는 기존에 빌드된 이미지를 바로 불러와서 사용할 수도 있지만, 여기서는 간단하게 Dockerfile을 하나 작성하여 새로 docker 이미지를 빌드하는 방식을 따르겠습니다. 우선 프로젝트 디렉터리에서 다음과 같이 Dockerfile을 하나 작성합니다. Dockerfile 자체는 기존의 설치 스크립트들과 다르지 않은 간단한 구조를 가지기 때문에 설명을 생략합니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;FROM ubuntu

# Install Node.js
RUN sudo apt-get update
RUN sudo apt-get install -y python-software-properties # python g++ make
RUN sudo add-apt-repository ppa:chris-lea/node.js
RUN sudo apt-get update
RUN sudo apt-get install -y nodejs

RUN echo &quot;export PATH=$PATH:/opt/node/bin&quot; &amp;gt;&amp;gt; ~/.bashrc
RUN . ~/.bashrc

# Bundle project source
ADD . /opt/src

## Install project dependencies
RUN cd /opt/src; npm install

EXPOSE  8080

# Run the node server
CMD [&quot;node&quot;, &quot;/opt/src/app/index.js&quot;]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 이 Dockerfile을 빌드하면 새로 docker 이미지가 하나 생성됩니다. 이 때 빌드는 Dockerfile의 각 단계별로 진행되며 별도 옵션을 주지 않는 한 자동으로 캐시되기 때문에 Dockerfile이 변경되면 변경된 부분만 다시 빌드할 수 있습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker build -t ubuntu-node-demo .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;빌드된 Docker 이미지들은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker images&lt;/code&gt; 명령으로 확인할 수 있으며, 이렇게 빌드된 이미지는 퍼블릭 저장소에 업로드할 수 있고 프라이빗 저장소를 만들어 저장할 수도 있습니다(git 저장소와 같은 원리). 빌드된 이미지를 docker 컨테이너에서 실행시킬 때는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run&lt;/code&gt; 명령을 사용합니다. 참고로 이 모든 작업들은 OSX 로컬 환경에서 docker CLI로 처리하면 되기 때문에 굳이 VM에 접속할 필요는  없습니다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run -p 8080:8080 ubuntu-node-demo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;여기서 -p 옵션은 &lt;a href=&quot;http://docs.docker.io/en/latest/use/port_redirection/&quot;&gt;포트 포워딩 설정&lt;/a&gt;을 하는 부분이며, 이 Node.js 앱에서는 8080번으로 웹접속을 설정했고 또 컨테이너 바깥(호스팅 VM)에서도 8080번 포트로 액세스하려 하기 때문에 이렇게 설정한 것입니다. 이제 정상적으로 작동하면 브라우저에서 접속하여 확인할 수 있습니다. 이 때 유의할 점은, OSX에서는 컨테이너로의 접속을 위해 실제로 2번의 포트 포워딩이 이루어진다는 점입니다. 한번은 OSX에서 호스팅 VM으로의 포워딩이고, 나머지 한번은 호스팅 VM에서 다시 docker 컨테이너로의 포워딩입니다. 이 중 하나라도 접속이 막히면 물론 웹접속은 이루어지지 않습니다.&lt;/p&gt;

&lt;h2 id=&quot;마무리&quot;&gt;마무리&lt;/h2&gt;

&lt;p&gt;여기까지 Docker의 기본개념과 OSX에서의 개발환경 구성을 중심으로 간단한 사용법을 소개했지만, 어디까지나 수박 겉핧기에 불과합니다. 실제로 Docker는 여기 소개된 것보다 훨씬 다양한 기능들을 갖추고 있으며 다양한 생태계를 만들어 나가고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2014/Screenshot_20140210_140936.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Docker는 이제 겨우 걸음마를 시작한 솔루션입니다. 그렇지만 이미 &lt;a href=&quot;http://www.itworld.co.kr/slideshow/85821&quot;&gt;올해의 오픈소스 수퍼루키 10선&lt;/a&gt;에 포함될 정도로 벌써 유명세를 치루고 있는 “devops 계의 루키”이기도 합니다. 물론 그만한 대접을 받을 자격이 있다 생각도 듭니다. 무거운 짐을 지고 항해하는 고래를 상징하는 로고 마스코트처럼, 올 한해 Docker의 멋진 순항을 기대해 봅니다.&lt;/p&gt;

&lt;p&gt;앞서 소개한 예제는 &lt;a href=&quot;https://github.com/sjoonk/docker-ubuntu-node-hello&quot;&gt;github&lt;/a&gt;에 올려 두었으니, 필요한 분들은 참고 바랍니다.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>터보링크(Turbolinks)와 레일스 4.0</title>
   <link href="/2013/06/28/turbolinks-and-rails-4/"/>
   <updated>2013-06-28T00:00:00+00:00</updated>
   <id>/2013/06/28/turbolinks-and-rails-4</id>
   <content type="html">&lt;p&gt;엊그제 &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;레일스(Ruby on Rails)&lt;/a&gt; 4.0 파이널 버전이 공식적으로 릴리즈 되었다. 2.x 버전에서 3.0 버전으로 넘어올 때 만큼 눈에 띄는 큰 변화는 없지만 그래도 프레임워크 전반에 걸쳐 작은 부분까지 놓치지 않고 세심하게 가다듬은 흔적들이 눈에 띄어 반갑다. 4.0 릴리즈 소식을 전하는 &lt;a href=&quot;http://weblog.rubyonrails.org/&quot;&gt;루비온레일스 블로그&lt;/a&gt;에서 특히 눈에 띈 부분은 터보링크(Turbolinks)를 비중있게 소개하고 있다는 점. 다음은 블로그에서 적힌 터보링크에 대한 소개다:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Speed-up the client-side with Turbolinks, which essentially turns your app into a single-page javascript application in terms of speed, but with none of the developmental drawbacks (except, maybe, compatibility issues with some existing JavaScript packages).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;터보링크를 쓰면 별다른 기술적 문제 없이 속도(speed) 측면에서 싱글페이지 자바스크립트 앱 효과를 낼 수 있다고 되어 있다.&lt;/p&gt;

&lt;h2 id=&quot;pjax와-터보링크&quot;&gt;Pjax와 터보링크&lt;/h2&gt;

&lt;p&gt;도대체 터보링크가 뭐길래? 레일스를 다루지 않는 분들을 위해 간단히 터보링크가 무언지부터 소개해 보자.&lt;/p&gt;

&lt;p&gt;터보링크를 이해하려면 터보링크의 아이디어 소스가 된 pjax부터 알아보는 편이 간단할 것 같다. &lt;a href=&quot;https://github.com/defunkt/jquery-pjax&quot;&gt;Pjax&lt;/a&gt;는 pushState와 Ajax의 결합어다. 말 그대로 HTML5 &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Manipulating_the_browser_history&quot;&gt;pushState&lt;/a&gt; 와 Ajax을 함께 사용하여 pushState 기능이 지원되는 브라우저에서 사용자가 웹페이지의 통상적인 링크를 클릭할 경우 전체 페이지를 갱신(full page refresh)하는 대신, 클릭 이벤트를 가로 채 자동으로 해당 URL에 대해 Ajax 호출을 하고 그 결과로 받은 웹페이지의 일부분(fragment)만으로 기존 웹페이지의 특정 영역을 대체(replace)하는 기법이다.&lt;/p&gt;

&lt;p&gt;Pjax를 쓰면 큰 노력 없이 정적인 웹페이지를 좀 더 빠르게 만들 수 있다. 그저 자바스크립트 라이브러리 하나 추가하는 것만으로 웹페이지 속 링크를 클릭할 때마다 매번 전체 페이지를 새로 갱신해야 하는 부담을 줄여주어 성능을 개선 시킬 수 있는 효과가 있기 때문이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/pjax-requests.jpg&quot; alt=&quot;&quot; /&gt;
(사진출처: &lt;a href=&quot;http://ntotten.com/2012/04/09/building-super-fast-web-apps-with-pjax/&quot;&gt;ntotten.com&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;레일스 &lt;a href=&quot;https://github.com/rails/turbolinks/&quot;&gt;터보링크&lt;/a&gt;는 여기서 한발 더 나간다. Pjax처럼 클릭 이벤트를 가로 채 자동으로 Ajax 호출하는 부분까지는 똑같지만, 아예 요청 결과를 파싱하여 title 태그와 body 태그를 추출한 다음 기존 페이지에서 상응하는 부분만 대체 시킨다. 과히 &lt;a href=&quot;http://en.wikipedia.org/wiki/Convention_over_configuration&quot;&gt;설정 보단 관례(convention over configuration)&lt;/a&gt;를 우선하는 “레일스 스러운” 발상이다. 실제로 터보링크는 37signals의 대표적인 웹서비스인 Basecamp의 모바일 버전에 적용되어 &lt;a href=&quot;http://37signals.com/svn/posts/3269-behind-the-speed-basecamp-mobile&quot;&gt;상당한 성능 개선 효과를 거둔&lt;/a&gt; 것으로 알려져 있기도 하다.&lt;/p&gt;

&lt;h2 id=&quot;호불호好不好&quot;&gt;호불호(好不好)&lt;/h2&gt;

&lt;p&gt;이 터보링크가 과연 레일스 4.0을 대표할 만큼 중요한 것일까? 굳이 프레임워크 속에 디폴트로 집어넣을만한 것이었을까? 레일스 3.1로 넘어올 때 새로 프레임워크에 추가된 &lt;a href=&quot;http://guides.rubyonrails.org/asset_pipeline.html&quot;&gt;에셋 파이프라인(asset pipeline)&lt;/a&gt; 만큼은 아니지만, 그래도 터보링크를 프레임워크 속에 넣는 것을 두고 레일스 커뮤니티에서 갑론을박이 있었던 것으로 기억한다. 그래서인지 레일스 블로그에는 아래와 같은 재밌는 댓들도 눈에 띈다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/idonotlinkturbolinks.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;터보링크를 사용함으로써 얻는 가장 큰 잇점은, 터보링크 페이지에도 소개되어 있듯, 매번 링크를 클릭할 때 마다 페이지 속 여러 에셋들, 즉 자바스크립트나 CSS 파일들을 다시 다운로드하여 리로딩하지 않아도 된다는 점이다(그럼으로써 애플리케이션의 속도를 향상시킬 수 있다).&lt;/p&gt;

&lt;p&gt;그리고 또 한 가지는, 이렇게 매번 자바스크립트 파일을 새로 로드하지 않아도 되기 때문에, &lt;a href=&quot;http://en.wikipedia.org/wiki/Single-page_application&quot;&gt;싱글페이지앱&lt;/a&gt; 구현이 가능해 진다는 점이다. 물론 &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt; 나 &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember.js&lt;/a&gt;, &lt;a href=&quot;http://angularjs.org/&quot;&gt;Angular.js&lt;/a&gt; 같은 &lt;a href=&quot;http://todomvc.com/&quot;&gt;자바스크립트 MV* 프레임워크&lt;/a&gt;를 사용하여 웹앱을 구성하는 것과는 방식이 다르지만, 전체 페이지가 한번만 로드된다는 점, 그에 따라 브라우저 속에서 상태(state)가 보존될 수 있다는 점 등에서는 싱글페이지 앱(SPA) 이다.&lt;/p&gt;

&lt;p&gt;앞서의 자바스크립트 MV* 프레임워크를 사용할 경우, 백엔드 처리를 위해 서버측(레일스 포함)에서 별도의 데이터 포맷(대개는 JSON)을 지원하는 API 엔드포인트(endpoint)를 구성해야 하는데 터보링크는 그냥 기존 방식대로 HTML로 렌더링하면 되니 편리하기도 하다.&lt;/p&gt;

&lt;p&gt;편리함만 있는 게 아니라 문제점도 있다(이런 문제들이 레일스 커뮤니티에서  반론과 비판의 이유가 된다).&lt;/p&gt;

&lt;p&gt;무엇보다도 가장 근본적인 문제는 터보링크가 HTML 페이지 속에서 자바스크립트가 처리되는 방식을 흔들어 놓는다는 점이다. 그리고 이것은 기존의 많은 자바스크립트 라이브러리들과 충돌하는 문제를 일으킬 수 밖에 없다는 게 유명한 오픈소스 개발자 Yehuda Katz의 &lt;a href=&quot;https://plus.google.com/106300407679257154689/posts/A65agXRynUn&quot;&gt;설명&lt;/a&gt;이다:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is not a mere quibble: a lot of existing JavaScript operates under the assumption of a clean scope, and a single DOMContentLoaded event. In a perfect world, popular JavaScript plugins would be architected to work well with a solution like Turbolinks, but the assumption of a clean global scope per server-rendered HTML page is baked into a lot of the JavaScript and jQuery libraries that people tend to use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;물론 레일스 역시 이런 문제점을 인지하고, 특히 jQuery와의 충돌에 대해서는, &lt;a href=&quot;https://github.com/kossnocorp/jquery.turbolinks&quot;&gt;솔루션&lt;/a&gt;도 제시하고 있긴 하지만,  결국 이 문제는 case by case로 해결할 수 밖에 없는 문제로 보인다. 터보링크와 다른 자바스크립트 라이브러리들 간의 호환성에 관한 정보를 제공하는 &lt;a href=&quot;http://reed.github.io/turbolinks-compatibility/&quot;&gt;Turbolinks Compatibility&lt;/a&gt; 같은 곳도 있다.&lt;/p&gt;

&lt;p&gt;자칫 잘못 사용할 경우 자바스크립트 전역 스코프가 초기화되지 않거나(body 태그 속에 동적으로 삽입되는 자바스크립트가 그 예), &lt;a href=&quot;http://staal.io/blog/2013/01/18/dangers-of-turbolinks/&quot;&gt;메모리를 계속해서 잡아먹을 가능성&lt;/a&gt;도 안고 있다.&lt;/p&gt;

&lt;p&gt;레일스 기반 오픈소스 포럼 솔루션 &lt;a href=&quot;http://www.discourse.org/&quot;&gt;Discourse&lt;/a&gt; 공동창업자 Robin Ward는 자신의 &lt;a href=&quot;http://eviltrout.com/2013/01/06/turbolinks-and-the-prague-effect.html&quot;&gt;블로그&lt;/a&gt;에서 프라하 어느 카페에서 인터넷에 접속하는 것을 예시로 들면서 터보링크 보다는 CDN과 자바스크립트 MV* 프레임워크를 사용하는 것이 올바른 접근이라고 말하기도 한다.&lt;/p&gt;

&lt;h2 id=&quot;터보turbo의-의미&quot;&gt;“터보(Turbo)”의 의미&lt;/h2&gt;

&lt;p&gt;조금 경력이 있는 개발자들이라면  “터보”라는 말을 들으면 떠오르는 단어가 있을 것이다. 바로 “터보 파스칼”, “터보 C” 등 앞에 “터보” 글자가 붙는 볼랜드(Borland)사의 컴파일러/IDE 제품군 이름이다. 지금은 컴퓨팅 역사 속으로 사라졌지만, 파스칼과 C언어가 세상을 주름잡던 당시만 하더라도 프로그래밍 언어 앞에 “터보” 가 붙으면 그야말로 “터보 엔진”을 단 것처럼 빠른 컴파일과 빠른 개발 속도를 선사했었다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/porsche-turbolinks.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;터보링크 앞에 붙은 “터보” 역시 그런 의미로 붙여졌을 것이다. 새 레일스 프로젝트를 생성하는 바로 그 순간부터 터보링크가 적용되니 빠르다고 하지 않을 수 없다. 그렇지만 터보링크는 옛날 볼랜드 제품군이 주름잡던 시절의 그 “터보”만큼 강력한 것 같지는 않다.&lt;/p&gt;

&lt;p&gt;그렇다면 언제 사용하면 좋을까?&lt;/p&gt;

&lt;p&gt;국내에서 만들어지는 웹서비스들의 경우 아직은 SPA 방식 보다는 전통적인 서버측 HTML 렌더링 방식을 사용하는 쪽의 비중이 훨씬 높은 것이 사실이다. 자바스크립트 MV* 프레임워크나 CDN을 적용하는 곳도 그렇게 많지는 않은 것 같다. 이런 전통적인(?) 방식의 웹 개발 환경에서라면 터보링크는 분명  “최소 노력으로 최대 효과”를 얻을 수 있는 실용적인 접근이 될 수 있을 것 같다. 특히 기존에 레일스로 만들어진 웹사이트의 모바일 버전을 새로 만드는 경우가 터보링크를 적용하기에 가장 적합한 유스케이스가 아닐까 생각된다. &lt;a href=&quot;(http://37signals.com/svn/posts/3269-behind-the-speed-basecamp-mobile)&quot;&gt;37signals가 그랬듯이&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;레일스 개발자들은 대부분 &lt;a href=&quot;http://www.insightbook.co.kr/books/ppp/%EC%8B%A4%EC%9A%A9%EC%A3%BC%EC%9D%98-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8&quot;&gt;실용주의 개발자&lt;/a&gt;들이다. 필요하면 쓰고 아니면 안쓰면 된다.  터보링크를 레일스 디폴트로 두면서 &lt;a href=&quot;http://37signals.com/svn/writers/dhh&quot;&gt;DHH&lt;/a&gt;가 했던 생각도 아마 그런 게 아니었을까. “내가 써 봤는데 좋더라구. 너도 한번 써 봐!” 맘에 안들면? 혹은 필요 없으면? &lt;a href=&quot;http://blog.steveklabnik.com/posts/2013-06-25-removing-turbolinks-from-rails-4&quot;&gt;안쓰면 그만&lt;/a&gt;이다.&lt;/p&gt;

&lt;p&gt;터보링크의 사용법은 &lt;a href=&quot;http://guides.rubyonrails.org/working_with_javascript_in_rails.html#turbolinks&quot;&gt;Rails Guides&lt;/a&gt;와 &lt;a href=&quot;https://github.com/rails/turbolinks/blob/master/README.md&quot;&gt;터보링크 README 파일&lt;/a&gt;에 잘 나와 있으니 참조하면 된다.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>"한국형" 웹사이트와 워드프레스 게시판</title>
   <link href="/2013/06/21/thinking-the-wordpress-bulletin-board-solutions/"/>
   <updated>2013-06-21T00:00:00+00:00</updated>
   <id>/2013/06/21/thinking-the-wordpress-bulletin-board-solutions</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://wordpress.org/&quot;&gt;워드프레스&lt;/a&gt;에 대한 관심이 높아짐에 따라 국내에서도 요즘은 워드프레스로 웹사이트를 만들려는 분들이 많아지고 있습니다. &lt;a href=&quot;/2012/03/17/creating-static-website-with-wordpress/&quot;&gt;워드프레스로 웹사이트를 제작&lt;/a&gt;하려는 분들이 갖는 워드프레스에 대한 공통적인 “느낌”은 대략 이런 것들인 것 같습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;만들기 쉽고 관리하기도 편하고 검색도 잘되고 또 무엇보다도 “공짜”!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;맞는 말입니다. 그리고 또 워드프레스로 웹사이트를 제작하려는 분들이 갖는 공통적인 “요구사항”이 하나 있는데 그건 바로 웹사이트에 “게시판”을 몇 개 달고자 한다는 것입니다. 우리가 아주 오래 전 호랑이 담배피던 시절 – bbs시절 – 부터 봐 왔던 바로 그 “게시판” 말입니다. 그런데 그 간단할 것 같고 낡디 낡고 흔하디 흔한 “게시판”이 워드프레스에서는 안된다는 말을 접하고는 조금 당황하게 됩니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“아니 그 간단한 게 왜 안되나요?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;맞습니다. 결론부터 말하면 “&lt;strong&gt;안됩니다.&lt;/strong&gt;” 개그콘서트 정여사 버전을 빌리자면 “안되도 너~무 안됩니다.” 하지만 세상에 안되는 건 없다고 믿는 분들도 계십니다. 워드프레스 게시판도 마찬가지입니다. 워드프레스 기본엔진을 뜯어 고쳐 게시판을 우겨 넣기로 한다면 완전 안될거야 또 없습니다. 그렇지만 워드프레스라는 오픈소스는 기본적으로 블로깅 엔진으로 출발했고 지금은 CMS라 우기고 있는 솔루션입니다. 솔루션은 &lt;a href=&quot;http://wpu.kr/note/%ED%95%9C%EA%B5%AD%ED%98%95-%EA%B2%8C%EC%8B%9C%ED%8C%90%EC%9D%B4-%EB%90%98%EB%8A%94-%EC%9B%8C%EB%93%9C%ED%94%84%EB%A0%88%EC%8A%A4%EA%B0%80-%EB%8F%84%EB%8C%80%EC%B2%B4-%EB%AC%B4%EC%97%87%EC%9D%BC/&quot;&gt;정해진 목적에 맞춰 사용하는 게 효율적&lt;/a&gt; 입니다. 말하자면 맞춤옷에 대비되는 기성복인 셈이죠. 워드프레스로 게시판을 만드는 게 왜 안되는지 그  기술적인 이유는 여기서 주절이 늘어 놓지 않겠습니다. (궁금하면 5백원!)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/campus-board.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;한국형-워드프레스-게시판들&quot;&gt;“한국형” 워드프레스 게시판들&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;안된다구요? 이미 워드프레스 게시판 플러그인들이 많이 있잖아요?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;라고 반문하실 수도 있습니다. 맞습니다. 이미 국내에는 여러 종류의 &lt;a href=&quot;http://heiswed.tistory.com/entry/%EC%9B%8C%EB%93%9C%ED%94%84%EB%A0%88%EC%8A%A4-%ED%95%9C%EA%B5%AD%ED%98%95-%EA%B2%8C%EC%8B%9C%ED%8C%90-%EB%AA%A8%EC%9D%8C&quot;&gt;한국형 워드프레스 게시판 플러그인들&lt;/a&gt;이 나와 있습니다. 인터넷 검색만 해 봐도 다음과 같은 플러그인들이 있으며, 이들 모두 통상적인 워드프레스 플러그인들과 마찬가지로 설치하여 활성화시키면 바로 사용할 수 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.lhboard.com/&quot;&gt;LH보드&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://ssamture.net/mh-board&quot;&gt;MH보드&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amumu.kr/plugins/amumu-board-download/&quot;&gt;AMUMU보드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그런데 뭐가 문제냐구요? 문제는 “&lt;strong&gt;한국형&lt;/strong&gt;” 이라는 수식어에 있습니다. 우리가 생각하는 “게시판”의 수준은 아주 높습니다. 그리고 워드프레스 게시판 플러그인들이 제공할 수 있는 수준은 여기에 비하면 턱없이 낮을 수 밖에 없습니다. &lt;a href=&quot;http://www.xpressengine.com/&quot;&gt;제로보드(XE)&lt;/a&gt;나 &lt;a href=&quot;http://sir.co.kr/&quot;&gt;그누보드&lt;/a&gt; 같은 설치형 게시판이나 혹은 포털사이트의 인터넷 카페에서 쓰던 게시판 수준 생각하고 접근하면 낭패를 보기 십상입니다. 아직 그 수준에 이른 플러그인들은 없으며 앞으로도 나오기가 쉽지 않을 테니까요.&lt;/p&gt;

&lt;p&gt;한국의 워드프레스 개발자들이 실력이 없어 그런 건 아닙니다. 그 근본적인 이유는 워드프레스 엔진의 기술적 구조에 있습니다. 워드프레스 엔진은 한국형 게시판을 100% 구현해 넣기엔 부적합한 구조를 갖고 있습니다(나쁘다는 의미가 아니라 다르다는 의미에서). 그러니 이런저런 꼼수(?)를 찾아 다닐 수 밖에요. 이와 관련해서 국내 한 블로그에 소개된 &lt;a href=&quot;http://www.nam.or.kr/archives/691&quot;&gt;분투기&lt;/a&gt;를 읽어 보셔도 재미있을 것 같습니다.&lt;/p&gt;

&lt;h2 id=&quot;워드프레스에-게시판-추가하기&quot;&gt;워드프레스에 게시판 추가하기&lt;/h2&gt;

&lt;p&gt;눈높이를 조금 낮추면 문제는 한결 수월해 집니다. 이제 워드프레스에 맞는 “가벼운” 게시판을 하나 만들어 추가해 보기로 하겠습니다. 통상적으로 워드프레스에 게시판을 추가하는 것은 글(포스트)들을 특정한 카테고리로 묶고 해당 카테고리의 글 목록을 워드프레스 페이지(page)에 표시하는 방식으로 하게 됩니다. 예를 들어, “자유게시판” 이란 제목의 게시판을 하나 만든다고 하면 다음과 같은 순서를 따릅니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;우선 “자유게시판”이란 이름의 카테고리를 하나 만듭니다.&lt;/li&gt;
  &lt;li&gt;이번엔 “자유게시판”이란 이름의 페이지를 하나 생성합니다(이름은 뭐든 상관 없습니다).&lt;/li&gt;
  &lt;li&gt;“자유게시판” 페이지에 “자유게시판” 카테고리로 작성된 글들의 목록을 게시판 형태로 표시합니다.&lt;/li&gt;
  &lt;li&gt;“자유게시판” 페이지를 메뉴에 추가하여 게시판으로 접근할 수 있게 만듭니다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;페이지 속에 글 목록을 넣는 방법은 여러 가지입니다만, 흔히 사용되는 방법은 플러그인에서 제공하는 단축코드(shortcode)를 활용하는 방법입니다. 예를 들어, 위의 게시판 플러그인들 중 하나인 &lt;a href=&quot;http://ssamture.net/mh-board&quot;&gt;MH보드&lt;/a&gt;를 사용한다면, MH보드에서 제공하는 단축코드인 ‘&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[mh_board]&lt;/code&gt;‘를 페이지 본문 속에 넣어주면 이 부분이 게시판으로 치환되어 화면에 표시되는 식입니다(아래 그림).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/mh-board-screenshot.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;기술적으로는, 페이지 속에 글 목록을 넣는다는 것은 워드프레스에서 &lt;a href=&quot;http://codex.wordpress.org/Custom_Queries&quot;&gt;커스텀 쿼리&lt;/a&gt;를 사용하여 루프(loop)를 구성하는 것을 의미합니다. 그리고 이 경우 그 쿼리의 조건값은 특정 카테고리에 속한 모든 글들을 추출하여 목록으로 표시하는 것이구요. 따라서 굳이 게시판 플러그인을 사용하지 않더라도 페이지 속에서 커스텀 쿼리를 구성할 수 있는 방법이라면 뭐든 가능합니다. 예를 들어 &lt;a href=&quot;http://wordpress.org/plugins/list-category-posts/&quot;&gt;List category posts&lt;/a&gt;나 &lt;a href=&quot;http://wordpress.org/plugins/display-posts-shortcode/&quot;&gt;Display Posts Shortcode&lt;/a&gt; 같은 플러그인을 사용할 수도 있고, 간단하게 직접 커스텀 쿼리가 들어간 템플릿을 작성해도 됩니다.&lt;/p&gt;

&lt;p&gt;말이 나온 김에 간단한 템플릿을 하나 만들어 보겠습니다. 특정 카테고리의 글들을 게시판 형태로 보여주는 템플릿인데, 페이지명(slug)과 일치하는 카테고리명(slug)을 가지는 모든 글들을 보여주는 간단한 페이지 템플릿입니다. 일종의 관례(convention)을 만든 것인데요. 이럴 경우, 사용자는 이 템플릿 파일을 테마 디렉터리 속에 넣어 두고, 게시판이 필요할 경우 새 페이지를 하나 생성하고 그 페이지의 템플릿을 이 게시판 템플릿으로 지정하면 자동으로 게시판이 하나 만들어지게 됩니다. 게시판에 글을 쓸 때는 글(포스트)의 카테고리만 게시판 페이지명과 일치하게 주면 자동으로 해당 게시판에 글이 게시가 되는 식입니다.&lt;/p&gt;

&lt;p&gt;커스텀 쿼리는 다음과 같이 주었습니다:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$args = array(
	'category_name' =&amp;gt; get_query_var('pagename'), 
	'posts_per_page' =&amp;gt; 5, 
	'paged' =&amp;gt; get_query_var('paged')	
);

// The Query
query_posts( $args );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 코드가 적용된 페이지 템플릿을 얼마 전 소개한 적이 있는 &lt;a href=&quot;/2013/06/04/introducing-doughnut-wordpress-theme/&quot;&gt;다음 Dough 기반 워드프레스 테마&lt;/a&gt;인 &lt;a href=&quot;https://github.com/usefulparadigm/doughnut&quot;&gt;도넛(Doughnut)&lt;/a&gt;에 적용하면 아래와 같은 결과가 만들어 집니다. 어떠세요? 제법 게시판 같아 보이나요?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/board-sample-shot.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이렇게 직접 템플릿을 구성하면 사용자 인터페이스 변경이 수월해지는 장점이 있습니다. UI를 입맛에 맞게 마음대로 커스터마이징할 수 있습니다. 여기에 사용된 페이지 템플릿 소스는 &lt;a href=&quot;https://github.com/usefulparadigm/doughnut&quot;&gt;도넛(Doughnut)&lt;/a&gt; 코드 속에 들어 있으니 &lt;a href=&quot;https://github.com/usefulparadigm/doughnut/blob/master/board-sample.php&quot;&gt;참고&lt;/a&gt;하시면 되겠습니다.&lt;/p&gt;

&lt;p&gt;이 글에서 따로 소개는 하지 않겠지만, 사용자들이 직접 글을 작성할 수 있도록 “글쓰기” 기능을 추가하는 것도 마찬가지입니다. 여러 가지 방법이 있고 그 중 적절한 것을 고르면 됩니다. 예를 들어 &lt;a href=&quot;http://wordpress.org/plugins/wp-user-frontend/&quot;&gt;WP User Frontend&lt;/a&gt; 같은 플러그인을 사용하는 것도 간단한 한 가지 방법이 될 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.perl.org/&quot;&gt;펄(Perl)&lt;/a&gt; 프로그래밍 격언 중에 “&lt;strong&gt;TMTOWTDI&lt;/strong&gt;“라는 말이 있습니다. 어떤 일을 하는데는 한 가지 이상의 방법이 있다(&lt;a href=&quot;http://en.wikipedia.org/wiki/There's_more_than_one_way_to_do_it&quot;&gt;There’s more than one way to do it&lt;/a&gt;)는 말인데요. 이 말은 워드프레스에도 그대로 적용되는 것 같습니다.&lt;/p&gt;

&lt;h2 id=&quot;업데이트&quot;&gt;업데이트&lt;/h2&gt;

&lt;p&gt;이 글을 포스팅한 후에 댓글 또는 이메일, 트위터 등을 통해 몇몇 분들께서 좋은 정보를 더해 주시고 또 여기에 추가해 주면 좋겠다고 말씀하시는  내용들이 있어 아래에 간략하게 덧붙입니다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.hwangc.com/wordpress-forum-plugin-10-theme-6/&quot;&gt;HwangC의 착한 워드프레스 블로그&lt;/a&gt;에는 bbPress 등 워드프레스 게시판으로 사용할 수 있는 여러 가지 국내외 플러그인과 테마들이 잘 정리되어 있습니다.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.cosmosfarm.com/&quot;&gt;Cosmosfarm&lt;/a&gt;에서 개발한 오픈소스 게시판 플러그인 &lt;a href=&quot;http://www.cosmosfarm.com/products/kboard&quot;&gt;KBoard&lt;/a&gt;는 워드프레스에서 기본으로 제공하는 데이터 구조를 사용하는 대신, 게시판과 댓글 처리를 위해 기본 워드프레스 엔진에 4개의 추가적인 DB테이블을 덧붙이는 방식을 씁니다. 때문에 여늬 “한국형” 게시판들 같은 수준높은 게시판을 구성할 수 있는 장점이 있습니다. 워드프레스를 굳이 이렇게까지 확장해서 쓸거면 차라리 &lt;a href=&quot;http://www.xpressengine.com/&quot;&gt;XE&lt;/a&gt;나 &lt;a href=&quot;http://sir.co.kr/&quot;&gt;그누보드&lt;/a&gt;를 써서 웹사이트를 만드는 게 낫지 않나 생각할 수도 있지만, 아무튼 워드프레스로 게시판 달린 웹사이트를 &lt;strong&gt;굳이 만들어야만&lt;/strong&gt; 하는 “한국형” 개발사 현실에서는 고마운 솔루션이 아닐 수 없습니다.&lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 
 <entry>
   <title>도넛(Doughnut), 다음 Dough 기반 워드프레스 테마</title>
   <link href="/2013/06/04/introducing-doughnut-wordpress-theme/"/>
   <updated>2013-06-04T00:00:00+00:00</updated>
   <id>/2013/06/04/introducing-doughnut-wordpress-theme</id>
   <content type="html">&lt;p&gt;구글링을 하다 보면 아주 좋은 오픈소스 CSS 프레임워크들을 많이 만나게 됩니다. 대표적인 것이 트위터가 만들어 공개한 &lt;a href=&quot;http://twitter.github.io/bootstrap/&quot;&gt;Bootstrap&lt;/a&gt;이고, 그 밖에도 &lt;a href=&quot;http://foundation.zurb.com/&quot;&gt;Foundation&lt;/a&gt;이나 &lt;a href=&quot;http://purecss.io/&quot;&gt;Pure&lt;/a&gt; 등 멋진 라이브러리들이 즐비하기 때문에 무엇을 선택할까가 오히려 고민인 경우가 많습니다. 아! 물론 이건 어디까지나 CSS3와 반응형 웹 디자인 등 최신 프론트엔드 디자인 흐름을 반영한 CSS 프레임워크들을 말하며, Blueprint나 960gs 같은 예전 그리드 방식의 CSS 프레임워크는 논외입니다.&lt;/p&gt;

&lt;p&gt;워드프레스 테마 개발자의 입장에서 보면 좋은 CSS 프레임워크들은 좋은 테마 개발의 재료가 됩니다. 예를 들어, 트위터 부트스트랩 같은 경우는 이 프레임워크에 기반하여 만들어진 테마가 이미 &lt;a href=&quot;http://www.themesforbootstrap.com/frameworks/show/all-wordpress-bootstrap-themes&quot;&gt;아주 많이&lt;/a&gt; &lt;a href=&quot;http://www.hwangc.com/wordpress-twitter-bootstrap-themes-10/&quot;&gt;나와&lt;/a&gt; 있습니다. ZURB의 파운데이션도 마찬가지구요.&lt;/p&gt;

&lt;p&gt;이렇게 좋은 프레임워크들과 여기에 기반한 워드프레스 테마들의 생태계를 보면서 우리나라에도 이런 좋은 CSS 프레임워크들이 많이 나왔으면 좋겠다는 바램을 늘 가지고 있었습니다. 그러다 최근 우연히 다음에서 &lt;a href=&quot;http://dough.daum.net&quot;&gt;Dough&lt;/a&gt; 라는 이름으로 멋진 CSS 라이브러리를 만들어 공개하였다는 사실을 알게 되었습니다. 물론 이전에 네이버 XE엔진에서 사용된 &lt;a href=&quot;https://code.google.com/p/ouif/&quot;&gt;OUIF(Open User Interface Framework)&lt;/a&gt; 라는 공개 UI 프레임워크가 있긴 했습니다만, 최근엔 업데이트가 안되는 듯 해 보입니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://usefulpa.s3.amazonaws.com/images/2013/daum-dough.png&quot; alt=&quot;Daum Dough&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://dough.daum.net&quot;&gt;Dough(도우)&lt;/a&gt;는 다음커뮤니케이션 웹표준기술팀에서 제작한 CSS 기반 UI Framework 입니다. 버전은 아직 0.2.0에 불과하지만, 사용해보면서 느낀 점은, 꼭 필요로 하는 기능들은 왠만큼 다 들어가 있어 보이는 데다 또 사용법도 아주 간단하다는 것이었습니다. 물론 아주 디테일한 부분이나 좀 더 다양한 컴포넌트 지원 등은 추가로 필요한 부분이겠지만, 적어도 지금 수준이라도 간단한 사이트에 적용하는데는 별 문제가 없어 보였습니다.&lt;/p&gt;

&lt;p&gt;그래서 이 멋진 “반죽(dough)”을 발판삼아 간단하게 워드프레스 테마를 하나 만들어 보았습니다. 이름은 반죽에 “nut”을 붙여 “도넛(doughnut)”으로 정했으며, github 페이지에서 다운로드 받으실 수 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/usefulparadigm/doughnut/archive/master.zip&quot;&gt;테마 다운로드&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/usefulparadigm/doughnut&quot;&gt;github 바로가기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;단, 아직은 그저 적용만 시킨 단계인지라 부족한 부분이 많이 있습니다. (언제나 그렇듯) 차츰 개선시켜 나갈 수 있으면 좋겠습니다. 시작이 반이니까요.^^&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>워드프레스 사이트에 결제모듈 연동하기</title>
   <link href="/2013/05/28/adding-custom-payment-gateway-to-wordpress-site/"/>
   <updated>2013-05-28T00:00:00+00:00</updated>
   <id>/2013/05/28/adding-custom-payment-gateway-to-wordpress-site</id>
   <content type="html">&lt;p&gt;작년 초에 &lt;a href=&quot;http://usefulparadigm.com/2012/03/17/creating-static-website-with-wordpress/&quot;&gt;워드프레스로 웹사이트 만들기&lt;/a&gt;를 포스팅할 때만 해도 국내에는 워드프레스와 관련하여 참고할만한 자료나 문서가 많이 부족했지만, 요즘은 서점에만 나가도 워드프레스 관련 책들이 넘친다. 불과 1년 여만에 정말이지 놀라운 변화다. 그만큼 관심도 많아졌고 또 저변도 넓어졌다는 얘기니 워드프레스를 좋아하는 한 사람으로 즐거운 변화가 아닐 수 없다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/wp-books.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;워드프레스로-쇼핑몰-만들기&quot;&gt;워드프레스로 쇼핑몰 만들기&lt;/h2&gt;

&lt;p&gt;그래서인지 요즘 워드프레스와 관련한 문의 중에는 워드프레스로 쇼핑몰을 구축하려고 하는데 어떻게 하면 되는지를 묻는 문의들이 많다. &lt;a href=&quot;http://m-blog.me/?p=1224&quot;&gt;워드프레스로 쇼핑몰을 구축하는게 과연 합리적인 방법인지 아닌지&lt;/a&gt;는 논외로 하고, 실제로 워드프레스로 간단한 쇼핑몰을 만들어 사용하는 사례들도 많이 있으니 못할 것도 아니다.&lt;/p&gt;

&lt;p&gt;일반적으로 쇼핑몰 하면 떠오르는 몇몇 주요한 기능들이 있는데, 워드프레스라고 해서 별반 달라질 건 없다. 예를 들어 상품 정보를 관리하고, 쇼핑카트를 만들고, 사용자가 주문을 할 수 있게 하고, 결제와 배송처리 등을 수행하는 게 통상적인 쇼핑몰의 주요 기능이라면, 워드프레스로 쇼핑몰을 만든다고 해서 이들 기능이 달라진다거나 하지는 않는다는 말이다.&lt;/p&gt;

&lt;p&gt;다만 워드프레스가 기본적으로 블로깅 도구로 부터 출발했고, 또 현재도 콘텐츠 관리 시스템(CMS)으로 주로 불리고 사용되는 탓에 쇼핑몰은 워드프레스가 “잘 하는” 분야는 분명 아니다. 이 점은 워드프레스를 구성하는 데이터베이스 테이블의 구조만 보면 바로 알 수 있다. 워드프레스는 포스트(Post)를 중심으로 하는 비교적 간단한 &lt;a href=&quot;http://codex.wordpress.org/Database_Description&quot;&gt;데이터베이스 구조&lt;/a&gt;를 갖는 탓에 워드프레스에 쇼핑몰 기능을 추가하기 위해서는 결국 워드프레스 엔진을 확장해야 한다. 새로운 데이터 모델의 추가가 불가피하는 말이다.&lt;/p&gt;

&lt;p&gt;다행히 워드프레스 커뮤니티에는 워드프레스 기본 엔진에 이런 “쇼핑몰 기능”을 추가해주는 플러그인들이 많이 나와 있고, 상당히 완성도 높은 플러그인들도 많기 때문에 이들 중 하나를 선택하여 설치하면 워드프레스를 바로 “쇼핑몰”로 변신시킬 수가 있다. 다음 몇몇이 그 중 대표적인 플러그인들이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://getshopped.org/&quot;&gt;WP e-Commerce&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.woothemes.com/woocommerce/&quot;&gt;WooCommerce&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/plugins/wordpress-ecommerce/&quot;&gt;MarketPress&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://jigoshop.com/&quot;&gt;JigoShop&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://cart66.com/&quot;&gt;Cart66&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/plugins/eshop/&quot;&gt;eShop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이들 플러그인 대부분이 기본 기능은 무료로 제공하면서 조금 더 고급이나 확장 기능은 유료인 가격정책을 가져가고 있기 때문에 설치해서 사용해 보고 그 중 가장 마음에 드는 것을 골라 추가 기능을 구매하는 방식으로 사용하면 된다. 다만 한 가지 아쉬운 점은 이 모든 플러그인들이 국내에서 제작된 것이 아니기 때문에 국내 환경을 기반으로 서비스하는 쇼핑몰을 제작하려고 할 경우에는 아무래도 걸리는 부분들이 있다는 점이다. 그 중 대표적인 문제 하나가 바로 “결제 연동”하는 부분이다.&lt;/p&gt;

&lt;h2 id=&quot;결제-연동하기&quot;&gt;결제 연동하기&lt;/h2&gt;

&lt;p&gt;알다시피 국내에서 결제를 처리하기 위해서는 주로 PG사와 계약을 맺고 PG사에서 제공하는 모듈을 받아서 결제 처리를 하게 된다. 국내 주요 PG사 (LG데이콤 U+, 올더게이트, 이니시스, KCP, 페이게이트 등)들은 제각각 자신들만의 연동 모듈을 제공하기 때문에, 결국 위의 플러그인들 중 하나를 선택하여 사용하게 되더라도 결제 처리 부분은 이들 PG사의 모듈 중 하나와 연동해야 하는 문제가 남게 된다. 위의  플러그인들이 여러 종류의 결제 옵션을 제공하고 있기는 하지만 아직 국내 PG사 연동을 지원하는 플러그인은 없기 때문이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/wp-e-commerce.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;여기서는 위에 소개한 플러그인들 중 가장 많이 사용되고 있는 &lt;a href=&quot;http://getshopped.org/&quot;&gt;WP e-Commerce&lt;/a&gt; 플러그인에서 국내 PG사 중 한 곳인 &lt;a href=&quot;http://www.allthegate.com/ags/index.jsp&quot;&gt;올더게이트&lt;/a&gt;의 PG모듈과 연동하는 방법을 간단하게 소개한다. 올더게이트를 선택한 데 특별한 이유가 있는 것은 아니며, 다른 PG사들 역시 기본 연동 방식에는 특별하게 다를 게 없기 때문에 다른 PG모듈과의 연동 시에도 참고할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;올더게이트 연동에 필요한 모듈들은 &lt;a href=&quot;http://www.allthegate.com/ags/download/download_01.jsp&quot;&gt;올더게이트 자료실&lt;/a&gt;에서 다운로드 받을 수 있으며, 자세한 사용법은 함께 따라오는 설치매뉴얼을 참고하면 된다. 설치 매뉴얼에서 보면 올더게이트의 PG연동 모듈은 다음과 같은 처리 흐름을 갖는다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/allthegate-flow.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;따라서 WP e-Commerse 플러그인(이하 ‘wpsc’)에서는 우선 사용자의 주문정보를 받아 PG의 AGS_pay 모듈까지 넘겨주어야 하는데, wpsc 플러그인은 사용자가 커스텀 PG를 추가하고 연동할 수 있는 &lt;a href=&quot;http://getshopped.org/resources/docs/get-involved/writing-a-new-payment-gateway/&quot;&gt;방법&lt;/a&gt;을 이미 만들어 두고 있다. wpsc에서는 wpsc-merchants 디렉터리 속에 두는 것을 권장하고 있지만, 간단하게 플러그인을 하나 만들어 그 속에 다음 코드를 추가해도 된다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$nzshpcrt_gateways[$num]['name'] = '올더게이트PG';  // 게이트웨이명
$nzshpcrt_gateways[$num]['internalname'] = 'pg_allthegate'; 
$nzshpcrt_gateways[$num]['function'] = 'gateway_pg_allthegate';
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 관리자 페이지의 wpsc 플러그인 설정에서 보면 다음과 같이 “올더게이트PG”가 Payment 옵션에 추가된 것을 확인할 수 있다. 이 옵션을 선택하면 올더게이트 PG가 활성화된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/wp-pg-allthegate.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 남은 일은 실제로 PG와 연동하는 부분을 만들어 주는 것이다. 앞서 작성한 코드 중 function 부분을 만들어 채워주면 되는데, 결제창을 팝업으로 띄우고, 주문에 관한 정보를 읽어 팝업창으로 넘기는 방식을 사용해 간단하게 구현해 보았다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;?php 

function gateway_pg_allthegate($seperator, $sessionid) {

	global $wpdb, $wpsc_cart;

	$purchase_log = $wpdb-&amp;gt;get_row(
	&quot;SELECT * FROM `&quot;.WPSC_TABLE_PURCHASE_LOGS.
	&quot;` WHERE `sessionid`= &quot;.$sessionid.&quot; LIMIT 1&quot;
	,ARRAY_A) ;

	$order_id 	= $purchase_log['id'];
	$amt 		= $wpsc_cart-&amp;gt;total_price;

	$pay_url = plugins_url( &quot;source/AGS_pay_1.php?OrdNo=$order_id&amp;amp;amt=$amt&quot; , __FILE__ );
	echo &quot;&amp;lt;script&amp;gt;window.open('$pay_url', '', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no,top=0,left=350,width=527,height=543');&amp;lt;/script&amp;gt;&quot;;
} 

?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 사용자가 상품을 장바구니에 담고 체크아웃하여 “구매하기(Purchase)” 버튼을 클릭하면 다음과 같이 결제창이 팝업으로 표시된다. (여기서는 올더게이트에서 제공하는 샘플 폼을 그대로 사용하였으며, 실제 사용할 때는 필요에 맞게 폼 양식을 적절히 변경하면 될 것이다)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/wp-checkout-demo.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;마무리&quot;&gt;마무리&lt;/h2&gt;

&lt;p&gt;지금까지 설명한 것은 어디까지나 원리를 중심으로 한 간단한 데모일 뿐이다. 실제로 프로덕션 환경에서 사용하기 위해서는 몇 가지가 더 추가되어야 한다. 예를 들면, 올더게이트가 EUC-KR 인코딩 방식을 채택하고 있기 때문에 UTF-8을 기본으로 하는 워드프레스에서 한글을 제대로 처리하기 위해서는 인코딩값을 변환해 주어야 한다. 또 위에서는 설명하지 않았지만, PG사로 부터 받은 결과값을 바탕으로 주문 정보를 업데이트하는 처리도 추가되어야 할 부분이다.&lt;/p&gt;

&lt;p&gt;국내에는 아직까지 워드프레스 기반 쇼핑몰을 지원하는 플러그인은 나와 있지 않은 것 같다. 이미 국내에 많은 좋은 쇼핑몰 솔루션들이 나와 있으니, 요즘과 같은 관심과 저변이 계속된다면 아마 조만간 워드프레스 기반에 맞춘 좋은 플러그인들도 많이 등장할 것이라 예상된다. 그러면 결제 처리와 관련된 문제들도 자연스레 해소되리라 기대해 본다.&lt;/p&gt;

&lt;h2 id=&quot;업데이트&quot;&gt;업데이트&lt;/h2&gt;

&lt;p&gt;이 글을 포스팅한 후에 댓글 또는 이메일 등을 통해 많은 분들께서 좋은 정보들을 제공해 주셨고, 또 그간 국내에서도 쓸만한 쇼핑몰/결제처리 관련 오픈소스들이 제법 공개된 탓에 참고로 정리해 보았습니다. 아래 목록은 계속해서 업데이트할 예정입니다. 혹시라도 빠졌거나 더 추가할만한 내용 알려 주시면 반영하겠습니다.&lt;/p&gt;

&lt;h3 id=&quot;워드프레스-쇼핑몰-솔루션&quot;&gt;워드프레스 쇼핑몰 솔루션&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;아직 워드프레스 기반 쇼핑몰 솔루션(플러그인)은 국내에 나와 있는 것이 없는 것으로 보입니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;결제처리pg연동-솔루션&quot;&gt;결제처리(PG연동) 솔루션&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://studio-jt.co.kr/%EC%9B%8C%EB%93%9C%ED%94%84%EB%A0%88%EC%8A%A4-%ED%95%9C%EA%B5%AD%ED%98%95-%EA%B2%B0%EC%A0%9C-%EC%97%B0%EB%8F%99-%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8-%EB%AC%B4%EB%A3%8C-%EB%B0%B0%ED%8F%AC/&quot;&gt;WooCommerce Paygate JT&lt;/a&gt; 스튜디오 제이티에서 개발한 WooCommerce용 결제모듈이며 Paygate 연동을 지원합니다. &lt;a href=&quot;http://wordpress.org/plugins/woocommerce-paygate-jt/&quot;&gt;다운로드&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.sunnysidesoft.com/woocommerce-paygate/&quot;&gt;WooCommerce Paygate&lt;/a&gt; Sunnysidesoft에서 만든 결제 플러그인이며, WooCommerce 기반에 Paygate 연동을 지원합니다. &lt;a href=&quot;https://github.com/sunnysidesoft/woocommerce-paygate&quot;&gt;다운로드&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;그 밖에도 &lt;a href=&quot;http://www.bloter.net/archives/166509&quot;&gt;플레닛메이트&lt;/a&gt;, &lt;a href=&quot;http://www.optian.co.kr/?p=3442&quot;&gt;옵티안&lt;/a&gt; 같은 곳에서도 결제 솔루션(플러그인)을 제작/판매하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>baas.io 단상</title>
   <link href="/2013/05/23/some-thought-about-baasio/"/>
   <updated>2013-05-23T00:00:00+00:00</updated>
   <id>/2013/05/23/some-thought-about-baasio</id>
   <content type="html">&lt;p&gt;오전에 잠깐 짬을 내어 &lt;a href=&quot;https://baas.io/&quot;&gt;baas.io 서비스&lt;/a&gt;를 한번 사용해 보았습니다. 알다시피 baas.io는 KTH에서 운영하는 클라우드 기반 애플리케이션 백엔드 플랫폼 서비스입니다. 흔히 &lt;a href=&quot;http://ko.wikipedia.org/wiki/PaaS&quot;&gt;PaaS&lt;/a&gt;라고 부르는 이 서비스의 가장 대표격은 최근 Facebook에 인수된 미국 회사 &lt;a href=&quot;https://www.parse.com/&quot;&gt;Parse&lt;/a&gt;라고 할 수 있습니다. 아마 baas.io도 이 Parse를 상당부분 벤치마킹한 서비스가 아닐까 생각이 듭니다. 다만, Parse와는 다르게 아직 오픈베타버전이라 확정된 &lt;a href=&quot;https://baas.io/guidePrice.html&quot;&gt;가격정책&lt;/a&gt;은 나와있지 않으며, 누구든지 무료로 사용해 볼 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://usefulpa.s3.amazonaws.com/images/2013/baasio_bi_300x300.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;baas.io가 제공하는 주요 기능에는 다음과 같은 것들이 있습니다. 자세한 내용은 baas.io 사이트에 잘 소개되어 있습니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;사용자 정보관리&lt;/strong&gt;: 사용자 인증과 권한관리 등을 포함한 사용자 정보 관리 기능을 baas.io에서 대신 처리해 줍니다. 사용자 정보관리는 거의 대부분의 앱서비스에서 꼭 필요로 하는 기능입니다. 요즘 많이들 사용하는 페이스북 인증과의 연동 기능도 제공하고 있어 편리합니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;데이터 관리&lt;/strong&gt;: 사용자 데이터 외에도 앱/웹 서비스에는 보관하고 관리해야 할 여러 종류의 데이터들이 있기 마련입니다. 예를 들어, 간단한 뉴스 앱을 만든다고 하더라도 어딘가에 뉴스 데이터를 관리해야 합니다. baas.io에서는 엔티티(Entity)와 컬렉션(Collection) 이라는 개념으로 쉽게 관계형 데이터 구조를 생성하고 관리할 수 있게 해 줍니다. 게다가 REST 기반 API를 제공하기 때문에 아주 쉽게 액세스가 가능하다는 장점이 있습니다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;이 밖에도 &lt;strong&gt;파일관리&lt;/strong&gt;(사진 업로드 등을 할 수 있습니다), &lt;strong&gt;POI&lt;/strong&gt;(위치기반 서비스를 만들 때 사용됩니다), &lt;strong&gt;PUSH&lt;/strong&gt;(모바일 앱에서는 꼭 필요한 기능이죠?), &lt;strong&gt;고객센터&lt;/strong&gt; 등의 기능을 제공합니다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;현재 iOS, Android, 그리고 Mobile Web 이렇게 3가지 플랫폼을 지원하지만, 제 생각엔 JavaScript를 이용하는 웹앱 보다는 iOS나 Android 앱을 개발할 때 조금 더 유용할 듯 합니다.&lt;/p&gt;

&lt;p&gt;baas.io의 기본 타깃은 모바일(웹)앱에서 필요로 하는 백엔드 단의 공통 서비스들을 baas.io가 제공해 줌으로써, 프론트엔드 앱 개발자들의 앱개발 프로세스를 쉽게 만든다는 측면입니다만, 사실 baas.io에서 제공하는 수준의 백엔드 기능들은 요즘 이런저런 오픈소스 도구나 프레임워크들 덕에 구현이 그렇게 까다롭거나 오랜 시간을 요하는 부분은 아닙니다. 따라서 오히려 baas.io의 장점은 대용량의 트래픽을 커버해 줄 수 있다는 부분이 아닐까 싶습니다만, 아직 가격정책이 책정되지 않아 얼마만큼의 효용이 있을지는 조금 더 두고봐야 할 부분 같습니다.&lt;/p&gt;

&lt;p&gt;나머지 하나는 서비스의 안정성인데, 비록 KT(H)라는 대기업에서 제공하는 서비스라고는 하지만, 최근 &lt;a href=&quot;http://www.bloter.net/archives/149604&quot;&gt;아임IN이나 푸딩 같은 서비스를 갑작스레 closing하는 사례&lt;/a&gt; 등을 감안할 때 언제까지 이 서비스가 유지될지 하는 것은 이 서비스를 사용하는 사람들에겐 중요한 리스크 측면이라 할 것입니다. 뭐 이건 3rd-Party 서비스를 사용하는 모든 프로젝트들의 공통적인 리스크 요인이라 말한다면 특별히 할 말은 없습니다만.&lt;/p&gt;

&lt;p&gt;아직 준비 중인 기능들도 더러 있어 보입니다. 데이터 모델에서는 Activity나 Event 등이 그렇고, Parse와 비교하면 사용자(개발자)가 직접 애플리케이션 로직을 추가할 수 있는 Cloud Code 같은 부분도 필요할 것입니다. 이런 좋은 서비스가 무럭무럭 자라 오래오래 만수무강하길 바랄 뿐.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>워드프레스 웹사이트 제작 가이드</title>
   <link href="/2012/08/13/wordpress-website-builidng-guide-2012/"/>
   <updated>2012-08-13T00:00:00+00:00</updated>
   <id>/2012/08/13/wordpress-website-builidng-guide-2012</id>
   <content type="html">&lt;!-- &lt;div class=&quot;alert-message block-message info&quot;&gt;
	&lt;strong&gt;워드프레스 웹사이트 무료로 제작지원해 드립니다!&lt;/strong&gt; 
	&lt;a href=&quot;/wordpress-hosting&quot;&gt;바로가기&lt;/a&gt;
&lt;/div&gt;	 --&gt;

&lt;p&gt;
워드프레스 기반의 웹사이트를 만들 때 필요한 프로세스와 방법들을 간단하게 STEP BY STEP으로 정리한 자료입니다.
&lt;/p&gt;

&lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/13953429&quot; width=&quot;427&quot; height=&quot;356&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px&quot; allowfullscreen&gt; &lt;/iframe&gt; &lt;div style=&quot;margin-bottom:5px&quot;&gt; &lt;strong&gt; &lt;a href=&quot;http://www.slideshare.net/usefulparadigm/ss-13953429&quot; title=&quot;워드프레스 웹사이트 제작 가이드&quot; target=&quot;_blank&quot;&gt;워드프레스 웹사이트 제작 가이드&lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a href=&quot;http://www.slideshare.net/usefulparadigm&quot; target=&quot;_blank&quot;&gt;Sukjoon Kim&lt;/a&gt;&lt;/strong&gt; &lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>워드프레스로 웹사이트 만들기</title>
   <link href="/2012/03/17/creating-static-website-with-wordpress/"/>
   <updated>2012-03-17T00:00:00+00:00</updated>
   <id>/2012/03/17/creating-static-website-with-wordpress</id>
   <content type="html">&lt;!-- &lt;div class=&quot;alert-message block-message info&quot;&gt;
	&lt;strong&gt;워드프레스 웹사이트 무료로 제작지원해 드립니다!&lt;/strong&gt; 
	&lt;a href=&quot;/wordpress-hosting&quot;&gt;바로가기&lt;/a&gt;
&lt;/div&gt;	 --&gt;

&lt;div class=&quot;panel panel-default&quot;&gt;
  &lt;div class=&quot;panel-body&quot; style=&quot;background: #eee;&quot;&gt;
    워드프레스 웹사이트에 관한 더 많은 정보들은 &lt;strong&gt;&lt;a href=&quot;https://wpguide.usefulparadigm.com/&quot; target=&quot;_blank&quot;&gt;WordPress 가이드&lt;/a&gt;&lt;/strong&gt;를 참고 바랍니다.
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;워드프레스의 인기가 높다. 그래서인지 요즘은 국내에서도 워드프레스를 이용하여 웹사이트를 구축하려는 시도들이 늘고  있다. 그런데 워드프레스는 원래 블로깅 도구로 출발한 탓에 웹사이트와 어울리는 디자인을 만들려면 조금 “손질”이 필요하다. 워드프레스를 블로그로 사용하는 방법은 이미 널리 알려져 있기 때문에 여기서는 워드프레스를 이용하여 웹사이트(흔히 기업이나 단체에서 “홈페이지”라 부르는)를 만드는 법을 소개하려 한다.&lt;/p&gt;

&lt;p&gt;우선 아래 웹사이트를 한번 보자. 이 사이트는 &lt;a href=&quot;http://wpsitebuilding.com/&quot;&gt;Building a Website with WordPress&lt;/a&gt;라는 사이트인데, 워드프레스로 만들었지만 보기에 통상적인 블로그 처럼 보이진 않는다. 워드프레스를 콘텐츠 관리 시스템(CMS) 내지는 그야말로 “정적인 웹사이트(static website)” 만드는 용도로 사용하고 있기 때문이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7052/6989080573_161ed78b7b_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;웹사이트-모드로-변신&quot;&gt;웹사이트 모드로 변신!&lt;/h2&gt;

&lt;p&gt;이렇게 워드프레스를 웹사이트로 사용하기 위해서는 몇 가지 기본적인 설정을 해 주어야 한다. 워드프레스가 설치된 상태에서 관리자 페이지의 Settings &amp;gt; Reading 메뉴로 가면 다음과 같이 프론트 페이지 표시를 어떻게 할건지 하는 부분이 나온다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7199/6842957196_252f93d4f5.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;기본값은 최근 포스트들을 나열하는 방식으로 설정되어 있는데, 블로그라면 이 방식이 적합하다. 그렇지만 웹사이트로 만든다고 하면 정적 페이지(static page)로 설정해 주어야 한다. 옵션 값을 변경하고 프론트 페이지(Front Page) 선택하는 부분에서 Sample Page를 선택한 다음 저장하면 이제 워드프레스가 “블로그 모드”에서 “웹사이트 모드”로 변경된다(일부 테마는 테마 자체에서 이 기능을 활성화시키기도 한다). 참고로 여기 Sample Page는 워드프레스가 그야말로 샘플로 넣어 둔 테스트용 페이지로, 나중에 다른 것으로 바꿀 것이다.&lt;/p&gt;

&lt;h2 id=&quot;테마-선택하기&quot;&gt;테마 선택하기&lt;/h2&gt;

&lt;p&gt;워드프레스의 힘은 테마에서 나온다. 어떤 테마를 선택하냐에 따라 워드프레스는 각양각색의 모양새를 만들어 내기 때문이다. 따라서 웹사이트의 용도에 맞는(또는 고객의 요구사항에 부합하는) 적합한 테마를 선택하는 것이 중요하다. 테마는 &lt;a href=&quot;http://wordpress.org/extend/themes/&quot;&gt;WordPress Themes&lt;/a&gt;에서 무료 테마를 검색해도 좋고 &lt;a href=&quot;http://themeforest.net/&quot;&gt;themeforest&lt;/a&gt;나 &lt;a href=&quot;http://www.studiopress.com/&quot;&gt;StudioPress&lt;/a&gt; 같은 유료 테마 사이트를 이용해도 된다. 여기서는 워드프레스의 2010년 기본 테마인 &lt;a href=&quot;http://wordpress.org/extend/themes/twentyten&quot;&gt;Twenty Ten&lt;/a&gt;을 사용하기로 하겠다.&lt;/p&gt;

&lt;p&gt;테마를 활성(activate) 시키면 다음과 같은 프론트 페이지가 보일 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7048/6989080743_cf6547db87_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;포스트-vs-페이지&quot;&gt;포스트 vs. 페이지&lt;/h2&gt;

&lt;p&gt;워드프레스에서 만들어 낼 수 있는 콘텐츠에는 여러 가지가 있지만 크게는 &lt;strong&gt;포스트(post)&lt;/strong&gt;와 &lt;strong&gt;페이지(page)&lt;/strong&gt;로 나눌 수 있다. 포스트는 ‘블로그 포스트’ 처럼 말 그대로 계속 새로운 내용으로 채워 나가는 콘텐츠를 만들 때 사용하는 반면, 페이지는 한번 만들어 두면 잘 변하지 않는 콘텐츠에 주로 사용한다. 웹사이트에서 흔히 볼 수 있는 회사소개 페이지나 컨택 페이지 같은 “페이지”들이 바로 워드프레스에서 말하는 그 “페이지”다. 블로그에서는 주로 “포스트”가 중심이 되지만, 정적인 콘텐츠들이 많은 웹사이트에서는 페이지의 비중이 높아진다. 페이지를 만들고 페이지를 커스터마이징 해야 할 일이 많아진다는 말이다.&lt;/p&gt;

&lt;p&gt;우선 앞서 임시로 연결해 둔 프론트 페이지 대신 새 페이지를 하나 만들어 보자. 페이지는 워드프레스 관리자로 가서 새 페이지 추가하기를 하면 추가할 수 있다. 여기서는 간단하게 페이지 제목을 “Welcome” 이라 두고 내용에 “환영합니다” 라고 한 줄 적었다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7210/6842956876_81a9be5aff_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 관리자 대시보드의 Settings &amp;gt; Reading 에서 앞서와 같이 프론트 페이지를 방금 전 작성한 Welcome 페이지로 변경해 보자. 그러면 사이트의 메인 페이지가 변경된 것을 확인할 수 있을 것이다. 또한 이전에 있던 Sample Page가 메인 페이지의 메뉴 항목에 새로 추가되어 있는 것도 알 수 있을 것이다. 워드프레스 기반 웹사이트에서 페이지들은 기본적으로 이렇게 메뉴 항목에 추가된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7179/6842956928_534f6980f9_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;또한 워드프레스는 유연한 &lt;strong&gt;페이지 템플릿&lt;/strong&gt; 기능을 제공하기 때문에 원한다면 각각의 페이지마다 다른 페이지 템플릿을 만들어 적용할 수 있다는 점도 참고하면 좋을 것이다.&lt;/p&gt;

&lt;h2 id=&quot;새소식-페이지-추가하기&quot;&gt;‘새소식’ 페이지 추가하기&lt;/h2&gt;

&lt;p&gt;아무리 페이지 중심의 정적인 웹사이트라고는 해도 포스트가 없다면 방문자들에게 별 재미가 없을 것이다. 매번 똑같은 페이지만 보일 바에야 굳이 워드프레스를 사용할 이유가 어디 있을까. 메인 메뉴에 “새소식” 메뉴를 하나 추가하고 이 곳에는 새로운 포스트들이 올라오게 해보자. “새소식”이라는 제목으로 새 페이지를 하나 만들자. 이 때 내용에는 아무 것도 쓰지 말고 그냥 빈 채로 둔다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7205/6842957128_ff6c073316.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 관리자 대시보드로 가서 Settings &amp;gt; Reading의 프론트 페이지 표시 부분에서 지금까지 비워두었던 두 번째 Posts Page 부분을 방금 만든 빈 “새소식” 페이지로 설정하자. 그런 다음 저장하고 다시 메인 페이지로 와서 보면 “새소식” 메뉴가 추가된 것을 알 수 있다. 이 메뉴를 클릭하면 콘텐츠들이 보일 것이다. 바로 우리가 작성한/그리고 앞으로 계속해서 작성해 올리게 될 새소식 “포스트” 들이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7201/6989081037_7fdb762048_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;블로그-흔적-지우기&quot;&gt;‘블로그’ 흔적 지우기&lt;/h2&gt;

&lt;p&gt;그런데 여기 한 가지 문제가 있다. 원래 워드프레스의 많은 부분이 블로그를 전제로 구성되어 있는 탓에, 워드프레스를 웹사이트 모드로 전환하면 여기저기 조금 어색한 부분들이 생기게 된다. 예를 들어 앞서 만든 메인 페이지에 댓글은 굳이 필요가 없다. 마찬가지로 컨택 페이지나 회사소개 페이지 같은 곳에서도 굳이 댓글을 달게 할 필요는 없을 것이다.&lt;/p&gt;

&lt;p&gt;이 때는 테마를 수정해 주면 된다. 알다시피 워드프레스 테마는 여러 개의 테마 파일들로 구성되는데, 그 중 페이지 처리를 담당하는 테마 파일이 &lt;strong&gt;페이지 템플릿&lt;/strong&gt;(page.php) 이다. 이 템플릿 파일을 열어 그 속에 있는 댓글 출력과 관련된 코드를 제거해 주면 이제 페이지에서 댓글이 사라진다. 이 때 테마를 수정하는 방법으로는 테마 자체를 직접 수정해도 되지만, &lt;a href=&quot;http://usefulparadigm.com/2012/03/09/customizing-wordpress-theme-using-child-theme/&quot;&gt;자식테마를 사용하여 관리&lt;/a&gt;하는 것도 좋은 방법이다. 참고로, 지금 사용하고 있는 TwentyTen 테마의 경우 loop-page.php 파일을 열어 그 속에서 comments_template() 함수 호출 부분을 제거해 주면 된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7055/6989102261_f3787957d3_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 밖에도 처리해야 할 일들이 많이 있다. 예를 들면, 워드프레스의 기본 기능인 카테고리(category)나 태그(tag) 기능도 조금 더 웹사이트에 맞춰 변경해 주어야 하고, 페이지의 URL 들도 웹사이트에 맞게 조정해 주는 것이 좋다. 관리자용 대시보드의 경우도 불필요한 것들은 제거해 주어서 글을 작성하는 사람들이 조금 더 편하게 입력할 수 있게 해 주는 것이 좋고, 필요한 위젯이나 플러그인들도 설치해 주어야 한다. 참고자료에 몇 가지 도움이 되는 플러그인들을 소개하였으니 참고하면 좋을 것이다.&lt;/p&gt;

&lt;h2 id=&quot;다른-방법들&quot;&gt;다른 방법들&lt;/h2&gt;

&lt;p&gt;지금까지는 워드프레스의 페이지 기능을 사용하여 정적인 웹사이트를 만드는 법을 알아 보았다. 그렇지만 워드프레스에서 웹사이트를 만들 때 꼭 이 방법만을 사용해야 하는 건 아니다. 앞서는 워드프레스에서 기본으로 제공하는 프론트페이지 설정 기능을 이용하였지만, 이 밖에 index.php 템플릿 파일을 직접 수정(권장하진 않는다)하거나 홈페이지용 템플릿인 home.php 파일을 추가하는 방식으로도 가능하다.&lt;/p&gt;

&lt;p&gt;또한 경우에 따라서는 기존 블로그 스타일을 유지하면서도 얼마든지 웹사이트 “스럽게” 보이는  사이트를 만들 수도 있다. 그 대표적인 방법이 매거진(magazine) 스타일의 테마와 같은, 적합한 용도의 테마를 사용하는 것이다. 아래는 상용 워드프레스 테마 중 하나인 &lt;a href=&quot;http://www.pagelines.com/showcase/genres/magazine/&quot;&gt;PageLines&lt;/a&gt;의 데모 화면들인데, 보다시피 블로그라기 보다는 훨씬 더 웹사이트에 가까워 보인다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7200/6989081345_b3d88c4b48_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이상으로 워드프레스를 웹사이트 용도도 사용하는 방법을 간단하게 소개했다. 지금까지 살펴 본 것만으로도 워드프레스가 얼마나 자유롭게 변형이 가능한 강력한 도구인지 가늠이 되었을 것이다. 그렇지만 이게 전부가 아니다. 차라리 맛보기 정도라고 불러야 맞을 것이다. 이 밖에도 워드프레스를 용도에 맞게 변경해서 사용할 수 있는 방법들은 헤아릴 수 없을 정도로 많다. 한마디로 “Sky is the limit” 이다.&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;h3 id=&quot;참고문서&quot;&gt;참고문서&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://wpsitebuilding.com/how-to-build-a-website-with-wordpress&quot;&gt;How to Build a Website with WordPress&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/Creating_a_Static_Front_Page&quot;&gt;Creating a Static Front Page&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://digwp.com/2012/01/wordpress-cms-plugins/&quot;&gt;WordPress CMS Plugins&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;웹사이트-만들-때-사용하기-좋은-테마들&quot;&gt;웹사이트 만들 때 사용하기 좋은 테마들&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.studiopress.com/themes/genesis&quot;&gt;Genesis Framework&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.pagelines.com/&quot;&gt;PageLines&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/themes/thematic&quot;&gt;Thematic&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;기타 각종 유/무료 테마들은 구글 등 검색엔진에서 “&lt;a href=&quot;https://www.google.co.kr/search?q=wordpress+magazine+theme&quot;&gt;wordpress magazine theme&lt;/a&gt;“이나 “&lt;a href=&quot;https://www.google.co.kr/search?q=wordpress+magazine+theme&quot;&gt;wordpress website theme&lt;/a&gt;” 등의 검색어로 검색하면 쉽게 찾을 수 있다&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;웹사이트에서-사용하면-좋을-유용한-플러그인들&quot;&gt;웹사이트에서 사용하면 좋을 유용한 플러그인들&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/wp-cms-post-control/&quot;&gt;WP-CMS Post Control&lt;/a&gt; 관리자 페이지를 CMS 용도에 맞게 수정&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/my-page-order/&quot;&gt;My Page Order&lt;/a&gt; 드래그드롭 방식으로 페이지 정렬&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.webspaceworks.com/resources/wordpress/30/&quot;&gt;Fold Page List&lt;/a&gt; 중첩 페이지 목록 표시&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/page-links-to/&quot;&gt;Page Links To&lt;/a&gt; 워드프레스 페이지에서 외부 URL 링크&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/pagemash/&quot;&gt;PageMash&lt;/a&gt; 드래그드롭으로 페이지 구조 관리&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/fresh-page/&quot;&gt;Flutter&lt;/a&gt; 커스텀 페이지 패널 작성&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://podscms.org/&quot;&gt;Pods CMS&lt;/a&gt; 범용 워드프레스 CMS 확장&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/rich-text-widget/&quot;&gt;Rich Text Widget&lt;/a&gt; 위젯에 리치 텍스트 추가&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/plugins/exec-php/&quot;&gt;Exec-PHP&lt;/a&gt; 페이지나 포스트 속에서 php 코드 사용&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>자식테마를 이용한 워드프레스 테마 관리하기</title>
   <link href="/2012/03/09/customizing-wordpress-theme-using-child-theme/"/>
   <updated>2012-03-09T00:00:00+00:00</updated>
   <id>/2012/03/09/customizing-wordpress-theme-using-child-theme</id>
   <content type="html">&lt;p&gt;워드프레스를 사용하다보면 테마(theme)를 수정해야 할 일들이 종종 생기게 된다. 이 때 워드프레스 테마를 수정할 수 있는 방법은 크게 두 가지인데, 하나는 직접 테마 자체를 수정하는 것이고 나머지 하나는 바로 지금 소개할 &lt;strong&gt;자식테마(child theme)&lt;/strong&gt;를 만들어 사용하는 것이다. 자식 테마는 다른 테마의 기능을 상속(inherit)받아 새로운 테마를 만들고 그 위에 필요한 기능만 덧붙이는 것으로, 이 때 상속받는 대상을 &lt;strong&gt;부모테마(parent theme)&lt;/strong&gt;라 부른다. 마치 실세계에서 자식이 부모의 유전자를 상속받는 것이나 객체지향 프로그래밍에서 자식객체가 부모객체를 상속받는 것과 유사한 개념으로 워드프레스 2.7부터 새로 도입되었다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7049/6966237459_ddd63fff69.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;자식테마를 만들어 사용하는 것은 테마의 호환성 관리 차원에서도 좋은 선택이다. 예를 들어, 내가 어떤 테마를 수정해서 쓰고 있는데, 그 테마가 어느날 업데이트되었다고 하자. 그러면 내가 지금껏 직접 테마에 가했던 변경사항들을 고스란히 다시 새 테마에 반영해 주어야 하는 문제가 생긴다. &lt;strike&gt;혹은 지금 쓰고 있던 테마가 구닥다리라서 새로운 테마로 갈아타려고 할 때에에도 기존에 테마에 가했던 이런저런 여러 가지 변경들 때문에 발목이 잡히기 일쑤다.&lt;/strike&gt; 자식테마를 사용하면 이런 “과거의 미련”으로부터 자유로울 수 있다.&lt;/p&gt;

&lt;h2 id=&quot;부모테마-고르기&quot;&gt;부모테마 고르기&lt;/h2&gt;

&lt;p&gt;그럼 자식테마를 한번 만들어보기로 하자. 어렵지 않다. 우선 부모가 될 테마를 하나 선택해야 한다. 어떤 테마든 부모테마가 될 수 있지만, 가급적 워드프레스의 새로운 버전의 기능들이 잘 반영된 테마를 부모테마로 삼는 게 좋다.&lt;/p&gt;

&lt;p&gt;그런 테마에는 어떤 것들이 있을까? 몇 가지만 추려보면 다음과 같다. 그 밖에 더 많은 테마들은 구글에서  ‘wordpress theme framework’로 검색해 보면 쉽게 찾을 수 있을 것이다. (테마 프레임워크는 자식테마와는 조금 다른 개념이지만, 테마 프레임워크를 부모테마로 사용해도 나쁠 건 없다)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://theme.wordpress.com/themes/twentyeleven/&quot;&gt;Twenty Eleven&lt;/a&gt; 워드프레스 3.0의 디폴트 테마&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/themes/notes-blog-core-theme&quot;&gt;Notes Blog Core&lt;/a&gt; Smashing WordPress로 유명한 Notes Blog에서 사용하는 테마&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wordpress.org/extend/themes/thematic&quot;&gt;Thematic&lt;/a&gt; 인기있는 테마 프레임워크&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;여기서는 &lt;a href=&quot;http://wordpress.org/extend/themes/notes-blog-core-theme&quot;&gt;Notes Blog Core&lt;/a&gt; 테마를 사용하기로 한다. 자식테마를 만들기 위해서는 먼저 부모테마가 설치되어 있어야 하니 설치가 안되어 있다면 설치하고 다음으로 넘어가자.&lt;/p&gt;

&lt;h2 id=&quot;자식테마-만들기&quot;&gt;자식테마 만들기&lt;/h2&gt;

&lt;p&gt;자식테마를 만드는 일은 간단하다. 워드프레스의 테마 디렉터리(wp-content/themes/) 아래에 적당한 이름으로 테마 폴더를 하나 생성해 주고 그 속에 style.css 파일만 하나 만들어 주면 끝이다. 그리고 style.css 맨 위에 다음과 같은 주석으로 이 테마가 Notes Blog Core 테마를 부모테마로 하는 자식테마임을 선언해 주면 된다. Template 란에 부모테마의 디렉터리명을 적어주는 것이 중요하다.&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
/*
Theme Name: 자식 테마 이름
Theme URI: http://your-theme-homepage.com
Description: 뭐든 테마를 기술할 수 있는 말을 적으세요!
Author: 누구?
Author URI: http://your-website.com
Template: notes-blog-core-theme
Version: A version number
.
기타 일반적인 정보들. 예를 들면, 라이선스 정보라든가 플러그인 요구사항, 호환성 정보, 기타 사용자들과 나누고픈 내용들
.
*/
&lt;/pre&gt;

&lt;p&gt;이제 워드프레스 대시보드로 가서 방금 전 만든 테마로 변경하자. 처음 만들어진 자식테마는 물론 아직 부모테마와 똑같은 모양이 아닐 것이다. 부모테마로부터 모든 기능을 물러 받았지만, 외모(look &amp;amp; feel) 부분은 아직 물러받지 못했기 때문이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7193/6966237287_e2e74c6905_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;테마-변경하기&quot;&gt;테마 변경하기&lt;/h2&gt;

&lt;p&gt;그럼 이제 style.css에 몇 가지 변경을 가해 보자. 우선 부모테마의 스타일부터 상속받자. style.css 에 다음 한 줄을 추가하고 나면 이제 부모테마와 똑같아 졌을 것이다.&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
@import url(&quot;../notes-blog-core-theme/style.css&quot;);
&lt;/pre&gt;

&lt;p&gt;부모에 의존하는 것은 여기까지가 끝이다. 이제부터는 자신만의 길을 가야한다. 지금부터 style.css에 추가하는 내용은 부모테마와 달라지는 부분이다. 예를 들어, 부모테마의 글꼴을 나눔고딕체로 변경하고 싶다면 다음과 같은 식으로 자식테마에서 변경해 주면 된다.&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
body {
	font-family: NamumGothic;
}
&lt;/pre&gt;

&lt;p&gt;만약 style.css 외에 테마의 다른 부분을 변경하고 싶다면? 마찬가지다. 부모테마에 있는 테마 파일과 동일한 이름의 테마 파일을 자식테마 디렉터리에 만들어 두고 그 속에서 필요한 변경을 해 주면 된다. 예를 들어, 페이지 테마에 변경을 가하고 싶으면, 부모테마 디렉터리에 있는 page.php 파일을 자식테마 디렉터리에 복사하고 그 복사한 page.php 파일을 변경하면 된다. 언제나 자식테마가 우선이다. 워드프레스는 자식테마인 경우 자식테마의 디렉터리를 먼저 참조하고 없을 경우만 부모테마를 찾는다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7046/6966237383_534c87d570_z.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;고려해야-할-점들&quot;&gt;고려해야 할 점들&lt;/h2&gt;

&lt;p&gt;그렇지만 자식테마가 만병통치약은 아니다. 과다하게 자식테마를 사용하는 것은 결국 부모테마를 직접 고치는 것과 별반 다른 게 없다. 게다가 자식테마를 사용할 경우 워드프레스가 부모테마와 자식테마 간을 상호참조해야 하기 때문에 복잡도가 조금 더 높아지고 약간의 성능감소도 따르는 것이 사실이다. 그렇지만 부모테마를 그대로 쓰되 스타일링 부분만 변경하려 하거나 아니면 funtion.php를 수정하여 약간의 기능변경을 하려 하는 경우라면 자식테마는 좋은 솔루션이 될 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;자식테마와 관련해 더 자세한 내용은 아래 참고자료를 참고하자.&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/Child_Themes&quot;&gt;Codex Child Themes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://themeshaper.com/2009/04/17/wordpress-child-theme-basics/&quot;&gt;WordPress Child Theme Basics&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.webdesignerdepot.com/2011/12/creating-your-first-wordpress-child-theme/&quot;&gt;Creating your first WordPress child theme&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://sixrevisions.com/wordpress/wordpress-theme-frameworks-options-you-should-consider/&quot;&gt;WordPress Theme Frameworks: Options You Should Consider&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.webdesignerdepot.com/2011/10/a-comparison-of-leading-wordpress-theme-frameworks/&quot;&gt;A comparison of leading WordPress theme frameworks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>git-scribe로 전자책 만들기</title>
   <link href="/2012/02/17/creating-ebook-with-git-scribe/"/>
   <updated>2012-02-17T00:00:00+00:00</updated>
   <id>/2012/02/17/creating-ebook-with-git-scribe</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7070/6890389633_851a7a1384_m.jpg&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;요즘 전자책 시장이 다시 활기를 띠고 있는 듯한 느낌이다. 아마존이나 애플, 구글 등 세계적인 IT기업들이 전자책 시장에 뛰어들어 속속 멋진 제품들을 쏟아내고 있고, 국내에서도 여러 업체들이 전자책 단말기부터 전자책 유통 플랫폼, 전자책 콘텐츠에 이르는 여러 가지 아이디어와 상품들을 출시하고 있다.&lt;/p&gt;

&lt;p&gt;게다가 아이패드나 갤럭시탭 등 스마트 기기의 보급과 정부의 디지털 교과서 정책 등이 맞물려 앞으로도 계속해서 전자책 시장은 그 규모가 커지리라는 사실을 누구나 예상할 수 있다. 특히 최근에는 애플이 iBooks Author라는 전자책 저작 도구를 만들어 무료로 배포함으로써 이제 명실공히 “누구든 책을 출간할 수 있는 시대”의 서막을 열었다. 물론 아직도 가야할 길은 멀지만 그렇다고 무작정 기다릴 수만은 없는 일.&lt;/p&gt;

&lt;p&gt;이 글에서는 &lt;a href=&quot;https://github.com/schacon/git-scribe&quot;&gt;git-scribe&lt;/a&gt;라는 간단한 오픈소스 전자책 저작도구을 사용하여 전자책을 직접 한번 만들어 보기로 하겠다.&lt;/p&gt;

&lt;h2 id=&quot;설치하기&quot;&gt;설치하기&lt;/h2&gt;

&lt;p&gt;git-scribe는 루비 젬이다. 따라서 당연히 &lt;a href=&quot;http://www.ruby-lang.org/ko/&quot;&gt;루비&lt;/a&gt;가 설치되어 있어야 하며, 또한 &lt;a href=&quot;http://git-scm.com/&quot;&gt;git&lt;/a&gt;을 데이터 저장소로 사용하는 관계로 git도 설치되어 있어야한다. 이 두 프로그램은 많은 사용자들의 컴퓨터에 이미 설치되어 있는 경우가 많고 또 설치 방법도 비교적 간단하기 때문에 여기서 따로 설명은 생략한다. 이 밖에도 몇 가지 추가적인 라이브러리를 설치해야 하는데, 필요한 라이브러리들은 각각 다음과 같다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;asciidoc : 소스문서 작성을 위해 필요&lt;/li&gt;
  &lt;li&gt;xsltproc : 소스문서의 html 변환을 위해 필요&lt;/li&gt;
  &lt;li&gt;a2x : epub 파일 생성을 위해 필요&lt;/li&gt;
  &lt;li&gt;source-highlight : 소스코드 구문 강조(syntax highlight)를 위해 필요&lt;/li&gt;
  &lt;li&gt;fop : PDF 파일 생성을 위해 필요&lt;/li&gt;
  &lt;li&gt;kindlegen : mobi  파일 생성을 위해 필요&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;우선 터미널에서 아래 명령으로 이들 라이브러리가 설치되어 있는지 확인하자.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git scribe check asciidoc - ok xsltproc - ok a2x - ok highlighting - ok fop - ok
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;설치되어 있지 않다면 설치해야 한다. 맥을 사용하고 있고 &lt;a href=&quot;http://mxcl.github.com/homebrew/&quot;&gt;Homebrew&lt;/a&gt;가 설치되어 있다면 다음과 같이 간단한 명령만으로 쉽게 설치할 수 있을 것이다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ brew install asciidoc source-highlight fop
$ brew install https://raw.github.com/adamv/homebrew-alt/master/non-free/kindlegen.rb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;책-만들기&quot;&gt;책 만들기&lt;/h2&gt;

&lt;p&gt;자, 이제 준비가 끝났으면 책을 한번 만들어 보기로 하자. 터미널을 열어 책을 쓸 디렉터리를 하나 만들자. 디렉터리명이 mybook이라면 다음과 같이 명령을 주면 된다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git scribe init mybook
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 mybook이라는 디렉터리가 생성되는데, 이 디렉터리에 들어가 보면 필요한 몇 개의 파일과 디렉터리들이 이미 만들어져 있음을 확인할 수 있을 것이다. 이것으로 끝이다. 이것으로 책을 쓸 모든 준비는 끝이 났다. 이제 책 “쓰는” 일만 남았다.&lt;/p&gt;

&lt;p&gt;그렇다면 책은 어디에다 써야 할까? 디렉터리 구조를 들여다 보면 이미 book 이라는 이름의 디렉터리가 만들어져 있는 것을 확인할 수 있을 것이다. 이 디렉터리가 책을 담을 곳이다. 이 디렉터리 속에 보면  book.asc 라는 파일이 있는데 이 파일이 모든 책의 시작점이 된다. 마치 웹사이트에서 index.html 파일이 시작점이 되는 것과 마찬가지다.&lt;/p&gt;

&lt;p&gt;파일을 열어보면 샘플로 작성된 문서가 있을테니 그 문서를 참조하여 글을 작성하면 될 것이다. 파일명에서 알 수 있듯 git-scribe는 AsciiDoc 이라는 문서 포맷을 사용한다. AsciiDoc 사용법은 &lt;a href=&quot;http://www.methods.co.nz/asciidoc/&quot;&gt;AsciiDoc 홈페이지&lt;/a&gt;나 또는 &lt;a href=&quot;http://powerman.name/doc/asciidoc&quot;&gt;AsciiDoc cheatsheet&lt;/a&gt;을 참고하면 된다.&lt;/p&gt;

&lt;h2 id=&quot;전자책-파일로-변환하기&quot;&gt;전자책 파일로 변환하기&lt;/h2&gt;

&lt;p&gt;책을 다 만들었다면 이제 전자책으로 변환하는 일만 남았다. 역시 간단하다. 터미널에서 다음 명령만 주면 된다. (중괄호 속의 단어 중 필요한 것 하나만 선택하면 된다. 예를 들어, epub 포맷으로 만들고 싶다면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git scribe gen epub&lt;/code&gt; 와 같은 식으로 주면 된다는 말이다)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git scribe gen [site|html|pdf|epub|mobi|all]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;이제 output 디렉터리를 열어보면 요청한 전자책 포맷대로 파일이 생성되어 있음을 확인할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;전자책 출간을 축하드린다!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Facebook Page에 iFrame Tab 추가하기</title>
   <link href="/2011/11/28/making-facebook-iframe-tabs-for-pages/"/>
   <updated>2011-11-28T00:00:00+00:00</updated>
   <id>/2011/11/28/making-facebook-iframe-tabs-for-pages</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7169/6417234831_80e84d748c_m.jpg&quot; class=&quot;right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;페이스북 사용자가 증가함에 따라 최근 기업들도 앞다퉈 페이스북Facebook 플랫폼을 기업의 마케팅 기반에 추가하는 사례가 늘어가고 있다.
페이스북 마케팅의 시작은 통상적으로 페이스북에 페이지를 만드는 것에서부터 출발하는 경우가 많은데, 페이스북 페이지를 운영하다 보면
페이스북에서 기본으로 제공하는 페이지 만으로는 필요한 니즈를 충족하지 못해 새로운 탭을 만들어야 하는 경우가 생기게 된다. 
이 때 가장 간단한 방법은 시중에 나와 있는 페이스북 탭 애플리케이션들(유/무료)을 이용하는 것이지만, 경우에 따라서는 이런 솔루션들만으로
니즈를 충족시키지 못하는 경우도 있고, 또 간단한 페이지 탭인 경우는 굳이 솔루션의 도움을 받지 않아도 되는 경우도 생긴다.&lt;/p&gt;

&lt;p&gt;여기서는 별도 솔루션을 사용하지 않고, 직접 만드는 방법을 소개한다. 
기존 솔루션의 종류나 사용법에 대해서는 페이스북에서 “static html” 또는 “static iframe”으로 검색하면 자세한 목록을 얻을 수 있다.&lt;/p&gt;

&lt;h2 id=&quot;1-페이스북-앱-등록하기&quot;&gt;1. 페이스북 앱 등록하기&lt;/h2&gt;

&lt;p&gt;페이스북 Page Tab도 일종의 페이스북 앱(App) 이기 때문에 아주 간단한 탭이라도 &lt;a href=&quot;https://developers.facebook.com/apps&quot;&gt;Facebook 개발자 사이트&lt;/a&gt;에 접속, 앱을 등록하는 절차를 거쳐야 한다. 만들려고 하는 것이 페이지 탭이기 때문에 &lt;strong&gt;페이지 탭&lt;/strong&gt; 메뉴를
활성화시킨 다음, 탭과 연결할 사이트(통상적으로는 이벤트 페이지가 될 것이다)의 페이지 URL을 등록해 주면 된다. 이 때 유의해야 할 점은,
페이스북이 &lt;a href=&quot;https://developers.facebook.com/docs/oauth2-https-migration/&quot;&gt;2011년 10월부터 모든 캔버스 앱(및 페이지 탭)에 대해 HTTPS를 적용&lt;/a&gt;함에 따라 반드시 https:// 로 시작하는 보안 URL을 등록해 줘야 한다는 점이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7010/6417314635_181d61878b_z.jpg&quot; alt=&quot;페이스북 앱 등록&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;2-콘텐츠-페이지-만들기&quot;&gt;2. 콘텐츠 페이지 만들기&lt;/h2&gt;

&lt;p&gt;앱 등록을 하였으면 실제 페이지 탭 속에 들어갈 콘텐츠 페이지를 만들어야 한다. 콘텐츠 페이지는 사용자가 페이지에서 탭을 클릭할 경우 보여지는 페이지이며, 실제로는 페이스북 페이지 내에서 iframe으로 렌더링(rendering)되기 때문에, 어떠한 HTML페이지든 상관없이 가능하다.
다만 통상적으로 이 페이지에는 페이스북의 각종 플러그인들을 얹혀 사용하는 경우가 많기 때문에 간단한 템플릿을 하나 작성해 두고 재사용하면
편리하다. 다음은 페이스북 탭 페이지용으로 사용할 수 있는 간단한 HTML 파일 템플릿이다.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1399667.js?file=fan_event.html&quot;&gt;&lt;/script&gt;

&lt;p&gt;이 템플릿 파일을 앞서 앱 등록 시에 설정했던 페이지 탭 URL과 맞추어 주면 콘텐츠 페이지가 완성된다. 
이 때 APP_ID를 앞서 등록한 페이스북 APP ID로 채우는 것을 잊지 말자.
만약 담벼락에 올리기나 댓글 처럼 추가 플러그인이 필요한 경우는 &lt;a href=&quot;https://developers.facebook.com/docs/plugins/&quot;&gt;페이스북 플러그인 페이지&lt;/a&gt;에서 코드를 가져다 붙이면 된다.&lt;/p&gt;

&lt;h2 id=&quot;3-페이지에-탭-추가하기&quot;&gt;3. 페이지에 탭 추가하기&lt;/h2&gt;

&lt;p&gt;마지막은 페이스북 페이지에 방금 제작한 탭을 추가하는 것이다. 앱 등록 페이지 좌측 하단에 있는 관련 링크 중에서 &lt;strong&gt;앱 페이지 보기&lt;/strong&gt;를 클릭하면 방금 생성한 앱의 페이지가 표시되는데, 이 앱 페이지의 좌측에 있는 &lt;strong&gt;내 페이지에 추가&lt;/strong&gt; 메뉴를 클릭하여 추가하고 싶은 페이지를 선택하면 해당 페이지에 방금 생성한 탭이 추가된 것을 확인할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7023/6417418693_b9dbf419b5_z.jpg&quot; alt=&quot;내 페이지에 추가&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updated(2011/12/13)&lt;/strong&gt; 최근 페이스북이 앱 페이지(앱 프로파일 페이지)를 &lt;a href=&quot;https://developers.facebook.com/blog/post/611/&quot;&gt;없애기로 결정&lt;/a&gt;함에 따라 이제 신규로 생성하는 앱은 
위와 같은 방식으로 페이지에 앱을 추가할 수 없게 되었다. 대신 페이스북에서는 다음과 같은 스크립트를 앱의 소스코드에 추가함으로써 “내 페이지에 추가하기” 기능을 쉽게 구현할 수 있도록 해 놓고 있다.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1470762.js?file=gistfile1.txt&quot;&gt;&lt;/script&gt;

&lt;p&gt;물론 직접 링크를 호출하는 방식으로도 가능하다. 브라우저의 URL 창에 다음 주소를 입력하면 예전과 같은 페이지에 추가하기 대화창이 나온다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://www.facebook.com/dialog/pagetab?app_id=YOUR_APP_ID&amp;amp;next=http://facebook.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;문서화되지 않은 방법&lt;/strong&gt;: 또는 다음 URL을 호출하여도 탭 추가가 가능하다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://www.facebook.com/add.php?api_key=YOUR_APP_ID&amp;amp;pages
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Updated(2012/03/16)&lt;/strong&gt; 최근 페이스북이 앱페이지(앱 커뮤니티 페이지)의 관리자 메뉴 속에 &lt;em&gt;앱을 페이지에 추가하기&lt;/em&gt; 메뉴를 추가했다. 앱페이지를 만들었다면 이 메뉴 기능을 이용해도 된다. &lt;a href=&quot;https://www.facebook.com/photo.php?fbid=407581229256851&amp;amp;set=a.365001673514807.110147.352249658123342&amp;amp;type=1&quot;&gt;자세한 내용&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;참고자료&quot;&gt;참고자료&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.facebook.com/blog/post/462/&quot;&gt;Introducing iframe Tabs for Pages&lt;/a&gt; (Facebook 개발자 블로그)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.facebook.com/docs/appsonfacebook/pagetabs/&quot;&gt;Page Tab Tutorial&lt;/a&gt; (Facebook 개발자 문서)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.facebook.com/docs/reference/dialogs/add_to_page/&quot;&gt;Add Page Tab Dialog&lt;/a&gt; (facebook 개발자 문서)&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>클라우드 기반에 Facebook App 호스팅하기</title>
   <link href="/2011/11/23/hosting-the-facebook-apps-on-cloud/"/>
   <updated>2011-11-23T00:00:00+00:00</updated>
   <id>/2011/11/23/hosting-the-facebook-apps-on-cloud</id>
   <content type="html">&lt;p&gt;최근 페이스북이 클라우드 플랫폼인 &lt;a href=&quot;https://developers.facebook.com/blog/post/558/&quot;&gt;Heroku를 자사의 애플리케이션 배포 플랫폼에 추가&lt;/a&gt;함에 따라 이제 페이스북 개발자들은 별도의 호스팅 절차 없이도 간단하게 페이스북 앱(
&lt;a href=&quot;https://developers.facebook.com/docs/guides/web/&quot;&gt;웹사이트&lt;/a&gt; 방식이든 
&lt;a href=&quot;https://developers.facebook.com/docs/guides/canvas/&quot;&gt;캔버스앱&lt;/a&gt;이든)을 개발할 수 있게 되었다.&lt;/p&gt;

&lt;p&gt;물론 굳이 이런 밀겹합(deep integration) 방식을 사용하지 않더라도 페이스북 앱을 장착할 수 있는 다양한 클라우드 기반들이 이미
많이 존재한다. 클라우드 기반에서 페이스북 앱을 호스팅할 수 있는 몇 가지 방안을 소개한다.&lt;/p&gt;

&lt;h3 id=&quot;heroku에-호스팅하기&quot;&gt;Heroku에 호스팅하기&lt;/h3&gt;

&lt;p&gt;가장 간단한 방법은 페이스북 앱 등록 페이지에서 제공하는 클라우드 서비스를 이용하는 방법이다. 이 때 클라우드 서비스를 추가하면 실제로는 클라우드 기반 앱 플랫폼인 Heroku와 연동된다. Heroku는 이전에는 루비 기반 앱만 호스팅할 수 있었지만 최근 Java, PHP, Node.js 등 다양한 개발 언어를 지원하는 ‘&lt;a href=&quot;http://blog.heroku.com/archives/2011/8/3/polyglot_platform/&quot;&gt;Polyglot Platform&lt;/a&gt;‘으로 전환하였다.&lt;/p&gt;

&lt;p&gt;Facebook 앱 등록 페이지에서 호스팅 서비스 추가를 클릭하면 다음과 같이 페이스북 앱 개발 시에 사용할 언어를 선택하는 옵션이 나오고 이 때 적절한 언어를 선택하고 나서 클릭하면 바로 디폴트 앱이 생성되는 것을 확인할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm7.staticflickr.com/6230/6386632221_cb4f3140e5.jpg&quot; alt=&quot;클라우드 서비스 추가하기&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다음과 같이 디폴트 앱이 생성되어 브라우저에 보여진다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm7.staticflickr.com/6043/6386632457_e6722f4eb3_z.jpg&quot; alt=&quot;페이스북 디폴트 앱&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이제 다시 페이스북 앱 등록 페이지로 와서 보면 페이스북 앱과 연동된 클라우드 서비스의 Hosting URL이 등록된 것을 확인할 수 있을 것이다. 물론 이 URL은 Heroku로 접속하여 변경할 수 있고, 기존에 Heroku에서 제공하는 다양한 부가서비스들도 동일하게 이용할 수 있다. 참고로 페이스북 앱 등록 페이지를 통해 설치되는 Heroku의 디폴트 앱에 대한 소스코드는 아래 github에서 확인할 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;PHP &lt;a href=&quot;https://github.com/heroku/facebook-template-php&quot;&gt;https://github.com/heroku/facebook-template-php&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Node.js &lt;a href=&quot;https://github.com/heroku/facebook-template-nodejs&quot;&gt;https://github.com/heroku/facebook-template-nodejs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Python &lt;a href=&quot;https://github.com/heroku/facebook-template-python&quot;&gt;https://github.com/heroku/facebook-template-python&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Ruby &lt;a href=&quot;https://github.com/heroku/facebook-template-ruby&quot;&gt;https://github.com/heroku/facebook-template-ruby&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;아마존-웹서비스-클라우드aws-cloud에-호스팅하기&quot;&gt;아마존 웹서비스 클라우드(AWS cloud)에 호스팅하기&lt;/h3&gt;

&lt;p&gt;아마존 웹서비스 클라우드 환경에 Facebook 앱을 호스팅하는 방법은 여러 가지 있지만 가장 간단한 방법 중 하나는 아마존 웹서비스 중 하나인 &lt;a href=&quot;http://aws.amazon.com/cloudformation/&quot;&gt;AWS CloudFormation&lt;/a&gt; 서비스를 이용하는 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://awsmedia.s3.amazonaws.com/articles/FB-apps-on-AWS-9-2011/fig1.png&quot; alt=&quot;설치 단계&quot; /&gt;&lt;/p&gt;

&lt;p&gt;다음과 같이 AWS CloudFormation 관리 콘솔에서 &lt;a href=&quot;http://s3.amazonaws.com/aws-facebook/SampleFacebookPHP.template&quot;&gt;Facebook 앱용 템플릿&lt;/a&gt;의 URL을 지정하면 바로 페이스북 앱을 생성할 수 있다. 이 때 Facebook AppId, Secret 정보와 AWS 계정 정보 등을 앱 실행에 필요한 정보들을 추가로 입력해 주어야 한다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7158/6387710847_d00f26377f_z.jpg&quot; alt=&quot;AWS Facebook 앱 템플릿 등록&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7033/6387710589_3d64302357.jpg&quot; alt=&quot;AWS 앱 등록 폼&quot; /&gt;&lt;/p&gt;

&lt;p&gt;EC2 스택이 새로 생성되고 Facebook PHP SDK 등 관련된 파일이 셋팅되는 동안 잠시 기다리면 다음과 같이 설치가 완료되고 CREATE_COMPLETE 메시지가 출력된다. 이때 생성되는 SiteURL 값을 페이스북 앱 등록 페이지에서 설정해 주면 AWS와 Facebook 간의 연동이 완료된다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm8.staticflickr.com/7144/6387729251_2bacf6544d_z.jpg&quot; alt=&quot;AWS 설치 완료&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 때 사용된 페이스북 앱의 소스코드는 다음 URL에서 확인할 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://aws-facebook.s3.amazonaws.com/aws-facebook-php-v1.tar.gz&quot;&gt;http://aws-facebook.s3.amazonaws.com/aws-facebook-php-v1.tar.gz&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;google-app-engine에-호스팅하기&quot;&gt;Google App Engine에 호스팅하기&lt;/h3&gt;

&lt;p&gt;Facebook 캔버스 앱이라고 해서 구글 앱 엔진에 앱을 호스팅하는데 달라지는 점은 전혀 없다. 통상적인 Google App Engine(GAE) 사용 절차에 따라 앱을 개발하여 배포하고 페이스북 개발자 페이지에서 앱 URL을 등록해 주면 된다. 다만 GAE가 현재 Python, Java, Go 언어만을 지원하기 때문에 PHP로 된 앱은 배포할 수 없다. 페이스북 개발자 문서에서 GAE에 Python 기반 Facebook Canvas App을 만드는 &lt;a href=&quot;https://developers.facebook.com/docs/samples/canvas/&quot;&gt;튜토리얼&lt;/a&gt;이 소개되어 있으니 자료로 참조하면 좋을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://developers.facebook.com/attachment/canvas-sample-main-app.png&quot; alt=&quot;Sample Canvas App&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;참고자료&quot;&gt;참고자료&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.heroku.com/archives/2011/9/15/facebook/&quot;&gt;Facebook and Heroku&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://devcenter.heroku.com/articles/facebook&quot;&gt;Getting Started with Your Facebook App on Heroku&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://aws.amazon.com/articles/1044&quot;&gt;Hosting Facebook Applications on Amazon EC2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.facebook.com/docs/samples/canvas/&quot;&gt;Sample Canvas App on GAE&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Play 프레임워크와 Heroku를 이용한 웹앱 개발</title>
   <link href="/2011/11/17/web-development-with-play-and-heroku/"/>
   <updated>2011-11-17T00:00:00+00:00</updated>
   <id>/2011/11/17/web-development-with-play-and-heroku</id>
   <content type="html">&lt;p&gt;최근 Java 기반 웹 프레임워크 중 하나인 Play!가 주목받고 있다. Java야 이미 오래 전부터 수많은 웹서비스와 엔터프라이즈 환경에서 검증된 웹 개발 언어로 그리고 주력 플랫폼으로 사용되고 있었기 때문에 다른 어떤 웹 개발 환경 보다도 다양하고 광범위한 기술 기반을 보유하고 있다. 이미 웹 개발과 관련한 많은 기술 표준들이 나와 있고 많은 훌륭한 웹 개발 프레임워크들이 존재하기 때문에 새로 무언가 필요할까 싶은 생각도 들지만, Play!를 접하고 나면 조금 다른 느낌이 든다. “아~ 자바로도 이런 게 가능하구나. 역시 언어 문제는 아니었군.” 하는 생각.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm7.static.flickr.com/6237/6353518869_7bda34fdca.jpg&quot; alt=&quot;Play framework&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Play!의 특징을 몇 가지만 들어 보면 다음과 같다.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;MVC 아키텍처를 채택&lt;/li&gt;
  &lt;li&gt;서블릿 컨테이너를 사용하지 않고 자체 서버로 직접 배포하는 방식을 취함 (container-less)&lt;/li&gt;
  &lt;li&gt;JBoss의 &lt;a href=&quot;http://www.jboss.org/netty&quot;&gt;Netty&lt;/a&gt; 라이브러리를 사용, 비동기 방식으로 IO를 처리하여 서버의 성능을 높임 (nonb-locking I/O)&lt;/li&gt;
  &lt;li&gt;JUnit 기반 테스팅 프레임워크를 내장&lt;/li&gt;
  &lt;li&gt;JPA 기반 ORM&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;시작하기&quot;&gt;시작하기&lt;/h3&gt;

&lt;p&gt;이 밖에 더 자세한 내용은 아래 참고자료를 참고하기로 하고, 우선 간단하게 Play!를 시작해 보기로 하자. 설치는 파일을 다운로드하여 적당한 디렉터리에서 압축을 풀어주면 완료된다. (Mac OSX에서 &lt;a href=&quot;http://mxcl.github.com/homebrew/&quot;&gt;Homebrew&lt;/a&gt;를 사용한다면 명령행에서 brew install 하면 된다).&lt;/p&gt;

&lt;pre&gt;
$ play new myplay
$ cd myplay
$ play run
&lt;/pre&gt;

&lt;p&gt;이제 브라우저에서 http://localhost:9000/ 으로 접속하면 이미 Play가 시작된 것을 확인할 수 있을 것이다.&lt;/p&gt;

&lt;h3 id=&quot;mvc-디렉터리-구조&quot;&gt;MVC 디렉터리 구조&lt;/h3&gt;

&lt;p&gt;Play framework의 디렉터리 구조는 다음과 같다. app 디렉터리 아래에 각각 model, controller, view 디렉터리가 위치하고 conf에는 애플리케이션 설정 및 routes 설정 등 각종 설정파일이, lib에는 외부 jar 파일이 담기고, public은 자바스크립트나 스타일시트, 이미지 같은 정적인 파일들이 담기는 공간이다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://farm7.static.flickr.com/6057/6353625503_8110c05881.jpg&quot; alt=&quot;directory structure of Play frx&quot; /&gt;&lt;/p&gt;

&lt;p&gt;이 때, 예를 들어, app/models 디렉터리 속에 담긴 User.java는 다음과 같은 형태의 코드로 구성된다. 이 클래스는 User모델로서 데이터베이스의 User 테이블과 OR 맵핑된다. (참고로 개발환경에서 이 소스코드의 컴파일은 동적으로 처리되며 tmp/ 디렉터리 아래에 자동으로 생성된다는 점이 특이하다).&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
package models;
 
import java.util.*;
import javax.persistence.*;
 
import play.db.jpa.*;
 
@Entity
public class User extends Model {
 
    public String email;
    public String password;
    public String fullname;
    public boolean isAdmin;
    
    public User(String email, String password, String fullname) {
        this.email = email;
        this.password = password;
        this.fullname = fullname;
    }
 
}
&lt;/pre&gt;

&lt;h3 id=&quot;배포하기&quot;&gt;배포하기&lt;/h3&gt;

&lt;p&gt;애플리케이션이 만들어 졌다면 배포해야 한다. Amazon EC2 기반의 앱 클라우드 플랫폼인 &lt;a href=&quot;http://blog.heroku.com/archives/2011/8/29/play/&quot;&gt;Heroku가 최근 Play framework을 지원&lt;/a&gt;하기 때문에 Heroku를 이용하면 간단히 배포할 수 있다. 소스 버전 관리는 git으로 한다는 가정 하에, 명령행에서 다음 명령으로 배포가 완료된다.&lt;/p&gt;

&lt;pre&gt;
$ heroku create --stack ceder
$ git push heroku master
$ heroku open
&lt;/pre&gt;

&lt;h3 id=&quot;참고자료&quot;&gt;참고자료&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.playframework.org/&quot;&gt;Play Framework&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.playframework.org/documentation/1.2.3/5things&quot;&gt;Five cool things you can do with Play&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://devcenter.heroku.com/articles/play&quot;&gt;Getting Started with Play! on Heroku/Cedar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>루비 기반 오픈소스 CMS 솔루션들</title>
   <link href="/2011/10/31/ruby-based-opensource-cms-solutions/"/>
   <updated>2011-10-31T00:00:00+00:00</updated>
   <id>/2011/10/31/ruby-based-opensource-cms-solutions</id>
   <content type="html">&lt;p&gt;요즘 웹사이트나 블로그 만드는 일은 더 이상 별로 어려운 작업이 아니다. 불과 몇 년 전만 하더라도 
조금 근사한 수준의 사이트를 만들 경우 비싼 비용을 지불하고 또 전문 업체에 의뢰하는 경우가 많았지만 
최근에는 굳이 그럴 필요가 많이 없어졌다. 이제 누구든 손쉽고 빠르게 자신의 웹사이트나 블로그를 만들고 지우고
할 수 있는 세상이 된 것이다.&lt;/p&gt;

&lt;p&gt;이렇게 된 데에는 여러 이유가 있겠지만 그 중 쉽게 콘텐츠를 만들어 웹 상에 올릴 수 있게 도와주는 좋은 콘텐츠 관리 도구(Content 
Management System) 들이 많이 출시된 것도 직접적인 원인 중 하나일 것이다.&lt;/p&gt;

&lt;p&gt;소스가 공개된 콘텐츠 관리 도구 중 대표적인 것으로는 &lt;a href=&quot;http://wordpress.org/&quot;&gt;WordPress&lt;/a&gt;, 
&lt;a href=&quot;http://drupal.org/&quot;&gt;Drupal&lt;/a&gt;,  &lt;a href=&quot;http://www.xpressengine.com/&quot;&gt;XE&lt;/a&gt;, 
&lt;a href=&quot;http://www.joomla.org/&quot;&gt;Zoomla&lt;/a&gt; 등이 있겠지만, 이들 도구/솔루션에 대해서는 이미 많은 곳에서
자세히 소개하고 있기에 여기서는 루비 기반의 오픈소스 CMS 도구를 몇 가지 소개해 본다.&lt;/p&gt;

&lt;h3 id=&quot;radiant&quot;&gt;Radiant&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://radiantcms.org/&quot;&gt;Radiant CMS&lt;/a&gt;는 루비 기반 CMS 중에서는 비교적 오랜 축에 속한다. 
간단한 관리자 화면을 통해 페이지와 레이아웃을 관리할 수 있기 때문에 간단한 웹페이지나 사이트를 만드는데 좋다.
루비온레일스 프레임워크 기반으로 확장(extention) 시스템을 제공한다. 현재 버전은 0.9.0로 MIT 라이선스를 따른다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://radiantcms.org/images/screenshot.jpg&quot; alt=&quot;Radiant&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;refinerycms&quot;&gt;RefineryCMS&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://refinerycms.com/&quot;&gt;Refinery CMS&lt;/a&gt; 역시 루비온레일스 프레임워크 기반에서 작동하며
주로 루비온레일스 기반 애플리케이션에 CMS 기능을 추가하는 용도로 사용하기 쉽게 설계되었다. 
콘텐츠는 WYSIWYG 에디터를 통해 쉽게 편집할 수 있게 되어 있으며 간단한 관리자 UI를 제공한다.
“Engine” 이라는 이름의 확장 플러그인 기반에서는 제법 많은 확장 모듈들을 제공하고 있다.
현재 버전은 1.0.8이며 MIT 라이선스를 따른다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://refinerycms.com/images/refinery-screenshot.png?1290654959&quot; alt=&quot;Refinery&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;locomotive&quot;&gt;Locomotive&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://locomotivecms.com/&quot;&gt;Locomotive&lt;/a&gt; 역시 루비온레일스 기반의 오픈소스 CMS 솔루션이다.
Locomotive는 하나의 CMS 속에 여러 개의 사이트를 호스팅할 수 있고 
설계부터 Heroku나 Amazon S3를 호스팅 플랫폼으로 상정하고 개발되었기 때문에 클라우드 기반 CMS 호스팅이
필요한 경우에도 사용할 수 있을 것이다. 확장 모듈을 제공하며 MIT 라이선스를 따른다.&lt;/p&gt;

&lt;h3 id=&quot;browsercms&quot;&gt;BrowserCMS&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://www.browsercms.org/&quot;&gt;BrowserCMS&lt;/a&gt;는 단순히 CMS라기 보다는 루비온레일스 프레임워크의 CMS 확장이라고
보는 것이 좋겠다. 이 솔루션은 루비온레일스 기반에 엔터프라이즈 급의 CMS 기능들을 추가해 주기 때문에
루비온레일스 애플리케이션을 강력한 CMS 도구로 만들어 준다. 현재 버전은 3.3.2이며 GPLv3 라이선스를 따른다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.browsercms.org/image1.jpg&quot; alt=&quot;BrowserCMS&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;기타&quot;&gt;기타&lt;/h3&gt;

&lt;p&gt;그 밖에도 많은 &lt;a href=&quot;https://www.ruby-toolbox.com/categories/content_management_systems&quot;&gt;루비 기반 CMS 솔루션들&lt;/a&gt;이 나와 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://nestacms.com/&quot;&gt;Nesta&lt;/a&gt;는 정말이지 가벼운 CMS인데 다른 CMS 솔루션들처럼 데이터베이스를 저장소로 사용하지 않고
git 저장소를 CMS 저장소로 사용하는 Sinatra 기반의 앱이다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; 역시 데이터베이스가 아닌 git 저장소 기반의 CMS 솔루션이며, 특히 Jekyll은 
&lt;a href=&quot;http://pages.github.com/&quot;&gt;github page&lt;/a&gt;에서 사용할 수 있으며, 
이 경우 &lt;a href=&quot;http://github.com&quot;&gt;github&lt;/a&gt;를 간단하게 자신의 웹사이트 또는 블로그로 만들 수 있다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>WordPress에서 Sass/Compass 사용하기</title>
   <link href="/2011/07/28/using-sass-and-compass-in-wordpress/"/>
   <updated>2011-07-28T00:00:00+00:00</updated>
   <id>/2011/07/28/using-sass-and-compass-in-wordpress</id>
   <content type="html">&lt;p&gt;이전에도 한번 &lt;a title=&quot;CSS 개발의 생산성을 높이는 도구들&quot; href=&quot;http://usefulparadigm.com/2011/03/18/productive-css-development-tools/&quot;&gt;소개&lt;/a&gt;한 것처럼 &lt;a href=&quot;http://sass-lang.com/&quot;&gt;Sass&lt;/a&gt;와 &lt;a href=&quot;http://compass-style.org/&quot;&gt;Compass&lt;/a&gt;는 CSS 개발의 생산성을 높여주는 유용한 도구들이다. 부연하자면, Sass는 &lt;a href=&quot;http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#variables_&quot;&gt;변수(variable)&lt;/a&gt;, &lt;a href=&quot;http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#mixins&quot;&gt;믹스인(mixins)&lt;/a&gt; 같은 개념들을 통해 CSS를 모듈화시켜 코드의 재활용성을 높여주는 반면, Compass는 이런 Sass의 강력한 기능들을 플러그인 형태의 확장 구조로 다시 한번 추상화 시킴으로써 HTML5/CSS3 같은 복잡한 최신 CSS 개발 환경에서도 쉽고 일관되게 CSS 개발을 가능하게 도와주는 강력한 개발 도구(authoring framework) 인 셈이다.&lt;/p&gt;

&lt;a title=&quot;View 'compass-css-framework' on Flickr.com&quot; href=&quot;http://www.flickr.com/photos/60489948@N04/5983951868&quot;&gt;&lt;img class=&quot;alignright&quot; style=&quot;margin: 10px;&quot; title=&quot;compass-css-framework&quot; src=&quot;http://farm7.static.flickr.com/6021/5983951868_144fa6837d_m.jpg&quot; border=&quot;0&quot; alt=&quot;compass-css-framework&quot; width=&quot;240&quot; height=&quot;150&quot; /&gt;&lt;/a&gt;


&lt;p&gt;Sass와 Compass는 주로 루비/레일스 커뮤니티에서 공유되고 사용되는 것으로 알려져 있지만 반드시 루비 환경에서만 동작하는 건 아니다. 실은 특정 개발 환경에 중립적이기 때문에 오히려 루비가 아닌 다른 환경에서도 그 진가를 발휘하는 좋은 CSS 개발 도구라  할 것이다. 예컨대 WordPress 의 테마(theme)를 개발할 때도 이 Sass/Compass 콤비네이션을 활용할 수 있다. 여기서 간단히 그 방법을 소개한다.&lt;/p&gt;

&lt;h3&gt;기본 전제&lt;/h3&gt;
&lt;ol&gt;
	&lt;li&gt;Sass/Compass는 이미 설치되었다고 가정한다. (설치에 관해서는 여기를 참조)&lt;/li&gt;
	&lt;li&gt;작업할 워드프레스 테마 디렉터리가 이미 만들어져 있다고 가정한다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;단계별 절차&lt;/h3&gt;
&lt;p&gt;워드프레스 테마의 루트 디렉터리에서 다음과 같은 compass 명령으로 설정파일을 하나 생성한다.&lt;/p&gt;
&lt;blockquote&gt;$ compass config --css-dir=.&lt;/blockquote&gt;

&lt;p&gt;디폴트로 이 파일은 config/compass.rb 로 생성되는데, 이 파일을 열어 보면 다음과 같이 기본적인 설정이 선언되어 있다. (물론 설정값은 프로젝트에 맞게 조정할 수 있다)&lt;/p&gt;

&lt;pre&gt;
http_path = &quot;/&quot;
css_dir = &quot;.&quot;
sass_dir = &quot;sass&quot;
images_dir = &quot;images&quot;
javascripts_dir = &quot;javascripts&quot;
&lt;/pre&gt;

&lt;p&gt;이제 위의 설정에 맞게 테마 프로젝트의 디렉터리 경로들을 조정했다면 sass 디렉터리를 하나 주가하고, 그 속에 sass파일을 하나 만들자. 여기서는 style.scss 라고 하였고, 그 속에 다음과 같이 간단하게 몇 줄의 코드를 추가해 보았다. (참고로 여기 코드는 어디까지나 샘플이며, 실제 프로젝트에서는 조금 더 모듈화가 필요할 것이다. 자세한 내용은 &lt;a href=&quot;http://compass-style.org/help/tutorials/best_practices/&quot;&gt;Comass BestPractice 문서&lt;/a&gt;를 참조)&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
@import &quot;compass&quot;;

#box {
  text-align: justify;
  background-color: #dedede;
  @include border-radius();
}
&lt;/pre&gt;

&lt;p&gt;위의 코드를 간단하게 설명하자면, 우선 1행에서 &lt;a href=&quot;http://compass-style.org/reference/compass/&quot;&gt;compass 모듈&lt;/a&gt;을 로드한다. 이 모듈은 compass의 기본 모듈인데, 그 속에는 CSS3 처리나 타이포그래피(typography), 기타 각종 유틸리티 모듈들이 포함되어 있기 때문에 프로젝트에서는 별도의 CSS 코딩 없이 바로 이 모듈에서 미리 만들어 제공하고 있는 CSS 코드들을 활용할 수 있는 것이다. 예를 들어, 위의 sass 파일에서는 6행에서 ID가 #box인 DOM 문서 객체에 대해 border-radius() 라는 믹스인을 적용하고 있다. 이 단 한 줄의 코드 삽입만으로 모든 CSS3 지원 브라우저에서 호환되는 둥근모서리 스타일링이 간단하게 처리된다.&lt;/p&gt;

&lt;p&gt;방금 전까지 작성한 파일은 CSS 가 아닌 sass/scss 파일이었다. 그렇다면 이제 이 파일을 브라우저가 인식할 수 있는 CSS로 컴파일하는 일만 남았다. compass에서 제공하는 다음 명령을 띄워 놓으면 sass 파일의 변경을 자동으로 감지하여 css 파일로 컴파일시켜준다.&lt;/p&gt;

&lt;blockquote&gt;$ compass watch&lt;/blockquote&gt;

&lt;p&gt;이제 브라우저에서 확인해 보면 방금전 우리가 만든 style.scss 파일이 컴파일 되어 자동으로 style.css 파일이 생성된 것을 확인할 수 있을 것이다. 나머지 작업들은 통상적인 워드프레스 테마 개발 과정을 따르면 된다.&lt;/p&gt;

&lt;h3&gt;참고자료&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://wynnnetherland.com/blog/sass-up-your-wordpress-themes-with-compass&quot;&gt;compass-wordpress 라는 루비 젬을 이용하는 방법에 대한 소개 자료&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://adamstacoviak.com/posts/using-rake-rsync-for-wordpress-deployment/&quot;&gt;rake + rsync 를 이용한 테마 프로젝트의 배포&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>WordPress와 페이스북 OpenGraph 연동하기</title>
   <link href="/2011/07/22/integrating-wordpress-with-opengraph/"/>
   <updated>2011-07-22T00:00:00+00:00</updated>
   <id>/2011/07/22/integrating-wordpress-with-opengraph</id>
   <content type="html">&lt;p&gt;&lt;img class=&quot;left&quot; style=&quot;margin: 10px;&quot; title=&quot;facebook-wordpress&quot; src=&quot;/img/uploads/2011/07/99-150x150.jpg&quot; alt=&quot;&quot; width=&quot;100&quot; height=&quot;100&quot; /&gt;페이스북 &lt;a href=&quot;https://developers.facebook.com/docs/opengraph/&quot;&gt;OpenGraph 프로토콜&lt;/a&gt;은 웹 상의 콘텐츠를 페이스북 속 소셜 그래프(social graph)와 연결할 때 사용하는 일종의 메타 데이터(meta data)라고 할 수 있다. 이 프로토콜을 사용하게 되면 웹 상의 어떤 콘텐츠에 대한 메타 정보들, 예를 들면 제목이라든지 URL, 또는 썸네일 이미지나 설명 같은 것들을 그대로 페이스북으로 전달할 수가 있는데, 실제 이런 정보의 전달은 사용자가 웹 페이지에 있는 &quot;&quot;좋아요(Like)&quot; 버튼을 클릭할 때 일어나게 된다. 이 때 페이스북은 전달받은 URL의 페이지를 읽어서 OpenGraph 프로토콜에 맞는 메타데이터 정보가 있는지를 검사하게 되고, 있을 경우 이들 정보를 사용자의 프로파일(담벼락)  등에서 표시할 때 사용하게 된다(그림1).&lt;/p&gt;

&lt;p&gt;뿐만 아니라 이렇게 OpenGraph를 통해 연결된 웹사이트의 콘텐츠가 업데이트될 경우 그 업데이트 정보가 해당 콘텐츠를 좋아요(Like)한 사용자에게 곧바로 알려지기 때문에 마치 실시간으로 PUSH를 보내는 것과 같은 기능을 만들어 낼 수도 있다. OpenGraph 프로토콜에 대한 자세한 내용은 페이스북 개발자 문서를 참고하길 바라며, 이 글에서는 이런 페이스북 OpenGraph 프로토콜을 오픈소스 CMS툴인 워드프레스(WordPress)에서 사용하는 방법만 간단히 소개한다.&lt;/p&gt;

&lt;img class=&quot;alignnone&quot; title=&quot;OpenGraph Protocol&quot; src=&quot;https://developers.facebook.com/images/devsite/open-graph.png&quot; alt=&quot;&quot; width=&quot;587&quot; height=&quot;157&quot; /&gt;
[그림1] OpenGraph 프로토콜 소개

&lt;p&gt;워드프레스에서 OpenGraph 프로토콜을 사용하는 것은 다른 통상적인 웹사이트에서 OpenGraph를 사용하는 것과 전혀 다를 것이 없다. 통상적으로 어떤 웹사이트에 OpenGraph 프로토콜을 적용하려면 다음과 같은 절차를 거치게 된다.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;웹페이지의 &amp;lt;head&amp;gt; 영역에 페이스북 OpenGraph에서 필요로 하는 일련의 메타 태그를 삽입한다. 이 때 각각의 페이지마다 달라지는 정보들(예: 제목, URL, 썸네일, 설명 등)은 그에 맞게 동적으로 처리해 준다.&lt;/li&gt;
	&lt;li&gt;페이스북에서 제공하는 Like 버튼과 같은 플러그인을 웹페이지에 추가한다.&lt;/li&gt;
	&lt;li&gt;페이스북 개발자 페이지에 들어가서 웹사이트를 등록하고 app_id를 받아서 앞서 OpenGraph 메타 태그에 적어 준다.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이렇게 해서 만들어진 통상적인 OpenGraph 태그의 구조는 아래와 같다. (자세한 설명은 &lt;a href=&quot;https://developers.facebook.com/docs/reference/plugins/like/&quot;&gt;페이스북 문서&lt;/a&gt; 참조)&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/1099227.js?file=gistfile1.html&quot;&gt;&lt;/script&gt;

&lt;p&gt;워드프레스라서 달라지는 점이 있다면 이 메타 태그들을 워드프레스의 템플릿 페이지(통상적으로는 header.php) 에 삽입한다는 정도일 것이다.&lt;/p&gt;

&lt;h4&gt;참고자료&lt;/h4&gt;

&lt;ul&gt;
	&lt;li&gt;OpenGraph 프로토콜을 적용한 후에는 페이스북에서 제공하는 &lt;a href=&quot;http://developers.facebook.com/tools/lint/&quot;&gt;URL Lint 도구&lt;/a&gt;를 이용하여 페이지에 OpenGraph 프로토콜이 제대로 설정되었는지 확인하는 것이 좋다.&lt;/li&gt;
	&lt;li&gt;Like 버튼 플러그인을 직접 적용하지 않고 &lt;a href=&quot;http://developers.facebook.com/tools/lint/&quot;&gt;AddThis&lt;/a&gt; 같은 소셜 버튼 위젯과 함께 사용해도 무방하다.&lt;/li&gt;
	&lt;li&gt;워드프레스 플러그인 중에는 페이스북 OpenGraph 데이터를 직접 내장시켜 주는 여러 종류의 플러그인들이 이미 나와 있다. 이들 중 하나를 사용하면 위의 작업을 직접하는 수고를 덜 수 있어 편리하다. 그 중 &lt;a href=&quot;http://wordpress.org/extend/plugins/ogp/&quot;&gt;Open Graph Pro&lt;/a&gt;를 추천함.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>기업용으로 활용가능한 오픈소스 SNS 솔루션들</title>
   <link href="/2011/06/21/oss-social-networking-solutions-for-enterprise/"/>
   <updated>2011-06-21T00:00:00+00:00</updated>
   <id>/2011/06/21/oss-social-networking-solutions-for-enterprise</id>
   <content type="html">&lt;p&gt;
&lt;img src=&quot;/img/uploads/2011/06/social-network.jpg&quot; class=&quot;right&quot; /&gt;

트위터나 페이스북 같은 소셜 네트워킹 서비스의 인기와 효용성에 힘입어 기업에서도 이런 솔루션들을 도입하여 조직 내부에서 수평적이고 자유로운 커뮤니케이션 문화를 조성하고 보다 격의없고 창의성 있는 생각과 아이디어를 조직원들 간에 서로 공유하려는 움직임들이 생겨나고 있다. 해외에서는 이미 오래 전에 yammer 같은 기업용 SNS 서비스들이 출시되어 인기를 끌었고, 국내에서도 몇몇 업체들이 기업용 SNS 솔루션을 만들어 제공 중이다. 또한 작년부터 주로 대기업을 중심으로 하여 사내 SNS 서비스를 구축한 사례들이 등장하고 올해에는 공공기관에서도 이런 사내 SNS망을 구축하여 사용하는 움직임이 보인다. 기업 또는 조직 내에서 소셜 네트워킹을 구축하여 사내의 새로운 문화로 정착시키려는 움직임은 향후에도 계속 확산될 것으로 보인다.&lt;/p&gt;

&lt;p&gt;기업용 SNS를 위해 가장 많이 사용하는 서비스는 아마도 &lt;a href=&quot;https://www.yammer.com/&quot;&gt;야머(yammer)&lt;/a&gt;일 것이다. 알다시피 yammer는 이메일 주소를 식별코드로 사용하여 같은 이메일 도메인을 사용하는 사람들만의 네트워크를 형성해 주고 그 속에서 소셜 네트워킹을 할 수 있게 만들어주는 서비스이다. 국내에서도 이미 많은 기업과 공공기관에서 도입해서 사용 중인 서비스이기도 하다.&lt;/p&gt;

&lt;img class=&quot;left&quot; style=&quot;margin: 10px;&quot; title=&quot;yammericon.jpg&quot; src=&quot;/img/uploads/2011/06/yammericon1.jpg&quot; border=&quot;0&quot; alt=&quot;Yammericon&quot; width=&quot;126&quot; height=&quot;126&quot; /&gt;

&lt;p&gt;그런데 이런 &quot;호스팅 방식&quot;의 서비스에서는 종종 보안과 관련된 우려가 제기되곤 한다. 물론 yammer 같은 서비스는 이런 사용자들의 우려를 감안하여 보안에 많은 신경을 쓰고 있지만, 그래도 &quot;DMZ&quot; 안에서 돌아가는 것과 밖에서 돌아가는 것 간에는 최소한 사용자들이 인식하는 심리적인 안정감에서라도 차이가 날 수 있다. 그래서 이런 호스팅 방식의 서비스를 쓰는 기관들도 종종 보안을 위해 별도의 솔루션을 가져가기도 한다.&lt;/p&gt;

&lt;p&gt;여기서 소개할 솔루션들은 이런 경우에 사용할 수 있는 오픈소스 SNS 솔루션들이다. 이미 검색엔진으로 검색해보면 헤아릴 수도 없을 만큼 많은 솔루션들이 시장에 출시되어 있고, 또 그 중에서 오픈소스 형태로 제공되는 솔루션들도 많은 것이 사실이다. 너무 많아 오히려 선택하기가 어려울 지경이라고 해야 할 것이다. 물론 &quot;SNS&quot; 라고 하는 것이 별로 &quot;만들기 어려운&quot; 솔루션도 아닌데다 사내 인트라넷 등 타 시스템과의 연동도 필요한 부분이 있고 또 조직 문화의 문제도 있는 탓에 직접 구축해서 사용하는 경우도 많겠지만, 지금 소개할 몇 가지 솔루션들도 기업용 SNS를 구축할 경우에 검토해 볼만 할 것이라 생각한다.&lt;/p&gt;

&lt;h3&gt;1. StatusNet&lt;/h3&gt;

&lt;p&gt;첫번째로 소개할 솔루션은 &lt;a href=&quot;http://status.net/&quot;&gt;StatusNet&lt;/a&gt;이다. 이미 &lt;a href=&quot;http://identi.ca/&quot;&gt;identi.ca&lt;/a&gt; 라는 서비스에서 실전 서비스를 하고 있고, 스마트폰과 데스크탑용 앱도 가지고 있는 이 SNS 솔루션은 &lt;a href=&quot;http://ostatus.org/&quot;&gt;oStatus&lt;/a&gt;라는 표준 스펙을 따르는 분산형 SNS(Federated SNS)이기도 하다. 트위터와 유사하 마이크로 블로깅(microblogging)을 기본으로 하지만 그룹을 생성할 수도 있고 메신저와의 연동도 가능한 장점이 있다. 분산형 SNS이기 때문에 여러 SNS 간에 서로 연결될 수도 있는 것도 장점이라 하겠다. PHP/MySQL 기반이며 현재 버전은 0.9.7로 곧 1.0 버전이 나올 예정인 이 솔루션은 &lt;a href=&quot;http://www.gnu.org/licenses/agpl.html&quot;&gt;AGPL&lt;/a&gt; 라이선스를 따른다.&lt;/p&gt;

&lt;img title=&quot;statusnet.png&quot; src=&quot;/img/uploads/2011/06/statusnet2.png&quot; border=&quot;0&quot; alt=&quot;Statusnet&quot; width=&quot;600&quot; height=&quot;187&quot; /&gt;

&lt;h3&gt;2. Diaspora&lt;/h3&gt;

&lt;p&gt;다음으로 소개할 솔루션은 &lt;a href=&quot;https://joindiaspora.com/&quot;&gt;디아스포라(diaspora)&lt;/a&gt;라고 하는 SNS 솔루션이다. StatusNet과 마찬가지로 역시 분산형 SNS를 표방하는 이 솔루션은 얼마 전 페이스북의 창업자 마크 쥬커버그로부터 지원금을 받아 화제가 되기도 했던 솔루션인데, 작년 가을에 알파버전을 오픈하면서 서비스를 개시했다. 특히 이 솔루션은 애스팩(aspect) 이라는 그룹 기능을 두어 그룹 간에서만 서로 커뮤니케이션을 하는 방법을 지원하기 때문에 사내에서도 어느 정도의 프라이버시 수준을 유지할 수 있는 장점이 있다. Ruby on Rails 기반이며, &lt;a href=&quot;http://www.gnu.org/licenses/agpl.html&quot;&gt;AGPL&lt;/a&gt; 라이선스를 따른다.&lt;/p&gt;

&lt;img title=&quot;diaspora.png&quot; src=&quot;/img/uploads/2011/06/diaspora.png&quot; border=&quot;0&quot; alt=&quot;Diaspora&quot; width=&quot;600&quot; height=&quot;164&quot; /&gt;

&lt;h3&gt;3. 기타&lt;/h3&gt;

&lt;p&gt;기존의 인트라넷이나 사이트를 가지고 있는 조직에서 소셜 기능을 추가하고 싶다면 &lt;a href=&quot;http://www.elgg.org/index.php&quot;&gt;elgg&lt;/a&gt; 같은 SNS 엔진(engine)을 검토해 보는 것도 좋겠다. 페이스북 같은 플랫폼이 만들어진다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://buddypress.org/&quot;&gt;버디프레스(BuddyPress)&lt;/a&gt;는 오픈소스 블로깅 솔루션인 워드프레스(WordPress)에 호감이 있는 조직이라면 관심을 가져볼만한 솔루션이다. 이 솔루션은 WordPress의 플러그인 형태로 제공되는 솔루션으로 워드프레스의 강력한 확장성을 잘 보여주는 솔루션이라 할 것이다.&lt;/p&gt;

&lt;p&gt;마지막으로, Ruby on Rails 기반 솔루션을 두어 가지 소개하고 끝을 맺기로 한다. StatusNet과 같은 oStatus 프로토콜을 사용하면서도 RoR로 된 솔루션을 찾는다면 &lt;a href=&quot;http://rstat.us/&quot;&gt;rStat.us&lt;/a&gt; 가 답이 될 수도 있다. 정확하게 SNS 만을 겨냥한 것은 아니지만, 작은 조직이나 팀 단위에서 프로젝트 관리도 하고 마이크로블로깅 기반 커뮤니케이션도 함께 할 수 있는 솔루션을 찾는다면 &lt;a href=&quot;http://teambox.com/&quot;&gt;팀박스(Teambox)&lt;/a&gt;도 고려해 볼만 한다.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>CSS 개발의 생산성을 높이는 도구들</title>
   <link href="/2011/03/18/productive-css-development-tools/"/>
   <updated>2011-03-18T00:00:00+00:00</updated>
   <id>/2011/03/18/productive-css-development-tools</id>
   <content type="html">&lt;p&gt;&lt;img class=&quot;attachment right&quot; src=&quot;http://farm6.static.flickr.com/5219/5535334248_eacd7eede0_m.jpg&quot; alt=&quot;&quot; width=&quot;240&quot; height=&quot;120&quot; /&gt;CSS는 웹사이트 디자인에 사용하는 도구다. 개념도 복잡하지 않고 문법도 간단하기 때문에 Box 모델이나 플로팅(floating) 같은 몇 가지 기본 개념만 익히고 나면 약간의 코딩 만으로 웹사이트에 멋진 비주얼 요소를 집어넣을 수가 있다. 그렇지만 매번 웹사이트를 만들 때마다 일일이 처음부터 CSS 작업을 하는 일은 경우에 따라서는 제법 성가시고 품이 많이 가는 일이기도 하다. 특히 IE의 비정상적인 작동을 바로잡기 위한 핵(Hack) 까지 고려한다면 더욱 그렇다. CSS 개발의 생산성을 높여주는 몇 가지 도구들에 대해 알아보자.&lt;/p&gt;

&lt;h3&gt;1. CSS 프레임워크&lt;/h3&gt;
&lt;p&gt;CSS 프레임워크(framework)는 미리 만들어 놓은 일종의 CSS 모듈이다. CSS 프레임워크를 사용하면 페이지의 기본 레이아웃에서부터 타이포그라피, 폼 디자인, 버튼 등 많은 부분의 디자인을 &quot;날로 먹을 수&quot;가 있다. 물론 모든 &quot;프레임워크&quot;가 그러하듯, CSS 프레임워크도 언제나 &quot;최선&quot;의 선택인 것은 아니며, 어떤 디자이너나 개발자들은 CSS 프레임워크 자체에 거부감을 가지기도 한다. 그렇지만 CSS 프레임워크가 개발 생산성을 높여줄 수 있다는 점에서는 이론의 여지가 없다. 그만큼 그 종류도 다양하기 때문에 오히려 어떤 것을 선택하느냐가 더 고민이 되는 경우가 많지만, 몇 가지 대표적인 것들만 소개하면 다음과 같다.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;http://960.gs/&quot; href=&quot;http://960.gs/&quot;&gt;960 Grid System&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;http://www.blueprintcss.org/&quot; href=&quot;http://www.blueprintcss.org/&quot;&gt;Blueprint&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;http://elasticss.com/&quot; href=&quot;http://elasticss.com/&quot;&gt;Elastic CSS Framework&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;http://developer.yahoo.com/yui/grids/&quot; href=&quot;http://developer.yahoo.com/yui/grids/&quot;&gt;YUI Grid CSS&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;http://lessframework.com/&quot; href=&quot;http://lessframework.com/&quot;&gt;Less Framework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이들 중 대부분의 CSS 프레임워크는 소위 &quot;그리드(grid) 디자인&quot;에 기반하지만, 자바스크립트와 함께 사용하여 UI 효과를 내는 것들도 있고, 또 최근에는 HTML5/CSS3를 이용한 CSS 프레임워크들이 많이 등장하고 있다.&lt;/p&gt;

&lt;h3&gt;2. SASS와 LESS&lt;/h3&gt;
&lt;p&gt;SASS와 LESS는 일종의 CSS 전처리기(pre-processor)다. 조금 더 간단하고 구조화된 문법으로 코드를 작성하면 자동으로 CSS 파일을 생성해 주기 때문에 CSS 개발의 생산성을 폰이는 데에 꼭 필요한 도구이기도 하다. 특히 믹스인(Mixin)이라는 개념은 일종의 '모듈'을 만드는 것으로서, CSS 코드 재활용을 높이고 생산성을 높여주는 좋은 개념이다. SASS는 루비(ruby) 언어로 작성되었고, 그래서 주로 루비/레일스 프로젝트에서 많이 사용되지만 반드시 그래야 하는 건 아니다.&lt;/p&gt;

&lt;p&gt;LESS(앞서 소개한 Less Framework과는 별개)도 SASS와 개념은 유사하지만, CSS파일의 생성이 자바스크립트 파서(parser)를 통해 클라이언트 측에서 이루어진다는 점에서, 서버측에서 컴파일이 이루어지는 SASS와 구별된다. 물론 LESS는 Node.js 환경에서도 작동한다. 이들 도구의 홈페이지는 각각 다음과 같다.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;SASS &lt;a href=&quot;http://sass-lang.com/&quot;&gt;http://sass-lang.com/&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;LESS &lt;a href=&quot;http://lesscss.org/&quot;&gt;http://lesscss.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;3. Compass&lt;/h3&gt;

&lt;p&gt;마지막으로 소개할 도구는 일종의 CSS 개발 자동화 도구인 Compass다. 이 도구를 이용하면 앞서 소개한 CSS Framework를 명령행에서 바로 설치할 수도 있고, SASS 컴파일을 자동화 시킬 수도 있으며, 무엇보다도 SASS와 결합하여 CSS의 구성요소를 모듈단위로 쪼개서 SASS 모듈의 재활용성을 높이는 역할을 하는, 일종의 메타(meta) CSS 프레임워크라 할 수 있다. Compass의 사용법은 &lt;a class=&quot;external&quot; title=&quot;http://compass-style.org/&quot; href=&quot;http://compass-style.org/&quot;&gt;Compass 사이트&lt;/a&gt;에 자세히 소개되어 있으니 참조하면 된다.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>루비/레일스 인증처리 라이브러리</title>
   <link href="/2011/03/15/ruby-rails-authentication-libraries/"/>
   <updated>2011-03-15T00:00:00+00:00</updated>
   <id>/2011/03/15/ruby-rails-authentication-libraries</id>
   <content type="html">&lt;p&gt;
&lt;img class=&quot;right&quot; title=&quot;authentication&quot; src=&quot;http://farm6.static.flickr.com/5219/5528988262_da728c673d_m.jpg&quot; alt=&quot;&quot; width=&quot;240&quot; height=&quot;159&quot; /&gt;사용자 인증(Authentication)은 한마디로 사용자 본인이 맞는지를 확인하는 절차다. 웹의 경우, 상태를 유지하지 않는 HTTP 프토토콜의 특성에 기인하여 다양한 인증방식이 존재하지만, 우리가 통상적으로 사용하는 방식은 ID와 비밀번호를 입력하도록 하는 로그인 폼을 보이고 그 폼에 사용자 자신의 신원 정보를 채우도록 해서 인증을 처리하게 된다. 얼핏 간단해 보이는 처리이지만, 사실 웹 개발을 할 때에 이 인증만큼 다양한 '변종'이 존재하는 영역도 드물 것이다. 루비/레일스로 개발을 하는 경우도 마찬가지다. 한 가지 표준 라이브러리가 있어 &quot;이것만 있으면 끝!&quot; 해 버리면 좋겠지만 현실은 그렇지가 못하다. 아래에서 루비/레일스를 이용한 웹 개발에 있어 대표적으로 사용할 수 있는 몇 가지 인증 라이브러리를 소개한다.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;https://github.com/technoweenie/restful-authentication&quot; href=&quot;https://github.com/technoweenie/restful-authentication&quot;&gt;restful-authentication&lt;/a&gt; 원래 authentication-fu 라는 이름으로 있다가, 레일스가 REST 기반으로 변경되면서 restful-authentication으로 업그레이드되었다. 가장 단순하면서도 커스터마이징에 너그러운 라이브러리로, 지금도 많이 쓰이고 있다.&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;https://github.com/thoughtbot/clearance&quot; href=&quot;https://github.com/thoughtbot/clearance&quot;&gt;clearance&lt;/a&gt; 재미있는 작품들을 많이 내기로 유명한 thoughtbot의 작품으로, 이메일과 비밀번호 인증만 필요한 경우라면 이보다 더 쉬울 순 없다.&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;https://github.com/binarylogic/authlogic&quot; href=&quot;https://github.com/binarylogic/authlogic&quot;&gt;authlogic&lt;/a&gt; 인증을 모델(model) 객체 수준으로 끌어올린 멋진 라이브러리이다. 다양한 설정 옵션을 지원하면서도 사용하기가 어렵지 않다.&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;https://github.com/plataformatec/devise&quot; href=&quot;https://github.com/plataformatec/devise&quot;&gt;devise&lt;/a&gt; 요즘 가장 &quot;인기있는&quot; 인증 라이브러리로 사용하기 쉽고 플러그인을 통한 확장이 용이하다. rack 기반 인증모듈인 warden에 기반한다.&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;https://github.com/intridea/omniauth&quot; href=&quot;https://github.com/intridea/omniauth&quot;&gt;omniauth&lt;/a&gt; intridea 에서 만든 이 작품은 영역이 조금 다르다. 통상적인 인증이 아닌 OpenID나 Twitter/Facebook 같은 소위 '서드파티3rd party' 인증을 처리한다.&lt;/li&gt;
	&lt;li&gt;&lt;a class=&quot;external&quot; title=&quot;https://github.com/NoamB/sorcery&quot; href=&quot;https://github.com/NoamB/sorcery&quot;&gt;socery&lt;/a&gt; 마지막으로 소개할 라이브러리는 신예다. 이전 라이브러리들의 장점을 모두 합했다고 하며 oauth 인증까지 지원한다. 아직 버전이 낮지만 완성도는 높다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;대부분의 오픈소스 영역이 그렇지만, 특히 루비/레일스가 재미있는 부분은 이렇게 서로 영감과 아이디어를 주고 받으면서 계속해서 새로운 제품들이 등장하고 또 등장하고 한다는 점이다. 내년 이 맘때는 또 어떤 라이브러리들이 어떤 아이디어를 갖고 나올지 기대되는 이유다.&lt;/p&gt;

&lt;h3&gt;참고자료:&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://ruby-toolbox.com/categories/rails_authentication.html&quot;&gt;http://ruby-toolbox.com/categories/rails_authentication.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>페이스북 소셜 앱 개발 가이드 자료</title>
   <link href="/2011/03/10/facebook-app-guide-2011-share/"/>
   <updated>2011-03-10T00:00:00+00:00</updated>
   <id>/2011/03/10/facebook-app-guide-2011-share</id>
   <content type="html">&lt;!-- &lt;div class=&quot;alert-message block-message info&quot;&gt;
	페이스북 앱 제작 의뢰 및 오픈 그래프 적용 관련 문의는 우측 하단 contact으로 해 주세요!
&lt;/div&gt;	 --&gt;

&lt;p&gt;2011.2.18 &lt;a href=&quot;http://www.bizdeli.com/socialAPP/index.asp&quot;&gt;소셜 앱 개발 성공 전략 컨퍼런스 2011&lt;/a&gt;에서 발표한 &quot;&lt;strong&gt;페이스북에서의 소셜 앱 개발 가이드&lt;/strong&gt;&quot; 발표자료를 공유합니다.&lt;/p&gt;

&lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/qhPngNKg751JLr&quot; width=&quot;595&quot; height=&quot;485&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;&quot; allowfullscreen&gt; &lt;/iframe&gt; &lt;div style=&quot;margin-bottom:5px&quot;&gt; &lt;strong&gt; &lt;a href=&quot;//www.slideshare.net/usefulparadigm/010218&quot; title=&quot;페이스북 소셜 앱 개발 가이드 2011&quot; target=&quot;_blank&quot;&gt;페이스북 소셜 앱 개발 가이드 2011&lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a target=&quot;_blank&quot; href=&quot;//www.slideshare.net/usefulparadigm&quot;&gt;Sukjoon Kim&lt;/a&gt;&lt;/strong&gt; &lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>OAuth 인증으로 다음 요즘 API 액세스하기</title>
   <link href="/2011/03/09/accessing-yozm-api-using-oauth/"/>
   <updated>2011-03-09T00:00:00+00:00</updated>
   <id>/2011/03/09/accessing-yozm-api-using-oauth</id>
   <content type="html">&lt;img class=&quot;right&quot; title=&quot;361332bf.jpg&quot; src=&quot;http://hueniverse.com/wp-content/uploads/2009/09/OAuth-Shine-300x298.png&quot; alt=&quot;361332bf.jpg&quot; width=&quot;150&quot; height=&quot;149&quot; /&gt;
&lt;p&gt;최근 들어 국내에서도 오픈 API 접근 시에 인증 표준인 OAuth를 적용하는 서비스들이 하나 둘 생겨나고 있다. &lt;a class=&quot;external&quot; title=&quot;http://oauth.net/&quot; href=&quot;http://oauth.net/&quot;&gt;OAuth&lt;/a&gt;는 이미 Facebook이나 Twitter, Google, Yahoo 같은 글로벌 인터넷 서비스에서는 제법 오래 전부터 적용되어 오고 있었지만, 국내에서 OAuth 서비스 제공자를 찾기는 쉽지 않았는데, 이제 다음이나 네이트 같은 대형 포털 사이트에서 OAuth를 적용하기 시작한 것은 반가운 일이 아닐 수 없다.  다음(Daum)에서 제공하는 OAuth 서비스에 대해 간단히 알아보고 이를 이용하여 다음의 SNS 서비스인 &lt;a class=&quot;external&quot; title=&quot;http://yozm.daum.net/&quot; href=&quot;http://yozm.daum.net/&quot;&gt;요즘(yozm&lt;/a&gt;) API에 접근해 보자.&lt;/p&gt;

&lt;p&gt;Daum은 OAuth 1.0을 지원하며 아래 URL로 접근 가능하다.&lt;/p&gt;

&lt;dl&gt;
	&lt;dt&gt;Request 토큰 URL&lt;/dt&gt;
	&lt;dd&gt;&lt;a href=&quot;https://apis.daum.net/oauth/requestToken&quot;&gt;https://apis.daum.net/oauth/requestToken&lt;/a&gt;&lt;/dd&gt;
	&lt;dd&gt;request 토큰 요청시 oauth_callback 값이 컨슈머의&lt;strong&gt;Callback 경로&lt;/strong&gt;와 동일해야 합니다.&lt;/span&gt;&lt;/dd&gt;
	&lt;dt&gt;사용자 인증 URL&lt;/dt&gt;
	&lt;dd&gt;&lt;a href=&quot;https://apis.daum.net/oauth/authorize&quot;&gt;https://apis.daum.net/oauth/authorize&lt;/a&gt;&lt;/dd&gt;
	&lt;dt&gt;Access 토큰 URL&lt;/dt&gt;
	&lt;dd&gt;&lt;a href=&quot;https://apis.daum.net/oauth/accessToken&quot;&gt;https://apis.daum.net/oauth/accessToken&lt;/a&gt;&lt;/dd&gt;
	&lt;dt&gt;서명 메소드는 HMAC-SHA1만 지원됩니다.&lt;/span&gt;&lt;/dt&gt;
&lt;/dl&gt;

&lt;h3&gt;OAuth dance&lt;/h3&gt;

&lt;p&gt;OAuth 인증 절차는 흔히 &quot;OAuth dance&quot;라고 부르는, 아래 그림과 같은 3단계의 인증 절차를 거친다.&lt;/p&gt;

&lt;img class=&quot;attachment&quot; title=&quot;OAuth.JPG&quot; src=&quot;https://dddz3g.bay.livefilestore.com/y1pXkudtRCpXWKlL9RBS9m3Zb7M7A2TAmkJku4Nv8_cRYuzpH0JHhV4Ani8oJaM3bmayMrhsiLexbKVlY-5kVKckIXlHhfubs5p/oauth-dance.jpg?psid=1&quot; alt=&quot;OAuth.JPG&quot; width=&quot;259&quot; height=&quot;194&quot; /&gt;
&lt;p&gt;* 출처: 다음 튜토리얼 자료&lt;/p&gt;

&lt;h3&gt;Yozm API 액세스하기&lt;/h3&gt;

&lt;p&gt;OAuth 인증을 거쳐 액세스 토큰(access token)을 획득했다면 이제 오픈 API에 접근할 수 있다. 예를 들어, 인증을 &quot;수락&quot;한 본인의 요즘(yozm) 개인 정보를 얻어오려면 다음 URL로 REST 호출하면 된다.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://apis.daum.net/yozm/v1_0/user/show.xml&quot;&gt;http://apis.daum.net/yozm/v1_0/user/show.xml&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;참고자료:&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;OAuth 소개 &lt;a href=&quot;http://oauth.net/documentation/getting-started/&quot;&gt;http://oauth.net/documentation/getting-started/&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;다음 OAuth 서비스 &lt;a href=&quot;https://apis.daum.net/oauth/main/welcome&quot;&gt;https://apis.daum.net/oauth/main/welcome&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;yozm 사용자 정보보기 &lt;a href=&quot;http://dna.daum.net/apis/yozm/ShowUser&quot;&gt;http://dna.daum.net/apis/yozm/ShowUser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>워드프레스 테마 커스터마이징:  두 가지 방법</title>
   <link href="/2011/03/08/customizing-wordpress-theme/"/>
   <updated>2011-03-08T00:00:00+00:00</updated>
   <id>/2011/03/08/customizing-wordpress-theme</id>
   <content type="html">&lt;img class=&quot;right&quot; title=&quot;download.blog&quot; src=&quot;/img/uploads/2011/03/download.blog_-300x267.png&quot; alt=&quot;&quot; width=&quot;180&quot; height=&quot;160&quot; /&gt;

&lt;p&gt;&lt;a href=&quot;http://wordpress.org/&quot;&gt;WordPress&lt;/a&gt;는 이미 블로깅(blogging) 도구라는 이미지에서 벗어나 멋진 CMS 플랫폼으로 자리매김한지 오래다. 그리고 이렇게 WordPress가 멋진 플랫폼으로 발전하게 된 데는 뭐니뭐니해도 유연한 확장성을 갖춘 테마(theme) 시스템이 큰 견인차 역할을 해 왔다. WordPress에서 테마를 변경하는데는 크게 두 가지 방법이 있다.&lt;/p&gt;

&lt;h3&gt;첫 번째 방법: 테마 템플릿 수정하기&lt;/h3&gt;

&lt;p&gt;첫 번째 방법은 테마 템플릿 파일 자체를 수정하는 것이다. 여기에는 기존의 다른 테마를 가져다가 수정하거나 아니면 아예 처음부터 새로 테마 시스템을 개발하는 것을 포함한다. WordPress의 테마 작성법에 대해서는 너무 많은 사용법과 문서들이 나와 있기 때문에 여기서는 따로 다루지 않기로 한다.&lt;/p&gt;

&lt;h3&gt;두 번째 방법: 테마 상속하기&lt;/h3&gt;

&lt;p&gt;워드프레스 2.7 버전부터 새로 도입된 이 방식은 말 그대로 어떤 테마를 상속하는 방법이다. 예를 들어, A라는 테마가 있다고 하면 이 테마를 그대로 사용하고 그 중 커스터마이징이 필요한 부분만 부분 수정하는 방식으로 테마를 변경하는 것이다. 이럴 경우 두 개의 테마 간에는 일종의 부모-자식 관계가 성립하며, 따라서 원래의 테마를 부모 테마(mother theme)라 부르고, 부모 테마로부터 상속받은 테마를 자식 테마(chile theme)라고 부른다.&lt;/p&gt;

&lt;p&gt;자식 테마를 만드는 방법은 간단하다. 새로운 테마 디렉터리를 하나 생성한 다음 sytle.css 파일의 주석에 Theme 값으로 부모 테마 디렉터리의 이름을 지정해 주면 끝이다. 예를 들면 다음과 같다.&lt;/p&gt;
&lt;pre&gt;/*
Theme Name:     Twenty Ten Child
Theme URI:      http: //example.com/
Description:    Child theme for the Twenty Ten theme
Author:         Your name here
Author URI:     http: //example.com/about/
Template:       twentyten
Version:        0.1.0
*/
&lt;/pre&gt;

&lt;p&gt;이제 이 테마는 고맙게도 부모 테마(여기서는 twentyten)의 모든 것을 물러 받는다. 그 다음 부터는 맘에 들지 않는 부분만 고치면 그만이다. 예를 들면, CSS 스타일의 일정 부분만 고칠 수도 있고, 부모 템플릿 파일 중 필요한 부분만 변경할 수도 있다.&lt;/p&gt;

&lt;p&gt;둘 중 어느 방법을 사용하느냐는 물론 상황에 따라 다르다. 경우에 따라서는 아예 새로 테마를 작성하는 첫 번째 방식이 더 효과적일 때도 있다. 그렇지만, 메인 테마를 그대로 두고 필요한 부분만 개선하는 두 번째 방법은, 메인 테마를 계속 유지하면서 자식 테마만 조금씩 변경하면서 운영할 때 아주 효과적인 방법이다.&lt;/p&gt;

&lt;h3&gt;참고자료:&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/Child_Themes&quot;&gt;http://codex.wordpress.org/Child_Themes&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;메인 테마로 사용하기 좋은 Theme Framework
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://themeshaper.com/thematic/&quot;&gt;Thematic, A WordPress Theme Framework&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://notesblog.com/&quot;&gt;Notes Blog Core Theme&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>톡팟tokpot 서비스 베타 오픈</title>
   <link href="/2010/11/09/tokpot-beta-open-notice/"/>
   <updated>2010-11-09T00:00:00+00:00</updated>
   <id>/2010/11/09/tokpot-beta-open-notice</id>
   <content type="html">&lt;p&gt;유스풀패러다임의 새 웹서비스인 톡팟tokpot 을 오픈하였습니다.&lt;/p&gt;

&lt;p&gt;톡팟tokpot은 트위터twitter 기반 게시판 위젯widget 서비스입니다. 톡팟을 이용하면 여러분 사이트나 블로그에 간단하게 트위터 기반 게시판을 붙여 넣을 수 있습니다.&lt;/p&gt;

&lt;a href=&quot;http://tokpot.com&quot;&gt;&lt;img class=&quot;aligncenter size-full wp-image-60&quot; title=&quot;tokpot&quot; src=&quot;/img/uploads/2010/11/tokpot.jpg&quot; alt=&quot;&quot; width=&quot;500&quot; height=&quot;491&quot; /&gt;&lt;/a&gt;

&lt;p&gt;톡팟은 특히 이런 분들께 유용합니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;나만의 브랜드를 가진 홈페이지나 블로그를 운영하면서 방문객들이 트위터로 이동하지 않고 내 사이트 내에서 소통을 이어가고자 할 때.&lt;/li&gt;
&lt;li&gt;사업체 또는 공공단체, 학교 등 홈페이지 속에서 트위터로 대화를 주고 받고자 할 때.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;아직 베타 버전이라 부족한 부분이 있지만, 사용자들의 피드백을 받아 꾸준히 업데이트해 나갈 계획입니다.&lt;/p&gt;

&lt;p&gt;많은 관심과 격려 부탁 드립니다.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>레일스3 환경에서 레일스2 애플리케이션 생성하기</title>
   <link href="/2010/09/25/generate-rails2-app-in-rails3/"/>
   <updated>2010-09-25T00:00:00+00:00</updated>
   <id>/2010/09/25/generate-rails2-app-in-rails3</id>
   <content type="html">&lt;img class=&quot;right&quot; title=&quot;from-rails2&quot; src=&quot;/img/uploads/2010/09/download3-0.png&quot; alt=&quot;&quot; width=&quot;144&quot; height=&quot;153&quot; /&gt;

&lt;p&gt;최근 레일스가 버전 3으로 업그레이드되면서 프레임워크 안팎으로 &lt;a href=&quot;http://edgeguides.rubyonrails.org/3_0_release_notes.html&quot;&gt;기존의 버전 업그레이드와는 차원이 다른 많은 변화&lt;/a&gt;가 생겼다. 레일스가 Merb와 합병한다는 소식을 공개한 것이 지난 2008년 말. 그 후로 약 2년간 거의 4,000회의 커밋과 250여 명의 커미터가 함께 한 ‘리팩터링 대장정’. 그래서인지 &lt;a href=&quot;http://accidentaltechnologist.com/ruby-on-rails/to-rails-3-or-not-to-rails-3-that-is-the-question/&quot;&gt;혹자&lt;/a&gt;는 이를 두고 마치 예전 마이크로소프트가 ASP에서 ASP.NET으로 갈아 탔을 때의 느낌을 연상하기도 하지만, 결과야 좀 더 두고 볼 일.&lt;/p&gt;

&lt;p&gt;업그레이드에 따른 가장 큰 이슈는 물론 기존의 레일스 애플리케이션을 새 버전으로 업그레이드시키는  것이겠지만, 경우에 따라서는 이미 레일스3을 설치하고서 갑자기 이전 버전의 레일스 애플리케이션을 생성해야 할 경우도 생긴다.  문제는 레일스3에서는 애플리케이션 생성 명령이 변경되어 기존의 rails 명령이 그대로 작동하지 않는 것.&lt;/p&gt;

&lt;p&gt;두 가지 방법이 있다.&lt;/p&gt;

&lt;h3 id=&quot;_1__rvm__&quot;&gt;방법 1 - RVM을 이용하는 방법&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://rvm.beginrescueend.com/&quot;&gt;RVM&lt;/a&gt;을 사용 중이라면 간단하게 루비 VM을 전환하여 레일스 환경을 변경할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 루비 1.9.2에서 레일스 3 사용하기
$ rvm install 1.9.2
$ rvm 1.9.2
$ rails new app-name

# 다시 이전 버전(레일스 2)으로 돌리기
$ rvm system
$ rails app-name&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;_2__bundler__&quot;&gt;방법 2 - Bundler를 이용하는 방법&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://gembundler.com/&quot;&gt;Bundler&lt;/a&gt;를 이용하면 굳이 RVM을 사용하지 않고도 간단하게 이전 버전의 레일스 애플리케이션을 생성할 수 있다.&lt;/p&gt;

&lt;p&gt;1) 새 프로젝트 디렉터리를 만든다.&lt;/p&gt;

&lt;p&gt;2) Gemfile을 만들고 다음과 같이 생성할 레일스 버전을 준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem &quot;rails&quot;, &quot;2.3.8&quot;
gem &quot;sqlite3-ruby&quot;, :require =&amp;gt; &quot;sqlite3&quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;3)  다음 bundle 명령을 차례로 수행.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ bundle install
$ bundle exec rails .&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>페이스북 앱 개발 가이드</title>
   <link href="/2010/07/20/facebook-app-tutorial/"/>
   <updated>2010-07-20T00:00:00+00:00</updated>
   <id>/2010/07/20/facebook-app-tutorial</id>
   <content type="html">&lt;p&gt;&lt;img class=&quot;right&quot; title=&quot;logo-f8-150x123&quot; src=&quot;/img/uploads/2010/07/logo-f8-150x123.gif&quot; alt=&quot;&quot; width=&quot;150&quot; height=&quot;123&quot; /&gt;&lt;/a&gt;Facebook과 연동한 웹 개발 방식은 크게 두 종류로 나눌 수 있다. 하나는 기존의 웹 사이트와 페이스북을 연동하는  Facebook Connect 방식의 웹 개발이고, 다른 하나는 페이스북 페이지 내에 사이트를 내장시키는 Facebook  Canvas App 방식이다. Facebook Canvas App은 다시 내장 방식으로 IFrame을 사용하냐 혹은 페이스북에서  제공하는 FBML을 사용하냐에 따라 IFrame Canvas와 FBML Canvas로 나눌 수도 있다.&lt;/p&gt;

&lt;p&gt;Facebook은 잘 정리된 개발문서와 개발자 지원 페이지를 제공하고 있고, 또한 위에서 소개한 각각의  개발 방식에 맞춰 여러 종류의 개발 언어로 작성된 SDK를 제공하기 때문에 어떤 개발환경을 사용하든 손쉽게 페이북과 연동되는 웹  애플리케이션/서비스를 개발할 수 있다.&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://developers.facebook.com/&quot;&gt;Facebook 개발자 페이지&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://developers.facebook.com/docs/&quot;&gt;Facebook 개발 문서&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Facebook SDKs: &lt;a href=&quot;http://developers.facebook.com/docs/reference/javascript/&quot;&gt;JavaScript&lt;/a&gt;, &lt;a href=&quot;http://github.com/facebook/php-sdk/&quot;&gt;PHP&lt;/a&gt;, &lt;a href=&quot;http://github.com/facebook/python-sdk/&quot;&gt;Python&lt;/a&gt;, &lt;a href=&quot;http://github.com/facebook/facebook-iphone-sdk/&quot;&gt;iPhone&lt;/a&gt;, &lt;a href=&quot;http://github.com/facebook/facebook-android-sdk&quot;&gt;Android&lt;/a&gt;, &lt;a href=&quot;http://github.com/facebook/csharp-sdk&quot;&gt;C#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;open_graph_api_oauth&quot;&gt;Open Graph API와 OAuth&lt;/h3&gt;
&lt;p&gt;최근 페이스북은 기존의 &lt;a href=&quot;http://developers.facebook.com/docs/reference/rest/&quot;&gt;REST 방식의 API&lt;/a&gt;를 버리고 &lt;a href=&quot;http://opengraphprotocol.org/&quot;&gt;Open Graph&lt;/a&gt;라는 오픈 프로토콜에 기반한 API로 서비스 접근 방식을 변경하였다. 또한 서비스 인증(authentication &amp;amp; authorization)도 오픈 표준인 &lt;a href=&quot;http://wiki.oauth.net/OAuth-2&quot;&gt;OAuth2&lt;/a&gt;를 채용함으로써 이전보다 훨씬 표준적인 개발 방식으로 접근할 수 있는 길을 열어 놓고 있다.&lt;/p&gt;

&lt;p&gt;특히 Facebook JavaScript SDK와 FBML의 클라이언트 확장인 XFBML을 이용하게  되면 기존의 Facebook Connect 이나 IFrame Canvas 방식의 Facebook App의 성능도 향상시킬 수 있게  되었다.&lt;/p&gt;

&lt;h3 id=&quot;facebook_app__&quot;&gt;Facebook App 개발 절차&lt;/h3&gt;
&lt;p&gt;Facebook App의 개발 절차를 간략히 정리하면 아래 단계와 같다. 자세한 내용은 페이스북 개발문서를 참조.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Facebook 개발자 페이지에서 &lt;a href=&quot;http://www.facebook.com/developers/createapp.php&quot;&gt;새 App을 추가&lt;/a&gt;한다.&lt;/li&gt;
	&lt;li&gt;Facebook JavaScript SDK를 페이지에 추가한다.&lt;/li&gt;
	&lt;li&gt;OAuth access_token으로 Graph API를 액세스한다.&lt;/li&gt;
	&lt;li&gt;FBML/XFBML, FQL을 적절히 이용한다.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;_facebook_app&quot;&gt;루비/레일스와 Facebook App&lt;/h3&gt;
&lt;p&gt;아쉽게도 아직 페이스북에서 루비/레일스 개발자들을 위한 공식 SDK는 제공하지 않는다. 그렇지만 이미 루비 커뮤니티에서는 페이스북 개발을 지원하는 많은 라이브러리와 도구들이 나와 있다. 대표적인 것은 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://github.com/mmangino/facebooker&quot;&gt;Facebooker&lt;/a&gt;: Rails 플러그인. 가장 오래되고 사용자 기반이 넓지만 Old REST 방식이며 다소 무겁다는 단점이 있다.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://github.com/mmangino/facebooker2&quot;&gt;Facebooker2&lt;/a&gt;: 기존 Facebooker를 새 API에 맞게 리모델링한 것으로, Graph API 라이브러리인 &lt;a href=&quot;http://github.com/mmangino/mogli&quot;&gt;mogli&lt;/a&gt;를 기반으로 한다.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://github.com/tmm1/sinbook&quot;&gt;sinbook&lt;/a&gt;: Sinatra 확장 라이브러리. 300줄 정도의 적은 코드로 되어 있으며, Old REST API 방식.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://github.com/arsduo/koala&quot;&gt;Koala&lt;/a&gt;: 새 API 기반이며 Connect과 App 개발 모드 모두를 지원한다. 주목할만한 신예 라이브러리.&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 
</feed>