Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Wrote fetch.py Backed up my blog.

  • Loading branch information...
commit be76468e76aa642a39c66b83867b0a8d18980d79 0 parents
@dahlia authored
Showing with 1,287 additions and 0 deletions.
  1. +1 −0  1052452651-30-minutes-lisp-in-ruby.json
  2. +15 −0 1052452651-30-minutes-lisp-in-ruby.md
  3. +1 −0  1087307773-2.json
  4. +3 −0  1087307773-2.md
  5. +1 −0  1095555825-irc.json
  6. +8 −0 1095555825-irc.md
  7. +1 −0  1148154394-mac-os-x-tokyo-python.json
  8. +12 −0 1148154394-mac-os-x-tokyo-python.md
  9. +1 −0  1242851060.json
  10. +5 −0 1242851060.md
  11. +1 −0  1268041887-unicode.json
  12. +17 −0 1268041887-unicode.md
  13. +1 −0  1285533566-mixin.json
  14. +8 −0 1285533566-mixin.md
  15. +1 −0  1295597685-fexpr.json
  16. +8 −0 1295597685-fexpr.md
  17. +1 −0  1356936681-langdev-irc.json
  18. +3 −0  1356936681-langdev-irc.md
  19. +1 −0  1364722885.json
  20. +9 −0 1364722885.md
  21. +1 −0  1379411418-facebook.json
  22. +3 −0  1379411418-facebook.md
  23. +1 −0  1382431580-python-datetime-datetime.json
  24. +17 −0 1382431580-python-datetime-datetime.md
  25. +1 −0  1575259937.json
  26. +45 −0 1575259937.md
  27. +1 −0  1653101302-toby-lee.json
  28. +41 −0 1653101302-toby-lee.md
  29. +1 −0  1728906260.json
  30. +7 −0 1728906260.md
  31. +1 −0  2128778779-fexpr.json
  32. +82 −0 2128778779-fexpr.md
  33. +1 −0  2337329381-6-0.json
  34. +14 −0 2337329381-6-0.md
  35. +1 −0  2399277655-last-fm.json
  36. +36 −0 2399277655-last-fm.md
  37. +1 −0  2431357247-irclog.json
  38. +15 −0 2431357247-irclog.md
  39. +1 −0  2492201571-python-getter-setter.json
  40. +37 −0 2492201571-python-getter-setter.md
  41. +1 −0  2703234440-subversion-mercurial-1.json
  42. +55 −0 2703234440-subversion-mercurial-1.md
  43. +1 −0  2906351242-python-perl.json
  44. +42 −0 2906351242-python-perl.md
  45. +1 −0  2920519622.json
  46. +38 −0 2920519622.md
  47. BIN  2920519622.png
  48. +1 −0  2968635983-java-collections-framework.json
  49. +9 −0 2968635983-java-collections-framework.md
  50. +1 −0  379524623.json
  51. +27 −0 379524623.md
  52. +1 −0  381793093-vlaah-api.json
  53. +27 −0 381793093-vlaah-api.md
  54. BIN  381959867-1.jpg
  55. +1 −0  381959867-1.json
  56. +16 −0 381959867-1.md
  57. +1 −0  412167974-the-heungsub-vlaah-embed.json
  58. +16 −0 412167974-the-heungsub-vlaah-embed.md
  59. +1 −0  417606841.json
  60. +15 −0 417606841.md
  61. +1 −0  429521447-arachneng-on-everything.json
  62. +3 −0  429521447-arachneng-on-everything.md
  63. +1 −0  432774871-pastedown-the-pastebin-service-for-markdown-documents.json
  64. +23 −0 432774871-pastedown-the-pastebin-service-for-markdown-documents.md
  65. +1 −0  433917521-universal-namespace.json
  66. +33 −0 433917521-universal-namespace.md
  67. BIN  436379667-pengdo-jiyul.jpg
  68. +1 −0  436379667-pengdo-jiyul.json
  69. +8 −0 436379667-pengdo-jiyul.md
  70. +1 −0  449446558-vlaah-9.json
  71. +3 −0  449446558-vlaah-9.md
  72. BIN  449446558-vlaah-9.png
  73. BIN  464608892.jpg
  74. +1 −0  464608892.json
  75. +1 −0  464608892.md
  76. +1 −0  469328703-vlaah-api-part-1-api.json
  77. +1 −0  469328703-vlaah-api-part-1-api.md
  78. +1 −0  473660929-vlaah.json
  79. +8 −0 473660929-vlaah.md
  80. +1 −0  481322492.json
  81. +1 −0  481322492.md
  82. +1 −0  488743743-mockcache.json
  83. +31 −0 488743743-mockcache.md
  84. +1 −0  505107383-php.json
  85. +23 −0 505107383-php.md
  86. +1 −0  505875176-1-internet-explorer-6.json
  87. +10 −0 505875176-1-internet-explorer-6.md
  88. +1 −0  514838935-vlaah.json
  89. +5 −0 514838935-vlaah.md
  90. BIN  514838935-vlaah.png
  91. +1 −0  532183323-iphone.json
  92. +17 −0 532183323-iphone.md
  93. +1 −0  537084437-io-part-1.json
  94. +5 −0 537084437-io-part-1.md
  95. +1 −0  537294542-ui.json
  96. +1 −0  537294542-ui.md
  97. +1 −0  567481297-imac.json
  98. +13 −0 567481297-imac.md
  99. +1 −0  575152478-rocket-dive.json
  100. +32 −0 575152478-rocket-dive.md
  101. +1 −0  613490344-sqlalchemy-werkzeug.json
  102. +72 −0 613490344-sqlalchemy-werkzeug.md
  103. +1 −0  623034732.json
  104. +5 −0 623034732.md
  105. +1 −0  692534002-bitbucket-v-github.json
  106. +18 −0 692534002-bitbucket-v-github.md
  107. +1 −0  713985464-deprecated-v-obsolete.json
  108. +3 −0  713985464-deprecated-v-obsolete.md
  109. +1 −0  730070594.json
  110. +9 −0 730070594.md
  111. +1 −0  745079289.json
  112. +8 −0 745079289.md
  113. +1 −0  752419604-ipv6.json
  114. +15 −0 752419604-ipv6.md
  115. +1 −0  756689263-dahlia-kr-url-3.json
  116. +5 −0 756689263-dahlia-kr-url-3.md
  117. +1 −0  784275981-java-java-java.json
  118. +7 −0 784275981-java-java-java.md
  119. +1 −0  796511696-unfortunately-more-and-more-people-use-scripting.json
  120. +3 −0  796511696-unfortunately-more-and-more-people-use-scripting.md
  121. +1 −0  810525751-irc.json
  122. +53 −0 810525751-irc.md
  123. +1 −0  841264469-fontface-kr.json
  124. +11 −0 841264469-fontface-kr.md
  125. +1 −0  857328074-distribute-pip.json
  126. +27 −0 857328074-distribute-pip.md
  127. +1 −0  891307068-nintendo-dsl.json
  128. +7 −0 891307068-nintendo-dsl.md
  129. +1 −0  905808670.json
  130. +6 −0 905808670.md
  131. +1 −0  966449437-pypi.json
  132. +17 −0 966449437-pypi.md
  133. +1 −0  998870071-dahlia-kr.json
  134. +8 −0 998870071-dahlia-kr.md
  135. +101 −0 fetch.py
1  1052452651-30-minutes-lisp-in-ruby.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-09-02 09:01:00 GMT", "url": "http://blog.dahlia.kr/post/1052452651", "url-with-slug": "http://blog.dahlia.kr/post/1052452651", "format": "markdown", "-slug": "-30-minutes-lisp-in-ruby", "id": "1052452651", "link-url": "http://gist.github.com/562017", "link-text": "30 minutes Lisp in Ruby", "unix-timestamp": "1283418060", "date": "Thu, 02 Sep 2010 18:01:00", "title": "30 minutes Lisp in Ruby", "type": "link", "slug": "30-minutes-lisp-in-ruby", "reblog-key": "Dg5ksGk2"}
15 1052452651-30-minutes-lisp-in-ruby.md
@@ -0,0 +1,15 @@
+소프트웨어 마에스트로 과정의 멘토단 중 하나로 선출되고 난 뒤, 요즘에는 Lisp 구현 프로젝트를 멘토링하고 있다. 멘티들이 Lisp을 구현하는데 내가 도와주는 식이다. 그런데 다들 Lisp 구현을 해보기는 커녕 Lisp을 써본 적도 없는 친구들이 대부분이라 난항을 겪고 있는데, 그래서 내가 멘티들을 모아다 같이 앉아서 약 30분 가량 해설을 하면서 처음부터 끝까지 Lisp을 구현해 보았다.
+
+그날은 이미 파서는 다들 구현했고, 파싱된 리스트를 평가(`eval`)하고 적용(`apply`)하는 부분을 설명해야 했기 때문에, 별도로 s-expression 파서를 구현하지는 않았다. 대신 Ruby의 문법을 사용해서 `eval`을 구현했다. 그래서 팩토리얼 함수를 구현하면 다음과 같은 모양의 코드가 된다.
+
+ [:def, :factorial,
+ [:lambda, [:n],
+ [:if, [:"=", :n, 1],
+ 1,
+ [:*, :n, [:factorial, [:-, :n, 1]]]]]]
+
+링크한 소스 코드는 그날 작성된 것은 아니고, 내가 집에 와서 같이 지내는 야간개발팀 친구들에게 비슷한 설명을 한 번 더 하면서 작성한 것을 토대로 정리를 많이 한 것이다.
+
+덧. reddit에도 올렸다. <http://www.reddit.com/r/ruby/comments/d8ldl/30_minutes_lisp_in_ruby/> Hacker News에도 올렸다. <http://news.ycombinator.com/item?id=1655673>
+
+<script src="http://gist.github.com/562017.js"> </script>
1  1087307773-2.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-09-08 17:43:00 GMT", "url": "http://blog.dahlia.kr/post/1087307773", "url-with-slug": "http://blog.dahlia.kr/post/1087307773", "format": "markdown", "-slug": "-2", "id": "1087307773", "unix-timestamp": "1283967780", "date": "Thu, 09 Sep 2010 02:43:00", "type": "regular", "slug": "2", "reblog-key": "IR7Jkt2i"}
3  1087307773-2.md
@@ -0,0 +1,3 @@
+최근 2년 정도는 살면서 심심할 틈이 없다. 일을 벌려놓기 좋아하는 성격이라 항상 해야할 일들이 머릿속을 꽉 채우고 있는데다, 해야할 일 이상으로 놀거리들이 현대에는 너무나 많기 때문이다. 그래도 가끔 심심한 기분이 들 때는 지하철 안이나 버스 안처럼 무얼 하고 싶어도 할 수 없는 상황인데, 그것조차 요즘에는 스마트폰 덕분에 심심할 일이 없어졌다.
+
+심심해서 뭘하고 시간을 때울까 고민하며 빈둥대는 시간이 많은 것은 분명 좋지 않지만, 심심할 틈이 없는 것도 한편으로는 놓치는 게 많다는 생각이 든다. 특히 책을 잘 안 읽게 된다. 그래서 웬만하면 스마트폰은 가방에 넣고 다니려고 하는데, 정신차리면 항상 손에 들고있으니 참 문제다. 없으면 또 이제 불편해서 못 살텐데.
1  1095555825-irc.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-09-10 04:37:48 GMT", "url": "http://blog.dahlia.kr/post/1095555825", "url-with-slug": "http://blog.dahlia.kr/post/1095555825", "format": "markdown", "regular-title": "\uc57c\uac04\uac1c\ubc1c\ud300 IRC \ucc44\ub110", "-slug": "-irc", "id": "1095555825", "unix-timestamp": "1284093468", "date": "Fri, 10 Sep 2010 13:37:48", "title": "\uc57c\uac04\uac1c\ubc1c\ud300 IRC \ucc44\ub110", "type": "regular", "slug": "irc", "reblog-key": "g8Z51tbD"}
8 1095555825-irc.md
@@ -0,0 +1,8 @@
+예전에 썼던 [IRC에 대한 글][1]에서도 언급했지만, 야간개발팀[^1]은 팀의 커뮤니케이션을 위해 IRC를 적극적으로 사용해왔다. 다만 닫힌 채널이었는데, 오늘부터 채널을 아예 열어재꼈다. 개발이나 스타트업, 웹 서비스 등 IT 전반에 대해서 잡담도 하고 가끔은 야간개발팀의 의사결정도 이뤄지는 채널이다. 아마 개발 단계의 서비스도 자주 마주칠 것이다. 관심있는 분들은 모두 놀러오시길! (야간개발팀이 의사결정을 하는데 훈수를 해주시라!)
+
+[오징어 IRC 네트워크][2]에 있는 [#lunant](irc://irc.ozinger.org/lunant) 채널이다.
+
+ [^1]: 정식 이름은 **Lunant**인데 **야간개발팀**이라는 이름으로 너무 많이 알려져 있어서 저 별명을 버릴 수가 없다. 야간개발팀이라고 하면 아는 사람도 Lunant라고 하면 모르는 경우가 좀 있으니까.
+
+ [1]: http://blog.dahlia.kr/post/810525751
+ [2]: http://ozinger.org/
1  1148154394-mac-os-x-tokyo-python.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-09-19 06:11:28 GMT", "url": "http://blog.dahlia.kr/post/1148154394", "url-with-slug": "http://blog.dahlia.kr/post/1148154394", "format": "markdown", "regular-title": "Mac OS X\uc5d0\uc11c tokyo-python \ube4c\ub4dc", "-slug": "-mac-os-x-tokyo-python", "id": "1148154394", "unix-timestamp": "1284876688", "date": "Sun, 19 Sep 2010 15:11:28", "title": "Mac OS X\uc5d0\uc11c tokyo-python \ube4c\ub4dc", "type": "regular", "slug": "mac-os-x-tokyo-python", "reblog-key": "VFKQC6cE"}
12 1148154394-mac-os-x-tokyo-python.md
@@ -0,0 +1,12 @@
+[tokyo-python][]은 Tokyo Cabinet의 Python 바인딩이다. 상당히 Python 스타일로 잘 인터페이싱되어 있어서 즐겨 사용하는 편이다.
+
+이걸 Mac OS X에서 설치하려고 했더니 librt가 없다며 다음과 같은 오류가 난다.
+
+ ld: library not found for -lrt
+
+Mac OS X에는 librt가 없다. 어떻게 해결할까 고민하며 검색해봤더니 이미 tokyo-python 이슈트래커에 [해당 문제][1]가 올라와 있었다. librt 빼도 빌드 잘 되고 잘 동작한다고 한다. 그래서 setup.py에서 librt 의존성을 제거하고 설치하니 잘 된다.
+
+이 문제는 tokyo-python 0.7.0에서 발생하는데 위에서 링크한 이슈를 읽어보면 trunk 버전에서는 이 문제가 해결된 것으로 보인다. 이 글을 쓰는 당시 0.7.0이 최신 버전이니 이 다음에 릴리즈되는 버전에서는 문제가 해결되어 있을 듯하다.
+
+ [tokyo-python]: http://code.google.com/p/tokyo-python/
+ [1]: http://code.google.com/p/tokyo-python/issues/detail?id=4
1  1242851060.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-04 15:31:00 GMT", "url": "http://blog.dahlia.kr/post/1242851060", "url-with-slug": "http://blog.dahlia.kr/post/1242851060", "format": "markdown", "-slug": "", "id": "1242851060", "unix-timestamp": "1286206260", "date": "Tue, 05 Oct 2010 00:31:00", "type": "regular", "slug": "", "reblog-key": "1heCcSR1"}
5 1242851060.md
@@ -0,0 +1,5 @@
+쓰고있는 도구에 아주 만족하는게 아니라면 불만을 간직했다가 언젠가는 직접 털을 깎아야([yak shaving][1])한다. **그 도메인을 욕할 것이 아니라.**
+
+이를테면 크로스 브라우징은 어려운 문제이므로 짜증이 올라와 욕을 하는 것은 같아도, 그 뒤의 행동이 주변 사람에게 “웹 개발 거지같아요, 하지 마세요”라고 말하고 다니는 것과 jQuery 같은 라이브러리를 만들어내는 것은 분명 태도(와 능력)의 차이다.
+
+ [1]: http://blog.dahlia.pe.kr/articles/2009/09/11/yak-shaving "야크 털깎기"
1  1268041887-unicode.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-08 08:27:00 GMT", "url": "http://blog.dahlia.kr/post/1268041887", "url-with-slug": "http://blog.dahlia.kr/post/1268041887", "format": "markdown", "regular-title": "Unicode \uc774\ud574\uc758 \ub2e4\uc591\ud55c \ub2e8\uacc4\ub4e4", "-slug": "-unicode", "id": "1268041887", "unix-timestamp": "1286526420", "date": "Fri, 08 Oct 2010 17:27:00", "title": "Unicode \uc774\ud574\uc758 \ub2e4\uc591\ud55c \ub2e8\uacc4\ub4e4", "type": "regular", "slug": "unicode", "reblog-key": "axT0MK2c"}
17 1268041887-unicode.md
@@ -0,0 +1,17 @@
+아래는 내가 경험한 여러 유형들을 정리해본 것.
+
+ 1. **최종 사용자**. “ㅅㅂ 한글 깨지네.”
+ 2. Unicode에 대해 전혀 모르는 개발자. 습관적으로 `charset=euc-kr`이나 `charset=cp949` 따위의 기존 레거시 코드를 템플릿 삼아 복사함.
+ 3. UTF-8을 쓰니 Unicode 완비되었다고 생각하는 사람.
+ 4. 세상에는 여러 종류의 인코딩이 존재하고 있다는 것을 아는 사람. iconv도 사용할 줄 안다.
+ 5. 특정 문자셋을 사용하는 문자(열)을 바이트열로 인코딩하는 방식이 인코딩이며, UTF-8이 곧 Unicode가 아니라는 것을 아는 사람. Python에서 `unicode` 타입과 `str` 타입이 왜 함께 있는지 이해하며 잘 사용한다. 혹은 C/C++에서 `wchar_t[]`/`std::wstring`으로 Unicode 문자열을 담아 사용하고 입출력 시에 그것을 인코드해서 `char[]`/`std::string`으로 변환해서 쓸 줄 안다. (또한 `wchar_t`가 곧 Unicode 문자를 뜻하는 것은 아니라는 것도 이해하고 있다.)
+ 6. Unicode에 여러 평면(plane)이나 카테고리(category), 스크립트(script) 등의 분류가 존재한다는 것을 알고 있다. [UCD][]의 존재를 알고 있다.
+ 7. **Unicode 전문가.** 각종 [Unicode 정규화 형식][unf]에 대해 잘 알고 있고, 자주 사용하는 몇몇 스크립트들의 바운더리 코드 포인트를 외우고 있으며, Unicode 버전 몇에 어떤 스크립트가 추가되었다든가(예를 들면 5.0 때 파스파 스크립트가 추가됨) 하는 잡다한 것들을 모조리 알고 있다.
+
+나는 6 정도이지만, 실제로 회사를 다니면서 느낀 바로는 2, 3, 4에 해당하는 사람이 대부분이었던 것 같다. IRC에서 같이 노는 사람들은 대체로 나와 비슷한 5–6 수준. 7에 해당하는 사람은 거의 본 적이 없다([강성훈][1] 씨 같은 경우 빼면…).
+
+ *[UCD]: Unicode Character Database
+
+ [ucd]: http://unicode.org/ucd/
+ [unf]: http://unicode.org/reports/tr15/
+ [1]: http://mearie.org/
1  1285533566-mixin.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-10 19:39:00 GMT", "url": "http://blog.dahlia.kr/post/1285533566", "url-with-slug": "http://blog.dahlia.kr/post/1285533566", "format": "markdown", "-slug": "-mixin", "id": "1285533566", "link-url": "http://en.wikipedia.org/wiki/Mixin", "link-text": "Mixin", "unix-timestamp": "1286739540", "date": "Mon, 11 Oct 2010 04:39:00", "title": "Mixin", "type": "link", "slug": "mixin", "reblog-key": "4yxNc6yw"}
8 1285533566-mixin.md
@@ -0,0 +1,8 @@
+> In [object-oriented programming languages][1], a __mixin__ is a [class][2] that provides a certain functionality to be [inherited][3] by a subclass, while not meant for [instantiation][4] (the generation of objects of that class).
+
+이 정의에 따르면, 추상 클래스(abstract class) 여러 개를 다중 상속할 수 있으면 그게 바로 mixin이다.
+
+ [1]: http://en.wikipedia.org/wiki/Object-oriented_programming_language
+ [2]: http://en.wikipedia.org/wiki/Class_(computer_science)
+ [3]: http://en.wikipedia.org/wiki/Inheritance_(computer_science)
+ [4]: http://en.wikipedia.org/wiki/Class_(computer_science)#Instantiation
1  1295597685-fexpr.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-12 01:48:00 GMT", "url": "http://blog.dahlia.kr/post/1295597685", "url-with-slug": "http://blog.dahlia.kr/post/1295597685", "format": "markdown", "-slug": "-fexpr", "id": "1295597685", "link-url": "http://en.wikipedia.org/wiki/Fexpr", "link-text": "Fexpr", "unix-timestamp": "1286848080", "date": "Tue, 12 Oct 2010 10:48:00", "title": "Fexpr", "type": "link", "slug": "fexpr", "reblog-key": "Kw0ovnVm"}
8 1295597685-fexpr.md
@@ -0,0 +1,8 @@
+Fexpr이란 (Lisp에서) 적용될 때 인자들을 모두 평가한 결과 값을 전달받는 대신, 인자에 나열된 폼들(forms)을 그대로 전달받는 함수를 말한다.[^1] 따라서 인자는 아무 것도 평가되지 않을 수도 있고, 평가 순서가 달라질 수도 있다. 함수 안쪽에서 폼을 가지고 명시적으로 평가(`eval` 함수를 이용해서)해야 하므로 Haskell 등에서 사용하는 [normal order evaluation][1]과도 다른 이야기다.
+
+Lisp은 아니지만 [Io][2]나 내가 만드려는 언어인 Veeyu도 fexpr 기능을 갖고 있다.
+
+ [^1]: 그야 물론 Lisp의 모든 폼이 사실은 리스트(list) 아니면 애텀(atom)이라는 homoiconicity 덕분에 가능한 이야기다.
+
+ [1]: http://en.wikipedia.org/wiki/Normal_order_evaluation#Normal_order
+ [2]: http://iolanguage.com/
1  1356936681-langdev-irc.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-20 06:09:47 GMT", "url": "http://blog.dahlia.kr/post/1356936681", "url-with-slug": "http://blog.dahlia.kr/post/1356936681", "format": "markdown", "-slug": "-langdev-irc", "id": "1356936681", "unix-timestamp": "1287554987", "date": "Wed, 20 Oct 2010 15:09:47", "type": "regular", "slug": "langdev-irc", "reblog-key": "wVIpbOTf"}
3  1356936681-langdev-irc.md
@@ -0,0 +1,3 @@
+LangDev IRC 채널에서 각자 자신의 _실용적인_ 첫 프로그램에 대해 얘기를 했다.
+
+나는 중학교 1학년 때 PHP로 내 계정을 관리하기 위한 웹 파일 관리 애플리케이션을 만든 적 있는데, 이게 나의 첫 프로그램이다. 이 때 `fopen()`, `fwrite()`, `fread()`, `fclose()` 등의 파일 입출력 함수를 배웠던 기억이 난다. 그 외에 `trim()`, `join()`, `explode()`, `file()`, `dir()`, `str_replace()`, `strrev()` 함수 등을 이 때 배웠던 것 같은데 기억이 가물가물하다.
1  1364722885.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-21 07:20:17 GMT", "url": "http://blog.dahlia.kr/post/1364722885", "url-with-slug": "http://blog.dahlia.kr/post/1364722885", "format": "markdown", "regular-title": "\uc2e0\uacbd\uc4f0\uc774\ub294 \uac83\ub4e4", "-slug": "", "id": "1364722885", "unix-timestamp": "1287645617", "date": "Thu, 21 Oct 2010 16:20:17", "title": "\uc2e0\uacbd\uc4f0\uc774\ub294 \uac83\ub4e4", "type": "regular", "slug": "", "reblog-key": "NR6dRbuw"}
9 1364722885.md
@@ -0,0 +1,9 @@
+- **Microsoft**, **Facebook**, **Smalltalk** 등처럼 한 단어로 이뤄진 고유명사를 MicroSoft, FaceBook, SmallTalk처럼 중간에 맘대로 대문자 하나를 더 넣어서 단어 두개로 만들어서 쓰는 경우
+- **Windows**, **iTunes** 등과 같은 복수형을 취하는 고유명사를 Window, iTune처럼 맘대로 단수형으로 바꿔서 쓰는 경우
+- **iPhone**, **iMac** 등을 i-phone, IMac 등으로 쓰고 있는 경우[^1]
+- **JavaScript**처럼 두 단어를 붙여서 쓰는 고유명사를 Javascript처럼 한 단어로 만들어버리거나 java script처럼 아예 공백을 넣어 띄어버린 채로 쓰고 있는 경우 (심지어 자바script 등으로 쓰는 경우도 있다…)
+- **Objective-C** 같은 고유명사를 Object C, Object-C 등으로 쓰는 경우
+
+뭐 열거하자면 이것 말고도 많다. 한국 사람들이 특히 이렇게 쓰는 경향이 심한 것 같다. 상표 같은 고유 명사는 잘 맞춰서 써줬으면 좋겠다. 난 이런게 너무 신경쓰이더라.
+
+ [^1]: 더 신경쓰이는 경우가 있는데, 자기네 제품 이름을 iFoobar 같은 형식으로 지어놓고서 어떤 매뉴얼에서는 i-foobar 같이 적어놓고 로고에는 i-Foobar라고 적는 등 직원마다 자기 맘대로 쓰고 있는 경우. 사실 전에 다니던 회사가 표기법 통일이 안되어서 이랬었다.
1  1379411418-facebook.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-23 07:31:29 GMT", "url": "http://blog.dahlia.kr/post/1379411418", "url-with-slug": "http://blog.dahlia.kr/post/1379411418", "format": "markdown", "-slug": "-facebook", "id": "1379411418", "link-url": "http://www.facebook.com/hongminhee", "link-text": "Facebook", "unix-timestamp": "1287819089", "date": "Sat, 23 Oct 2010 16:31:29", "title": "Facebook", "type": "link", "slug": "facebook", "reblog-key": "hbfTcb5u"}
3  1379411418-facebook.md
@@ -0,0 +1,3 @@
+Facebook을 본격적으로 시작했다.
+
+<http://www.facebook.com/hongminhee>
1  1382431580-python-datetime-datetime.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-10-23 17:45:00 GMT", "url": "http://blog.dahlia.kr/post/1382431580", "url-with-slug": "http://blog.dahlia.kr/post/1382431580", "format": "markdown", "regular-title": "Python\uc758 datetime.datetime \ubcd1\uc2e0 \uac19\uc740 \ub450 \uac00\uc9c0", "-slug": "-python-datetime-datetime", "id": "1382431580", "unix-timestamp": "1287855900", "date": "Sun, 24 Oct 2010 02:45:00", "title": "Python\uc758 datetime.datetime \ubcd1\uc2e0 \uac19\uc740 \ub450 \uac00\uc9c0", "type": "regular", "slug": "python-datetime-datetime", "reblog-key": "fpXDXdr3"}
17 1382431580-python-datetime-datetime.md
@@ -0,0 +1,17 @@
+Python 표준 라이브러리에 있는 [`datetime.datetime`][1] 클래스의 두 병신 같은 부분:
+
+ - 두 개념이 하나의 자료형에서 공존하고 있다:
+
+ - 시간대(time zone) 없는 시각 정보를 담는 **naive datetime**
+ - 시간대 정보가 함께 있는 **tz-aware datetime**
+
+ 예상할 수 있듯 이 클래스는 저 두 가지가 **하나의 자료형에서** 공존하기 때문에 다형적으로 작동하지 않는다.
+
+ - 기본 시간대([`datetime.tzinfo`][2]) 구현이 전혀 없다. _심지어 UTC조차!_ UTC 시간대의 tz-aware datetime 인스턴스를 만들고 싶다면, 먼저 [`datetime.tzinfo`][2]를 상속받는 UTC 클래스를 손수 작성해야 한다.[^1]
+
+
+ [^1]: 뭐 어차피 시간대를 고려해야 하는 경우라면 [pytz][3]는 거의 필수고, `pytz.utc`를 쓰면 되지만 그래도 영 짜증나는 부분이 아닐 수 없다.
+
+ [1]: http://docs.python.org/library/datetime.html#datetime-objects
+ [2]: http://docs.python.org/library/datetime.html#datetime.tzinfo
+ [3]: http://pytz.sourceforge.net/
1  1575259937.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-11-14 21:32:44 GMT", "url": "http://blog.dahlia.kr/post/1575259937", "url-with-slug": "http://blog.dahlia.kr/post/1575259937", "format": "markdown", "regular-title": "\uac1c\ubc1c\uc790 \ucc2c\uc591", "-slug": "", "id": "1575259937", "unix-timestamp": "1289770364", "date": "Mon, 15 Nov 2010 06:32:44", "title": "\uac1c\ubc1c\uc790 \ucc2c\uc591", "type": "regular", "slug": "", "reblog-key": "KfFcrnwF"}
45 1575259937.md
@@ -0,0 +1,45 @@
+다소 긴 글이 될 것 같다. 진부한 기획자와 개발자 이야기이다.
+
+일단 개발자 입장에서 기획자의 개발자들에 대한 오해(혹은 그렇다고 여겨지는 것)들을 바로잡을 필요가 있을 것 같다. 바로 “개발자들은 기획에 관심도 없고 오히려 기획 업무를 싫어한다”는 생각이다.
+
+이 오해는 아마도 기획자들이 만나는 개발자들의 유형을 분류하는 것부터 풀어나가야 할 것 같다. 나는 이 글에서 막연하게 개발자를 두 부류로 나눌 생각이다. 하나는 **좋은 개발자**이고, 다른 하나는 **그냥 개발자**이다. 전자는 열정이 있는 개발자이며, 개발을 비교적 즐거워하는 타입이다. 후자는 밥벌이 개발자고 30대가 되면 은퇴하고 치킨집을 차려야 한다고 굳게 믿는 타입이다. 그리고 대한민국 개발자라면 후자가 더 많은 듯 보인다.[^1]
+
+좋은 개발자와 그냥 개발자는 대부분 개발자가 된 동기가 전혀 다르다. 그냥 개발자는 대부분 평범한 인문계 고등학교를 졸업하고 자신의 대학수학능력시험 점수에 맞춰 (그리고 그 시대의 유행을 좇아) 대학교와 학과를 정하다보니 적성이나 하고 싶은 것과 상관 없는 컴퓨터 공학/과학을 전공한 경우가 대부분이다. 물론 이런 현상은 컴퓨터 공학/과학 외의 다른 학문도 결국 비슷하게 일어나기 때문에 흔하다면 흔하다. 스스로 재미 없다고 생각하는 일을 전공과 직업으로 택한 그들의 고달픔을 동정할 수 있겠지만, 일정부분 자업자득인 셈이다.
+
+반면 좋은 개발자는 애초에 대학교와 학과를 선택하기 이전, 아마도 중학교, 빠르게는 초등학교 때부터 프로그래밍을 취미로 삼았던 경우가 대부분이다. 이 부류의 사람들은 고등학교 때부터 이미 Linux를 주 운영체제로 사용했다거나, 서투르나마 혼자서 서비스를 운영했다거나, 여러 오픈소스 프로젝트에 기여하는 등의 경험을 한다. 나와 친한 개발자들은 절대 다수가 그렇다. 그렇다면 이 부류의 사람들은 도대체 어쩌다가 대학교도 가기 전부터 대학교에서 배울, 혹은 대학교에서도 배우지 못할 이런 지식과 경험을 쌓게 되는 것일까?
+
+자, 여기 내가 하고자 하는 얘기가 있다. **사실 기획자가 기획을 시작하게 된 동기와 ‘좋은 개발자’들이 개발을 어릴 때부터 시작하게 된 동기는 같다!** 자기가 머릿속에 떠올린 무언가를 실제로 손으로 만져보고 싶다는 욕구가 바로 그 동기이다.
+
+그리고 우리는 어릴 때 프로그래밍을 배웠지만 결국 개발자가 되지 못하는 사람들을 보며 좀더 확신을 얻을 수 있다. 다른 세대는 어떨지 모르겠으나 내 또래만 해도 초등학교 때 컴퓨터 학원 다니는게 유행이었다. 나는 컴퓨터 학원을 다닌 적 없지만, 다닌 친구들을 보면 그 중에 성취도가 높은 학생들을 위주로 Visual Basic 6를 가르쳤다. (나보다 조금 윗세대는 GW-BASIC을 배웠다고.) 그리고 좀더 커서 선린인터넷고등학교를 다니면서 수도권 내에서 비교적 많은 지역 출신의 친구들과 얘기해보니 그것은 우리 동네 유행이 아니라 어느 정도 전국적인 유행이었던 듯 싶다. 하지만 그들 가운데 대부분은 개발자와 상관 없는 사람으로 성장한다. **기술을 알아봤자 그걸로 만들고 싶은게 딱히 없다면 기술은 발전할 여지가 없기 때문이다.** 게다가 동네 컴퓨터 학원에서 알려주는 프로그래밍 기술이래봤자 머리굴려 성적표 계산기 짜는 수준이므로 “세상에는 프로그래밍이라는 것도 있다”는 것을 알려주는 의의밖에 없다.
+
+결국 어릴 때 컴퓨터 학원을 다녀 Visual Basic으로 프로그래밍을 입문했든, 아니면 나처럼 제로보드가 한창 유행할 때 PHP 책 하나 사서 독학으로 입문했든 간에, **자기가 뭔가 만들고 싶은게 있었던 사람들만 개발자로 성장한다.** 모티베이션이 가장 중요한 것이다.
+
+자, 이 정도로 설명했으면 좋은 개발자의 최초 동기와 기획자들의 최초 동기가 실은 같은 것이라는 점은 이해할 수 있을 것이다. (그냥 개발자들에게는 미안하지만, 이후부터는 개발자는 좋은 개발자만 칭하는 것으로 하겠다.) 당연히 개발자들은 그러한 동기 아래, 처음 몇년간은 철저히 자신이 만들고 싶은 것을 구현하는 데 필요한 기술들 위주로 공부를 해나간다. 그리고 실제로 자기가 직접 만들고자 하는 것들을 어설프게나마 만들어 나간다. 그리고 그들 중 일부는 자신의 이상적인 기획에 근접한 것들을 만들어 내기도 한다. **당연히 이 과정에는 개발 뿐만 아니라 기획도 포함되어 있다. 기획자들이 기획이 없는 프로덕트 구현이 가능하다고 생각하지 않는다면.**
+
+따라서 개발자들이 기획에 관심이 없다는 얘기는 오해라고 할 수 있다. 아, 당연히 앞서 언급한 **그냥 개발자**들이야 그런거 별로 없다. 자신이 만나본 개발자 중에서는 좋은 개발자가 없었다고? 운이 좋지 않으시네요. 그래도 운이 나쁘다는 얘기는 아닙니다. 못 만나는 게 보통인 것 같거든요.
+
+그러면 왜 같은 동기를 가졌던 사람들이 기획자와 개발자라는 두 부류로 나뉘게 되는 것일까? 나는 답이 간단하다고 생각한다. 만들고 싶은 걸 만드려고 프로그래밍 공부를 시작해서 순조롭게 개발 소양을 익힌 사람들은 개발자가 되는 것이고, 그렇지 않은 사람들은 기획자로 남아 자신 대신 개발을 해줄 사람들을 찾는 방향으로 방법을 바꾼다. 말이 방법을 바꾸는 것이지, 나의 냉소적인 시각에서는 개발 공부 좀 하다가 포기하는 셈이다. 아예 처음부터 엄두를 못 냈거나.
+
+물론 기획자들은 자신들만이 하는 고유한 업무가 있다고 이야기할 것이다. 단순히 프로덕트 디자인을 고민하는 것이 아니라, 그것을 명세로 잘 문서화하고, 문서를 중심으로 개발자들과 커뮤니케이션한다. 이것도 사실은 개발자라는 중간 계층이 따로 필요하니까 생긴 프로세스일 뿐이다. 기획자들은 부정하고 싶을 수도 있겠지만 이미 코드는 이상적으로 명세와 같은 역활을 하며, 실제로 잘 쓰여진 코드는 명세 역할을 할 수도 있다. (물론 이 이야기는 현실을 고려하지 않은 면이 크다.)
+
+기획자에게 프로그래밍의 본질을 잘 설명해주겠다. 프로그래머가 작성한 코드는 이미 명세이다. 다시 말해 컴퓨터를 돌리기 위해 코드를 쓰는게 아니다! 애초에 코드를 돌리기 위해 컴퓨터가 발명된 것이다. 단지 컴퓨터가 그 명세를 실현해주는 것이다. 어디서 들어본 것 같지 않은가? “기획자가 작성한 명세가 있고 개발자가 그 명세를 실현해준다.” 과격하게 얘기해서, 우리가 현업에서 이야기하는 기획 프로세스는 분업이라기 보다는 본질적으로 같은 일을 두 번 하는 것이다. 기획자가 아이디어를 정리해서 명세로 정리한다. 개발자는 그 자연어로 작성된 명세를 다시 프로그래밍 언어로 **번역**한다. 개발자의 일을 이렇게 정의하면 비교적 단순 작업이 되어버리고 앞서 얘기한 **그냥 개발자**들이 이런 일을 도맡아 할 공산이 크다. 반면 **좋은 개발자**들은 기본적으로 기획자이며 아이디어를 명세로 작성하는데 자연어 대신 프로그래밍 언어를 쓴다. 프로그래밍 언어에 대한 오해를 풀어야한다. 프로그래밍 언어는 컴퓨터가 이해할 수 있는 언어가 아니다. 사람이 큰 실수 없이 로직을 기술하기 위해 고안된 언어이고, 그 언어를 실행하기 위해 발명된 것이 컴퓨터와 기타 도구들이다.
+
+**기획자** + **개발자**
+: 아이디어 → 정리 → 명세 (문서) → 명세 (코드)
+
+**좋은 개발자**
+: 아이디어 → 정리 → 명세 (코드)
+
+이리저리 돌려서 얘기했지만 내 생각을 요약하자면 이렇다. 기획자는 개발을 할 줄 알아야 하는데 그렇지 않으니까 개발자를 따로 둬야 했고, 그로 인한 업무가 더 생겼다. 당연히 기획자가 이 글을 본다면 어이없어 하겠지만, 애초에 언어의 함정에 빠져서 그런 감정을 느끼는 것이라고 생각한다. 앞서 얘기한 좋은 개발자는 사실 개발자가 아니다. 그 사람들은 개발을 할 줄 아는 기획자들이다. 그리고 흔히 우리가 얘기하는 기획자는 개발을 할 줄 모르는 기획자다. 잘 생각해보자. 개발을 할 줄 알면 개발자라고 불러야 할까? 그렇다면 기획자 본인들이 개발을 할 줄 알게 되었다고 생각해보자. 그럼 본인들이 이제 개발자가 되나?
+
+요즘 앱스토어부터 시작해서 소셜 네트워크, 소셜 커머스 등 “소셜”이 접두어로 붙는 거품 가득한 신종 인더스트리가 마구 나오고 있는 와중에, 새로운 프로덕트 기획하는 사람들이 많다. 그리고 이 사람들이 항상 하는 이야기가 있다. “개발자 구해요.” 애초에 기획자와 개발자가 상호보완적이라면 개발자가 기획자 구하는 이야기도 많이 나와야 한다. 난 그런 소리는 조금은 커녕 전혀 본 적도 없다. 왜 그럴까? 애초에 새로운 프로덕트를 만드려는 개발자는 기획자를 찾지 않는다. 새로운 프로덕트를 만드려고 한다는 것이 기획을 이미 직접 시작했다는 소리이므로. 결국 개발자가 기획하는 경우는 있어도 기획자가 개발하는 경우는 없다. 개발자가 기획하는 것은 엉성하나마 가능한 얘기고 기획자가 개발하는 것은 불가능한 이야기기 때문이다. 애초에 개발도 할 줄 아는 기획자면 이미 개발자라고 불리고 있을 것이다. 내가 앞서 얘기한 **좋은 개발자**다.
+
+이제 진짜 하고 싶은 얘기이다. **자칭 기획자라고 하는 사람들은 개발을 좀 공부했으면 한다.** 개발자로서 커뮤니케이션이 불편해서 이런 얘기하는게 아니다. 나는 기획자와 일하지 않으므로 그런 불편은 없다—내가 속한 [Lunant][](야간개발팀)는 전원이 기획과 개발을 둘 다 한다. 자기가 만들 프로덕트를 스스로 프로토타이핑도 못한다면 제대로 된 프로덕트 디자인이 힘들기 때문이다. 프로토타입이라도 있어야 사람들에게 빠르고 정확한 피드백을 받는데, 언제까지 입으로 설명하고 다른 사람이 “어떤 것 같아요”라고 대답하는 소리를 들은 뒤에 저 말 중에 어디까지가 립서비스일까 하는 생각을 하며 복잡하게 일할 것인가. 프로토타이핑 직접 해서 보여준 다음에 그걸 어떻게 쓰나 옆에서 관찰하는 게 투명하고 좋은 피드백을 얻기 좋다. 그리고 그렇게 얻은 피드백으로 프로토타입을 계속 직접 주물럭대면서 여러 이터레이션을 돌린 다음, 그것을 구체화시킬 때 본격적인 개발을 아웃소싱해도 늦지 않다. **기획자더러 프로덕트 개발 처음부터 끝까지 다 하라는 소리가 아니다. 개발 능력을 갖춰야 프로덕트 디자인을 제대로 해낼 수 있다는 이야기다.**
+
+이런 얘기 하면 대부분 반응이 이렇다. “나도 안 해본 게 아니야. 근데 어렵더라고.” “사람마다 적성이 있어. 3개월 동안 책 계속 들여다 봐도 무슨 소린지 모르겠는데 어떡해.” 아, 그 얘기들 말인데 내가 프로그래밍 입문할 적에 정확히 그랬었다. 초등학교 5학년 때 PHP 책을 사서 만 1년이 넘도록 책을 끼고 살았는데 아무리 읽어도 무슨 소리인지 도통 모르겠어서 프로그래밍 못했다. 내가 제대로 프로그래밍을 시작한 것은 결국 중학교 입학 이후다. **그러니까 대부분 적성이 안 맞는 게 아니라 그냥 더 오래 붙잡고 있어야 할 뿐이다.**
+
+어차피 이런 글을 써봤자 내가 답답해하는 종류의 사람들은 속으로든 자신의 블로그에든 대거리를 놓으며 평생 개발에는 손도 대지 않을 공산이 크다. 그 사람들이 드는 자신이 개발에 손을 대서는 안되는 이유가 그럴듯하든 엉터리이든, 중요한 사실이 하나 있다. 아무리 제 머릿속에 놀라운 이미지를 품고 있다고 해도 자신이 직접 구현을 해내지 않는 이상 비싼 돈 주고 아웃소싱을 하더라도 그 이미지를 제대로 구현한 것을 두 눈으로 직접 볼 수는 없을 것이라는 점이다.
+
+[^1]: 물론 신뢰할만한 통계 자료 같은 것을 근거로 하는 얘기가 아니라, 내 짧은 경험만을 토대로 얻은 종합적인 인상이므로 바이어스가 있을 수는 있다.
+
+[lunant]: http://lunant.com/
1  1653101302-toby-lee.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-11-23 00:30:00 GMT", "url": "http://blog.dahlia.kr/post/1653101302", "url-with-slug": "http://blog.dahlia.kr/post/1653101302", "format": "markdown", "-slug": "-toby-lee", "id": "1653101302", "unix-timestamp": "1290472200", "date": "Tue, 23 Nov 2010 09:30:00", "type": "regular", "slug": "toby-lee", "reblog-key": "HmHiVocq"}
41 1653101302-toby-lee.md
@@ -0,0 +1,41 @@
+어쩌다가 Toby Lee라는 사람이 내가 쓴 글(이라기 보다는 그냥 나 같지만)에 대해 쓴 [오래된 글][1] 하나를 발견했다.
+
+> 맨날 하는 소리가 똑같은 언어 우월주의자.
+> 구체적인 얘기는 못하면서 항상 레파토리는 똑같다.
+> 디자인패턴은, DI는, 머머는 자바가 꾸져서 필요한 것일 뿐이라고.
+> So what?
+
+글 내용이 아니면 아닌 것이고 토를 타면 토를 달 것이지, 왜 글 내용이 아니라 나에 대한 인신 공격을 한담… 확실히 발견했을 때 좋은 기분은 아니었다. 그리고 여러 생각이 들어서 두서없이 글을 써보려 한다.
+
+나는 프로그래밍 언어를 디자인하는 입장이고 당연히 이미 존재하는 프로그래밍 언어를 잘 쓰자는 쪽으로 생각하기 보다는 다른 사람이 더 좋은 프로그래밍을 할 수 있도록 하는 프로그래밍 언어를 디자인하자는 관점으로 자주 생각하기 때문에, 프로그래밍 언어 자체에 관심이 없는 사람에게는 “언어 우월주의자”같은 식으로 보일 수도 있을 것 같다. 하지만 디자인 패턴 등이 언어의 부족한 점을 매꾸기 위한 “우아해 보이는” workaround라는 생각에는 변함이 없다.
+
+오히려 언어 우월주의자가 아니라면 Java 자체의 문제에 대해 논하는 것을 “그런가보다”하고 들을 수 있어야 하지 않을까 하는 생각도 든다. 난 비록 Python 등의 언어를 사용하지만 새로 나오는 언어들에 꾸준히 관심을 주고 어느 정도씩은 공부를 한다. 당연히 새로 나온 언어 중에는 비교적 최신의 PL 연구 결과가 반영된 것들도 많고, 그런 것들에서 기존 언어의 문제점을 발견하기도 한다. 내가 주로 쓰는 언어인 Python에서도 마찬가지다. 다만 내가 보기에 Java나 C 등은 “너무 낡아서” 쓰고싶지 않지만 그러기에는 너무 자주 마주치는 언어이기 때문에 더 많이 말을 하게 되는 것 같다.[^1]
+
+대체 Java가 뭐가 어때서? 사실 말을 하자면 한도 끝도 없지만, 내 심정을 솔직하게 표현하자면 Java 쓰는 사람들더러 “C가 뭐가 어때서?”라고 할 때 어디부터 말을 해야 할까라는 생각이 스치면서 약간 무력감을 느끼는 것과 비슷한 느낌일 것이다. C를 잘 쓰는 사람에게는 사실 Java의 장점을 얘기해도 별로 장점으로 들리지 않을 것이다. 내 생각에 Java는 가비지 컬렉션을 한다는 점 하나만으로도 C보다 좋은 언어이고, 반대로 메모리 관리를 직접한다는 것은 기술의 한계지 결코 장점이 되지는 못한다. 메모리 관리를 최대한 자동화한다는 의도는 좋은 것이고, 현실적으로 충분히 똑똑치 못한 것은 프로그래밍 언어의 연구 과제이다. 그렇다고 과거로 돌아가 모두들 행복하게 포인터로 수동 메모리 관리를 하며 좋은 소프트웨어 개발을 합시다 하는 것은 내가 볼 때는 말이 되지 않는다. 게다가 rich한 표준 라이브러리도 존재하고, JVM이라는 세상에서 가장 성숙한 (외계 기술의 종합체인) 가상 머신 구현도 있다. 여러가지를 따져 볼때 C에 비해 Java는 일장일단이 있는 관계가 아니라 십장일단 혹은 백장일단 정도의 관계가 아닐까 싶다.
+
+물론 언제나 리얼 월드에는 수많은 제약이 존재하고 C나 Java를 쓸 수밖에 없는 경우도 많을 것이다. 나도 산업기능요원 했을 적에는 어쩔 수 없이 1년 넘게 PHP로 삽질을 많이 했다. 당연히 PHP도 잘 쓰면 좋은 언어인데, 어떤 도구라도 잘 쓰면 된다는 말은 참 힘이 빠지는 얘기가 아닐 수 없다. 정작 그런 얘기 하는 사람에게 C로 SI 개발 해보라고 하면 질색할 것이 뻔하다. 질색하는 이유는 C보다 Java에 훨씬 익숙하기 때문도 있겠지만, 어떤 언어가 어떤 일에 “적합한지” 이미 답을 알고 있기 때문일 것이다.
+
+그리고 모든 도구가 그렇듯, 프로그래밍 언어의 발전 역시 “범용 프로그래밍”에 좀더 적합해지려는 노력이고, 내가 평소 주장하는 바는 Java보다 “범용 프로그래밍”에 적합한 언어가 분명 많이 존재한다는 것이다. 모든 프로그래밍에는 common pattern이 많고[^2] 그것들을 좀더 효율적으로 해낼 수 있으면 대체적으로 좀더 좋은 프로그래밍 언어라고 할 수 있는 것이다.
+
+IoC 얘기만 해도 사실 이건 말 그대로 subroutine 관계에 있어서 호출자와 호출 대상을 역전시키는 패턴인데, subroutine은 스택을 가정한 흐름이고 호출이 끝나면 원래 위치로 되돌아간다는 특성 때문에, subroutine만 지원하는 언어에서는 딱히 다른 방도가 없다. 하지만 이걸 모든 프로그래밍 언어에 공통적으로 필요한 패턴으로 보기에는 조금 곤란하다. 그야 GUI 툴킷을 C/Java 등으로 만들 때는 메인 룹이 필요하고 subroutine 관계에서는 IoC 써야 하지만, coroutine이나 하다못해 Python의 generator 같은 것이라도 있으면 IoC를 도입하지 않고 좀더 직관적인 형태로 디자인할 수도 있다.[^3] Ruby에서 블럭을 쓰는 많은 일들이 Python에서 generator로 해결될 수 있다는 점을 생각해보자. ([소싯적에 썼던 글 참고.][2]) 블럭은 기본적으로 IoC이고 generator는 coroutine의 아주 naive한 구현으로 볼 수 있다.
+
+물론 IoC가 필요한 때가 있고, Java 같은 언어를 쓴다면 IoC가 필요하지만 그렇다고 “IoC가 필요 없는 프로그래밍 언어가 있느냐”고 확신할 것도 없는 것이다. 그리고 IoC가 좋으면 계속 그걸 써도 되고 coroutine이 뭔지 generator가 뭔지 딱히 궁금해하지 않아도 된다. C 개발자가 가비지 컬렉션에 관심 없고 `malloc`/`free` 여전히 잘 쓰고 있으니 그 방식으로 프로그램 잘 만드는 거랑 비슷하겠다.
+
+하지만 분명히 프로그래밍 언어의 발전이라는 것은 엄연히 존재하는 건데, 언어 우월주의자라고 욕하는 것은 좀 억울하다. 대부분의 사람들이 “도구는 잘 쓰면 그만”이라고 생각하고 “장인은 도구를 가리지 않는다”는 말을 과대 해석하고 misquote하는 세상에서 나 같이 생각하고 사는 사람은 역시 좀 피곤한 것 같다.
+
+마지막으로 나도 misquote 좀 한번 해보자. Henry Ford의 말이다.
+
+> If I’d listened to customers, I’d have given them a faster horse.
+
+비유하자면 디자인 패턴은 말을 빠르게 하는 것이다. 좋은 승마법 혹은 말을 잘 키우는 방법이다. 프로그래밍 언어 자체를 변화시키려는 노력은 “운송 방식” 자체를 개선하려는 의지이고, 언젠가는 차나 나아가 우리가 아직 상상하지 못하는 새로운 운송 방법을 찾아낼 수 있는 가능성이다.
+
+[![](http://farm5.static.flickr.com/4101/4890405186_7a1c5b71c8.jpg)](http://www.flickr.com/photos/hongminhee/4890405186/)
+
+[^1]: 정확히 말하자면 Java는 꾸준히 변화하는 중이고 Python도 출생년도로 보자면 1991년으로 Java보다 앞서있다. 두 언어의 차이라면 얼마나 언어가 빠르게 발전하냐는 적응력의 차이지만, 그것만으로도 두 언어에 대한 내 호감도는 크게 달라지는 것 같다. 그리고 이게 내가 Lisp을 좋아하는 이유이기도 하고.
+
+[^2]: 물론 완전히 _일반적인_ 패턴은 없을 수도 있지만 충분히 공통적인 패턴은 수도 없이 많다.
+
+[^3]: coroutine은 subroutine이라는 말과 대조해서 보면 추측할 수 있듯, 호출이 끝난 직후 원래 위치로 암시적으로 돌아가는 대신, 명시적으로 호출을 이어가야 한다는 점에서 기본적인 프로그래밍 방법이 아주 달라진다.
+
+[1]: http://www.google.com/buzz/tobyilee/V5rhqyHWNJ8/http-blog-dahlia-kr-post-784275981-%EB%A7%A8%EB%82%A0-%ED%95%98%EB%8A%94
+[2]: http://blog.dahlia.pe.kr/articles/2009/09/15/python-%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0%EB%B0%98%EB%B3%B5%EC%9E%90%EC%9D%98-%EB%A7%88%EB%B2%95
1  1728906260.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-11-29 18:58:32 GMT", "url": "http://blog.dahlia.kr/post/1728906260", "url-with-slug": "http://blog.dahlia.kr/post/1728906260", "format": "markdown", "regular-title": "\uc18c\ube44\ud558\ub294 \ucde8\ubbf8\uc640 \uc0dd\uc0b0\ud558\ub294 \ucde8\ubbf8", "-slug": "", "id": "1728906260", "unix-timestamp": "1291057112", "date": "Tue, 30 Nov 2010 03:58:32", "title": "\uc18c\ube44\ud558\ub294 \ucde8\ubbf8\uc640 \uc0dd\uc0b0\ud558\ub294 \ucde8\ubbf8", "type": "regular", "slug": "", "reblog-key": "wtnIpS9j"}
7 1728906260.md
@@ -0,0 +1,7 @@
+[이 글][1]을 보고 나니 문득 드는 생각이 있어서 글을 쓴다.
+
+취미를 크게 둘로 나누자면 소설을 읽는 것과 같은 소비하는(consuming) 취미와 소설을 쓰는 것과 같은 생산하는(productive) 취미가 있는데, 후자보다 전자에 손이 더 잘 가는 게 사실이다. 그래서 사람이 아무 동기나 의지가 없는 경우 소설을 쓰기보다는 읽기 십상이고, 또 그래서인지 많은 사람들이 후자에 해당하는 취미는 아예 없기도 하다. 그리고 생산하는 취미를 가진 사람들도 사실은 수많은 소비하는 취미를 갖고 있고, 그 중 하나 정도만 생산하는 취미인 경우가 대부분이다. 주변에서 그림을 그리고 글이나 음악을 쓰고 프로그램을 만드는 등의 취미를 가진 사람은 사실 꽤나 희귀하고, 있다면 (당사자들은 갸우뚱하는 평가지만) 일종의 ‘능력자’ 취급을 받기도 한다. 하나만 있어도 그렇고, 둘 이상 있다고 하면 더더욱 ‘능력자’니 ‘재주꾼’이니 하며 추켜세우기 바쁘다.
+
+어떤 종류의 취미 생활을 하더라도 즐겁기는 하지만, 남들에게 즐거움을 전파하는 데는 소비하는 취미보다는 생산하는 취미가 효과적이다. (내가 소설을 읽는다고 남이 즐겁지는 않다.) 그리고 무언가를 읽거나 듣거나 사용해서 얻는 즐거움에 비해 무언가를 만들면서 얻는 즐거움과 성취감, 그리고 그것을 남들에게 보여줬을 때 그들이 내게 보내는 피드백을 통해 느끼는 보람 따위를 모두 합친 즐거움은 훨씬 큰 것 같다. 나의 강한 편견을 더하자면, 소비하는 취미만 있는 사람보다 생산하는 취미가 있는 사람의 인생이 두 배, 아니 열 배는 더 행복해 보인다. 그래서 만약 내게 자식이 생긴다면 다른 어떤 교육보다 그런 취미를 찾을 수 있도록 여러 기회를 마련하는 데에 가장 큰 노력을 할 것 같다. 막상 그런 날이 온다면 실제로는 어떻게 될지 알 수 없겠지만…
+
+[1]: http://j.mearie.org/post/1727724364/goal-for-december-2010
1  2128778779-fexpr.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-12-07 04:11:00 GMT", "url": "http://blog.dahlia.kr/post/2128778779", "url-with-slug": "http://blog.dahlia.kr/post/2128778779", "format": "markdown", "regular-title": "Fexpr, \ub9e4\ud06c\ub85c \uadf8\ub9ac\uace0 \uace0\ucc28 \ud568\uc218", "-slug": "-fexpr", "id": "2128778779", "unix-timestamp": "1291695060", "date": "Tue, 07 Dec 2010 13:11:00", "title": "Fexpr, \ub9e4\ud06c\ub85c \uadf8\ub9ac\uace0 \uace0\ucc28 \ud568\uc218", "type": "regular", "slug": "fexpr", "reblog-key": "C58hayUF"}
82 2128778779-fexpr.md
@@ -0,0 +1,82 @@
+내 주변 사람들은 알 수도 있지만, 나는 Io와 Lisp 랭귀지를 상당히 좋아하는 편이고, 그보다는 정확히 말해 프로그래밍 랭귀지 전반에 관심이 많고 직접 만들고 있는 것도 있다. 그리고 내가 만드는 언어는 당연히 좋아하는 언어들로부터 영향을 받을 수밖에 없었다. 그중 하나가 [Io][]로부터 영향을 받은 기능인 [fexpr][]이다. (Io 언어를 몰라도 Lisp을 써봤다면 이해하는데 문제가 없겠지만, 잘 이해가 가지 않는다면 내가 IBM developerWorks에 썼던 [Io의 homoiconicity에 대한 설명][1]을 참고하면 좋을 것이다.)
+
+Io를 디자인한 [Steve Dekorte][]가 무슨 생각으로 Io에 fexpr[^1]을 집어넣었는지 정확히 알 수는 없다. 아마도 언어 구조와 일반 함수(메서드) 모두를 일반적으로 다루고 싶어서일 것이다. 언어에 fexpr이 있다면 함수를 지원하지 않아도, fexpr 안쪽에서 인자로 받은 quotes forms[^2]를 applicative order로 평가하게끔 구현하는 것으로 언어 자체를 고치지 않고 함수를 만들어 낼 수 있다. 실제로 Io의 메서드는 이름만 그렇지 결국 fexpr이고, applicative order로 평가하는 것을 쉽게 만드는 syntactic sugar가 제공되는 정도다.
+
+예를 들어 다음과 같은 Io 메서드 `a``b`는 완전히 같은 일을 한다:
+
+ a := method(call arguments at(0) doInContext(call sender) + 1)
+ b := method(x, x + 1)
+
+다만 `a` 메서드는 fexpr이라는 것이 명확히 드러난 것이고, `b``a`와 같은 fexpr을 만들어주는 syntactic sugar를 사용하여 더 읽고 쓰기 쉬워졌을 뿐이다. 언어 구조와 같은 것을 만들어내기 위해 인자들을 normal order로 평가해야 하는 경우가 아닌 이상, 대부분의 메서드는 applcative order로 평가되어야 하므로 저런 syntactic sugar는 실제로 코딩하기 위해서는 필요할 수밖에 없다. 다만 저런 syntactic sugar가 언어 차원에서 제공되지 않더라도 언어 사용자가 fexpr을 통해 얼마든지 syntactic sugar를 만들어낼 수 있다는 점이 중요하다.
+
+보통 현대적인 Lisp은 fexpr보다는 매크로를 선호하는 편이고, 찾아보면 fexpr을 제공하는 언어는 생각보다 드물다. 그 이유는 아마 매크로가 대부분의 경우 더 가독성도 높고 편한데다, 할 수 있는 것이 조금 줄어드는 대신 매크로 호출(macro expansion)을 인라이닝(inlining)하는 컴파일 최적화를 구현하는데도 까다롭지 않기 때문일 것이다. 아니, 정확히 말하자면 매크로는 ‘apply’하거나 ‘call’한다고 표현하지 않고 ‘expand’한다고 표현하는 걸 감안하면, 인라이닝은 최적화가 아니라 꼭 그렇게 되어야 하는 것으로 보는게 맞겠다. 실제로 Lisp 매크로란 결국 quoted forms를 받아서 치환될 quoted forms를 반환하는 것이니 인라이닝되라고 그렇게 디자인된 것이 맞는 것 같다.
+
+반면 fexpr을 언어에 추가한다고 하면 당장 조금만 생각해봐도 컴파일 타임에 _모든_ fexpr 호출을 인라이닝하기가 불가능하거나 적어도 쉽지 않으리라는 것을 알 수 있다. 하지만 앞서 말한대로 fexpr의 가장 큰 장점은 언어 구조와 함수, 그리고 매크로까지 모두 일반적으로 다룰 수 있다는 점일 것이다. 매크로 역시 (비록 항상 인라이닝이 되지는 않겠지만) fexpr으로 구현이 가능하다. 하지만 그 역은 성립하지 않는다.
+
+언어를 디자인할 때부터 최적화 등을 고려할 수도 있지만, 나는 그러기 보다는 표현력을 높이는 데에 우선하는 대신 최적화는 구현 시에 구현자의 형편껏 할 수 있는 데까지만 해줘도 좋다고 생각하는 편이다. 스펙상으로는 fexpr를 primitive로 제공하고 함수는 fexpr을 통한 구현으로 설명하는 대신, 실제 구현에서는 둘을 다르게 만들고 함수가 fexpr의 서브타입(subtype)이 되게 해도 된다. 인라이닝 최적화는 컴파일 타임에 할 수 있는 부분까지만 하고,[^3] 그렇지 않은 경우 인자로 전달된 quoted forms를 런타임에 평가하도록 다소 비효율적이지만 완전히 의도대로 작동하게 할 수 있다. 어차피 최적화는 되면 좋지만 안되도 상관은 없는 투명한 처리이기 때문이다.
+
+매크로에서는 ‘그렇게 작동해야 하는 _기능_’인 인라이닝이 fexpr에게는 ‘하면 좋은데 안해도 괜찮은 _최적화_’인 것이 큰 차이다. 그렇다면 매크로의 장점을 고려하여, fexpr와 일반 함수, 매크로 셋 모두를 언어에서 제공하되, 매크로를 fexpr의 서브타입으로 만들 수도 있을 듯하다. 다만 실제로 사용할 컴파일러 구현에서는 매크로는 항상 인라이닝되도록 하면 된다. 이렇게 되면 fexpr을 도입한 가장 큰 이유인 일반성을 잃지 않으면서도, fexpr을 사용할 수 있는 대부분의 경우에 매크로를 대신 사용하도록 권고하여 좀더 나은 성능을 기대하게 할 수도 있다. (Fexpr를 인라이닝 최적화 없이 호출한다면 인자의 평가가 런타임에 이뤄지므로, 즉 그 부분은 컴파일되는 것이 아니라 런타임이 되어서야 인터프리터에 의해 실행될테니 확실히 훨씬 비효율적이긴 할 것이다. 매크로 인라이닝도 어떻게 보면 code bloat이라고 할 수도 있겠지만.)
+
+반면 나는 Io로부터 일부러 가져오지 않은 부분도 있는데, 언어 API를 설계할 때 블럭을 받기 위해 fexpr을 그대로 사용하는 관습이 바로 그것이다. Io의 API는 대부분 고차 함수(higher-order function) 대신 fexpr을 쓰게 되어있는데, 다음과 같은 식으로 쓰이게 된다.
+
+ myList foreach(x, x println)
+
+위 API는 첫번째 인자로 평가되지 않을 변수명을 받고[^4], 루프를 돌 때마다 매번 새로운 임시 environment[^5]를 만들어내고 해당 environment에 첫번째 인자를 통해 받은 변수명을 정의한 뒤, 루프에서 해당 순서의 리스트(여기서는 `myList`) 원소를 할당한 다음, 두번째 인자로 전달받은 평가되지 않은 표현식(즉, 루프 몸통)을 임시 environment에서 평가하는 방식으로 구현되어 있다. 내가 설계했다면 저렇게 fexpr을 쓰는 대신 좀더 vebose하더라도 함수를 받는 형태의 고차 함수로 아래와 같이 쓰도록 설계했을 것이다:
+
+ mylist foreach(block(x, x println))
+
+그 이유는 두 가지가 있다. 첫번째로 fexpr을 구현하는 것보다 고차 함수를 구현하는 것이 훨씬 직관적이며 읽고 쓰기 쉽기 때문이다. Io의 원래 API처럼 `foreach` 메서드를 구현하려면 다음과 같이 해야 한다:
+
+ List foreach := method(
+ argName := call argAt(0) name
+ loopBody := call argAt(1)
+ parentContext := call sender
+ for(i, 0, self size - 1,
+ context := parentContext clone
+ context setSlot(argName, self at(i))
+ loopBody doInContext(context)
+ )
+ )
+
+Io를 잘 모르더라도 이건 좀 너저분하다는 인상을 받을 수 있을 것이다. 반면 같은 Io 코드라고 해도 내가 제안한 것처럼 고차 함수로 디자인했다면 `foreach` 메서드는 아래와 같이 비교적 간결하게 구현 가능하다.
+
+ List foreach := method(f,
+ for(i, 0, self size - 1, f call(self at(i)))
+ )
+
+두번째 문제는 코드를 읽는 입장에서 어떤 인자가 applicative order로 평가되고 어떤 인자가 normal order로 평가되는지 예측하기 힘들어진다는 점이다. 예를 들어 이름을 의미 없게 만든 다음 코드를 보고 `a`, `b`, `c + d` 중 어떤 인자가 얼마나 평가될지 예측할 수는 없다:
+
+ f(a, b, c + d)
+
+이 문제는 fexpr든 매크로든 normal order로 평가되는 함수 호출(혹은 그와 같은 문법으로 가능한 것)이 있는 언어에서는 근본적으로 해결하기 힘들긴 하다. 하지만 언어 API에서 최대한 fexpr을 지양하고 고차 함수를 사용하여, 언어 사용자는 대부분의 호출이 applicative order로 평가될 것이라고 믿을 수 있을 것이다. 더불어 나는 내가 설계한 언어에서는 fexpr 호출과 그렇지 않은 함수의 호출에 대해 다른 코딩 스타일을 사용하도록 유도할 생각이다. 전자는 `fexpr (args)`처럼 여는 괄호 왼쪽에 공백을 주고, 후자는 `func(args)`처럼 공백을 없애도록 하면 읽는 사람 입장에서는 구분이 좀더 편할 것이다.[^6]
+
+[^1]: Io 언어 안에서는 그냥 메서드(method)라고 부른다.
+
+[^2]: ‘quote’나 ‘form’ 같은 표현은 Lisp 용어이고, Io 용어로 말하면 `Message` 객체.
+
+[^3]: 제대로 고민해본 것은 아니지만, 일단 지금 생각으로는 fexpr을 호출하는 모든 코드에 대해 인자 폼(argument forms)을 넘겨서 컴파일 타임에 fexpr 몸통을 평가해보는 것으로 많은 fexpr 호출을 인라이닝할 수 있을 것 같다. S-expression으로 예를 들자면 (`vau``lambda`의 fexpr 버전이며 `env`가 호출하는 쪽의 environment라고 가정하고) 아래와 같은 fexpr을 정의했을 때:
+
+ (define fexpr (vau (a b) env (+ (eval a env) (eval b env))))
+
+ 다음과 같은 fexpr 호출은:
+
+ (fexpr a (+ b c))
+
+ 다음과 같이 인라이닝되는 것이다:
+
+ (+ a (+ b c))
+
+ 평가는 인자로 주어진 quoted forms가 `eval` 함수에 적용되기 전까지만 하면 된다.
+
+[^4]: 따라서 위 코드에서는 `x` 변수가 정의되어 있지 않지만 변수가 없다는 오류가 발생하지 않는다.
+
+[^5]: Environment는 Lisp에서 쓰는 얘기고, Io에서는 context라고 말하는 모양이다.
+
+[^6]: Fexpr을 제공하는 Lisp 방언인 [Kernel][] 같은 경우도 fexpr에 대해서는 `$` 접두어를 붙이는 컨벤션을 사용하여 일반 함수와 fexpr을 구분한다.
+
+[io]: http://www.iolanguage.com/
+[fexpr]: http://blog.dahlia.kr/post/1295597685
+[steve dekorte]: http://dekorte.com/
+[kernel]: http://en.wikipedia.org/wiki/Kernel_(programming_language)
+[1]: https://www.ibm.com/developerworks/kr/library/20100615/index.html
+
1  2337329381-6-0.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-12-16 16:15:32 GMT", "url": "http://blog.dahlia.kr/post/2337329381", "url-with-slug": "http://blog.dahlia.kr/post/2337329381", "format": "markdown", "-slug": "-6-0", "id": "2337329381", "link-url": "http://j.mearie.org/post/2334141016/emoji-on-unicode-6-0", "link-text": "\uc720\ub2c8\ucf54\ub4dc 6.0\uc758 \uc5d0\ubaa8\uc9c0 \uc0ac\ud0dc", "unix-timestamp": "1292516132", "date": "Fri, 17 Dec 2010 01:15:32", "title": "\uc720\ub2c8\ucf54\ub4dc 6.0\uc758 \uc5d0\ubaa8\uc9c0 \uc0ac\ud0dc", "type": "link", "slug": "6-0", "reblog-key": "PgJTzwTo"}
14 2337329381-6-0.md
@@ -0,0 +1,14 @@
+예전에 썼던 글 가운데 하나인 [Unicode 이해의 다양한 단계들][1]에서 맨 마지막 단계에 이렇게 쓴 바 있다:
+
+> 7\. **Unicode 전문가.** 각종 [Unicode 정규화 형식][2]에 대해 잘 알고 있고, 자주 사용하는 몇몇 스크립트들의 바운더리 코드 포인트를 외우고 있으며, Unicode 버전 몇에 어떤 스크립트가 추가되었다든가(예를 들면 5.0 때 파스파 스크립트가 추가됨) 하는 잡다한 것들을 모조리 알고 있다.
+
+그리고 이에 대해 아래와 같이 첨언하기도 했다.
+
+> 7에 해당하는 사람은 거의 본 적이 없다([강성훈][3] 씨 같은 경우 빼면…).
+
+링크한 [유니코드 6.0의 에모지 사태][4]라는 글이 이전에 언급한 “내가 유일하게 봤던 유니코드 이해 7단계에 해당하는 사람”이 쓴 글이다. 역시 명불허전, 이번 Unicode 6.0의 변화 중에 가장 재미있는 부분인 이모지 추가에 관해 굉장히 자세하고 흥미롭게 풀어낸 글이다.
+
+[1]: http://blog.dahlia.kr/post/1268041887
+[2]: http://unicode.org/reports/tr15/
+[3]: http://mearie.org/
+[4]: http://j.mearie.org/post/2334141016/emoji-on-unicode-6-0
1  2399277655-last-fm.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-12-21 07:13:00 GMT", "url": "http://blog.dahlia.kr/post/2399277655", "url-with-slug": "http://blog.dahlia.kr/post/2399277655", "format": "markdown", "regular-title": "Last.fm\uacfc \ub098\uc758 \uc74c\uc545 \uac10\uc0c1", "-slug": "-last-fm", "id": "2399277655", "unix-timestamp": "1292915580", "date": "Tue, 21 Dec 2010 16:13:00", "title": "Last.fm\uacfc \ub098\uc758 \uc74c\uc545 \uac10\uc0c1", "type": "regular", "slug": "last-fm", "reblog-key": "yQfoUcPw"}
36 2399277655-last-fm.md
@@ -0,0 +1,36 @@
+[Last.fm][]을 거의 [4년째][1] 쓰고 있다. 서비스 하나를 4년 이상 쓰는 것이 쉽지 않다. 내가 쓰는 서비스 중에서 4년 넘어가는 게 뭐가 있을까? Google과 Google Reader, Gmail 말고 딱히 없는 것 같다. 하지만 Last.fm은 내가 4년을 쓰고 있으면서도 평소에는 쓴다고 자각하지 못하는 서비스이기도 하다. 그만큼 내 생활에 녹아들었다는 소리가 아니다[^1].
+
+우선 내가 Last.fm을 쓰는 이유를 생각해보자. Last.fm 서비스가 제공하는 기능은 많지만 표면적으로 그들이 내세우는 것은 “당신이 좋아할만한 (그러나 아직 당신이 접하지 못했을) 음악을 추천해준다”라고 생각한다. (정작 유료화된 부분은 상관 없는 쪽이지만.) 하지만 내가 Last.fm을 쓰는 이유는 내 취향에 맞는 새로운 음악들을 발견하기 위해서가 아니다. 나는 정작 4년을 썼으면서 Last.fm으로 새로운 음악을 찾아서 들은 경우가 손에 꼽힐 정도다.
+
+내가 Last.fm을 사용하는 이유는 내가 진짜 어떤 음악을 듣는지 보고 싶어서이다. 잠깐, 조금 이상하게 들릴 수도 있다. 음악을 딴 사람이 틀어주는 것도 아니고, 보통은 자신이 선곡을 해서 듣는데 무얼 듣는지 모른다는 얘기인가? 물론 모두들 자신이 어떤 음악을 많이 듣는지 정도는 알고 있을 것이다.
+
+하지만 자신이 가장 좋아하는 아티스트 둘을 떠올려보자. 당신은 가장 좋아하는 아티스트의 음악을 그 다음으로 좋아하는 아티스트의 음악에 비해 몇 배 정도 많이 재생할까? 전혀 가늠하기 힘들 것이다. 게다가 살아가면서 취향도 변하기 마련이다. 어릴 때는 록 음악을 좋아하여 Led Zeppelin을 많이 들었는데 나이를 먹어서는 재즈가 좋아져서 Miles Davis를 많이 듣게 되었다면, 비교적 최근에 들은 Miles Davis는 횟수는 몰라도 대략 얼마나 많이 들었는지는 감이 잡히는데 어렸을 때 들었던 Led Zeppelin은 막연히 많이 들었다는 생각만 들지 얼마나 많이 들었는지도 감이 잡히지 않는다. 학창 시절에는 수업 시간에 음악을 들을 수 없었으나, 직장에서는 음악을 들을 수 있기 때문에 실제로 재생 횟수에는 자신이 느끼는 것 이상의 큰 격차가 있을 가능성도 높다.[^2]
+
+Last.fm을 쓰는 자각을 하지 못한다고 했는데, 그 이유는 내가 음악을 듣는 습관을 변화시키지도 않고 그런 것을 강요하지도 않기 때문인 것 같다. Last.fm에 가입하고 나서 [Last.fm Scrobbler][2]만 설치하면 그 뒤로 무언가 해야하는 일은 없다. 집에서 듣는 음악은 모두 iTunes로 재생하며, 외출해서는 iPhone이나 iPod으로 음악을 듣는데, 이 모든 재생 기록(언제 무엇을 들었는지)은 Scrobbler가 알아서 수집한다. 자동으로 되기 때문에 내가 서비스에 대해서 해야할 행동이 없다. 즉, 관리 비용이 없다.
+
+수집된 내 재생 기록은 로 데이터(raw data) 그대로 조회할 수 있으며, 내가 이번주에 어떤 아티스트를 제일 많이 들었고 그 회수는 얼마나 되는지, 가장 많이 들은 트랙이 무엇인지 등을 간단하게 그래프로 보여준다. Last.fm이 음악 추천을 괜찮게 해줄 수 있는 것도 결국 이러한 로 데이터를 수집하기 때문이다.
+
+![](http://img196.imageshack.us/img196/766/lastfmtopartists.png "이 글을 쓰는 시점 Last.fm에 표시된 최근 3개월 내가 가장 많이 들은 아티스트 순위")
+
+다만 이렇게 수집된 ‘자신의 음악 감상 실태’를 보는 것이 생각보다 훨씬 재미있다. 왜 재미있냐고? 사실 난 Last.fm 쓰기 전에는 내가 이렇게 오덕 노래를 많이 듣는지 몰랐다. Last.fm에 나온 내 음악 감상 통계를 보고 처음에는 쉽게 받아들일 수가 없었다. 자신이 가장 좋아한다고 ‘생각’하는 것과 정작 손이 가는 트랙과 앨범 사이에는 차이가 나기 때문에 이렇게 통계를 내서 결과를 보면 자신의 예상과는 영 딴판일 가능성이 높다. 나는 Led Zeppelin을 가장 좋아한다고 생각하는데 정작 손이 가장 많이 가는 쪽은 LINKIN PARK나 LUNA SEA[^3]일 수 있는 것이다. 충분히 그럴 수 있다;;[^4]
+
+참고로 이 scrobbling은 최소한 트랙의 반 이상을 들어야 한 번의 재생으로 수집되기 때문에, 평소에 플레이리스트를 셔플 모드로 두고 재생하더라도 충분히 경향성이 잡힌다. 셔플 모드로 듣더라도 별로 안 좋아하는 트랙은 반 이상 듣기 전에 넘기기 십상이므로.
+
+나는 음악을 아직까지도 CD를 사서 구하는데, 그걸 립을 뜬 다음 iTunes로 듣는다. 즉, 남들에 비해 앨범 하나에 지출하는 비용이 크다. 그래서 ‘아직 발견하지 못한 좋은 트랙’을 재발견하는 것에 관심이 갈 수밖에 없는데, 보통 많이 듣는 아티스트의 잘 듣지 않는 트랙은 충분히 들은 뒤에 기피하는 것이기 때문에 재발견하기 힘든 경우가 많으나, 자주 듣지 않는 아티스트의 경우 모든 트랙이 기피 대상이기 때문에 충분히 들어보지 않은 것들이 많아서 트랙을 재발견할 가능성이 좀더 높다. 이렇게 ‘재발견’을 하기 위해서도 Last.fm을 사용하곤 한다. 가끔 아티스트의 순위 아래쪽을 뒤져서 사놓기만 하고 잘 듣지 않았던 앨범을 가끔 다시 들어보는 것이다. (물론 ‘괜히 안 들었던 게 아니였군’하고 생각할 때가 많다.)
+
+----
+
+같이 사는 [선배][3]가 오늘 말해준 아이디어 하나: 클럽 파티를 할 때 참석자에게 Last.fm 계정을 받게 하고, 파티에서는 DJ가 참석자들이 공통적으로 많이 듣는 곡들을 위주로 믹싱을 하면 어떨까? 아무래도 자기가 모르는 곡보다는 이미 잘 아는 곡을 믹싱하는 쪽이 더 흥이 나기 때문에 분위기 만드는 데에 더 좋을 것 같다. (물론 난 클럽과는 거리가 먼 사람이지만…)
+
+[^1]: 그런 의미로 한 말이라면 ‘자각하지 못한다’는 표현은 진부하면서도 부적절한 것이다. 아무리 서비스를 많이 쓴다고 해도 그걸 쓴다는 자각은 사라지지 않는다. Facebook을 아무리 많이 써도 자기가 Facebook을 쓰는지 모르는 사람은 없다. 자각하지 못하는 것은 빠져든 서비스를 쓰느라 하지 못하는 일들이 무엇인지이다. Facebook을 많이 쓰는 사람이 자각하지 못하는 것은 자기가 Facebook을 쓴다는 사실이 아니라 Facebook을 하느라 못하는 일들이 무엇인지이다.
+
+[^2]: 아주 나이브하게 생각하면 재생 회수는 그 트랙이나 앨범, 아티스트를 얼마나 좋아하는지를 그대로 반영한다고 볼 수도 있는데, 실제로 재생이라는 행위에는 감상자의 의지 말고도 많은 환경적인 요인이 변수로 작용하기 때문에 그렇지 않다는 이야기다.
+
+[^3]: 우리나라에서는 아마도 오덕들이 주로 들었을 일본의 90년대 인기 밴드.
+
+[^4]: 오프 토픽이지만 이것에 대해 좀더 얘기를 하자면, 내 음악 감상 통계를 보면 전체 기간에서 1위가 LUNA SEA이다. 처음에는 이걸 부정하고 싶어서 LUNA SEA를 한동안 일부러 듣지 않았건만, 그럼에도 2위와의 격차가 너무 커서 순위를 뒤집을 수는 없었다. 그 뒤로는 내 음악 취향은 일빠 덕후라는 것을 겸허하게 받아들이고 그냥 LUNA SEA가 1위인 채로 냅두고 있다… (그래, 마음 깊은 곳에서는 LUNA SEA의 음악이 좋다고 생각하고 있잖아…?;)
+
+ [last.fm]: http://last.fm/
+ [1]: http://www.last.fm/user/mydahlia
+ [2]: http://www.last.fm/download
+ [3]: http://shinvee.kr/
1  2431357247-irclog.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-12-23 14:45:00 GMT", "url": "http://blog.dahlia.kr/post/2431357247", "url-with-slug": "http://blog.dahlia.kr/post/2431357247", "format": "markdown", "-slug": "-irclog", "id": "2431357247", "link-url": "http://packages.python.org/irclog/", "link-text": "irclog", "unix-timestamp": "1293115500", "date": "Thu, 23 Dec 2010 23:45:00", "title": "irclog", "type": "link", "slug": "irclog", "reblog-key": "6gNEtXTP"}
15 2431357247-irclog.md
@@ -0,0 +1,15 @@
+만들어서 혼자 쓰기만 하고 있던 irclog를 [PyPI에 올렸다.][1] irssi 로그를 웹에서 볼 수 있게 해준다. easy_install이나 pip로 설치할 수 있다.
+
+ $ pip install irclog
+
+설치한 다음에는 아래처럼 웹 서버를 띄울 수 있다. (`<server>`, `<channel>` 등은 저장 경로 패턴.)
+
+ $ python -m irclog.web.server --port 80 \
+ $HOME'/.irssi/log/<server>/<channel>/<date:%Y-%m-%d.log>'
+
+자신이 쓰고 싶은 WSGI 서버가 따로 있으면 그걸 써도 된다. WSGI 애플리케이션은 [`irclog.web.Application`][2] 클래스의 인스턴스를 만들어서 쓰면 된다.
+
+<http://packages.python.org/irclog/>
+
+[1]: http://pypi.python.org/pypi/irclog
+[2]: http://packages.python.org/irclog/irclog/web.html#irclog.web.Application
1  2492201571-python-getter-setter.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-12-28 04:02:30 GMT", "url": "http://blog.dahlia.kr/post/2492201571", "url-with-slug": "http://blog.dahlia.kr/post/2492201571", "format": "markdown", "-slug": "-python-getter-setter", "id": "2492201571", "link-url": "http://www.reddit.com/r/Python/comments/es7g7/diving_in_to_python_from_java_what_should_i_know/", "link-text": "Python\uc5d0\uc11c getter/setter\ub294 \uc8c4\uc545", "unix-timestamp": "1293508950", "date": "Tue, 28 Dec 2010 13:02:30", "title": "Python\uc5d0\uc11c getter/setter\ub294 \uc8c4\uc545", "type": "link", "slug": "python-getter-setter", "reblog-key": "iEYiWFgj"}
37 2492201571-python-getter-setter.md
@@ -0,0 +1,37 @@
+링크한 Reddit (/r/Python) 글타래 [Diving in to Python from Java. What should I know?][1]를 보면 이런 종류의 글타래에는 보통 별로 볼 것 없는 댓글이 많은데 반해, 이 글에는 생각보다 괜찮은 조언이 많이 보인다. `/* … */` 꼴의 여러줄 주석이 없는 이유[^1], `//` 대신 `#`을 주석으로 쓰는 이유[^2], Javadoc 쓰지 말고 [Sphinx][] 쓰라는 얘기, 상속으로만 다형성을 만들게 아니라 덕 타이핑을 잘 활용하라는 얘기 등등. (사실 나도 모든 조언에 전적으로 동의하는 것은 아니다.)
+
+그건 그렇고 내가 하고자 하는 얘기는 사실 아래 인용한 [댓글][2]에 대해서다.
+
+> One thing to be very careful of is that you can write Java in any language. Do not do so! A big initial clue is you start writing getters and setters. (I was guilty of that in my first Python program.)
+
+Java를 쓰던 많은 사람이 다른 언어를 배울 때도 무턱대고 getter/setter를 쓰려고 하는데, 이건 프로퍼티(property) 기능이 없어서 생겨난 Java 언어만을 위한 관용구기 때문에 Python에서 쓸 하등의 이유가 없다.
+
+그럼 어떻게 해야 하나? Python에서는 다음과 같은 옵션이 존재한다.
+
+ 1. 그냥 애트리뷰트(attribute) 그대로 노출한다. Java에서는 하지 않는 짓이다. 왜냐하면 나중에 애트리뷰트에 접근하는 지점에 어떤 부가적인 오퍼레이션을 넣고자 하면 뒤늦게 getter/setter가 필요해질텐데, 그렇게 되면 인터페이스가 달라져서 해당 객체에 의존하는 다른 기존 코드가 깨지기 때문이다. 이 문제는 아래(2)에서 설명하는 프로퍼티(property) 기능 덕분에 걱정할 필요가 없다.
+
+ 또 다른 문제는 Java에 프로퍼티 기능이 있다고 하더라도 코드 수준의 인터페이스는 호환되는데 반해 바이너리 수준의 인터페이스가 호환되지 않아 전체 소스 코드를 다시 컴파일해야 하기 때문이다. (C#을 보라.)
+
+ 2. 애트리뷰트 그대로 노출하다가, 부가적인 로직이 필요해졌을 때만 [`property`][3]를 사용한다. `property`는 기본적으로는 다음과 같이 사용한다.
+
+ age = property(lambda self: (self.birthday - datetime.date.today()).days / 365)
+
+ 데코레이터(decorator) 문법을 이해하고 있다면 저걸 다음과 같이 쓸 수도 있다는 것을 알아챌 것이다.
+
+ @property
+ def age(self):
+ interval = self.birthday - datetime.date.today()
+ return interval.days / 365
+
+ 사용하는 문법은 `object.age`와 같이 애트리뷰트 접근과 **완전히** 똑같기 때문에 처음 디자인 할 때는 애트리뷰트를 그대로 노출하다가 나중에 프로퍼티로 갈아치워도 인터페이스가 달라지지 않는다. 완전히 똑같다는 얘기는 바이트코드 수준에서도 접근 방식이 동일한 바이너리로 다뤄진다는 얘기이다. 즉, C#과 같이 빌드를 다시 해야하는 수고도 없다.
+
+[^1]: 여러줄 주석은 임시로 코드 일부분을 막거나, 코드를 문서화 하는데 사용된다. 어느 쪽이든 3중 인용부호로 된 여러줄 문자열 리터럴을 사용하면 된다. 전자는 최종 코드에는 없을 것이기 때문에 그렇게 해도 되고, 후자는 원래 그런 용도로 [docstring][]을 쓰기 때문에 그렇다.
+
+[^2]: 당연히 Unix의 [셔뱅(shebang)][shebang] 때문.
+
+[sphinx]: http://sphinx.pocoo.org/
+[docstring]: http://en.wikipedia.org/wiki/Docstring
+[shebang]: http://en.wikipedia.org/wiki/Shebang_(Unix)
+[1]: http://www.reddit.com/r/Python/comments/es7g7/diving_in_to_python_from_java_what_should_i_know/
+[2]: http://www.reddit.com/r/Python/comments/es7g7/diving_in_to_python_from_java_what_should_i_know/c1aie9x
+[3]: http://docs.python.org/library/functions.html#property
1  2703234440-subversion-mercurial-1.json
@@ -0,0 +1 @@
+{"date-gmt": "2011-01-11 22:26:32 GMT", "url": "http://blog.dahlia.kr/post/2703234440", "url-with-slug": "http://blog.dahlia.kr/post/2703234440", "format": "markdown", "-slug": "-subversion-mercurial-1", "id": "2703234440", "unix-timestamp": "1294784792", "date": "Wed, 12 Jan 2011 07:26:32", "type": "regular", "slug": "subversion-mercurial-1", "reblog-key": "x2yTxHda"}
55 2703234440-subversion-mercurial-1.md
@@ -0,0 +1,55 @@
+몇년 전 Subversion을 쓰다가 [Mercurial][][^1]로 갈아탄 이후로, DVCS를 이것 저것 써본 것 같다. 가장 많이 쓰는 것은 역시 [Mercurial][]이고, GitHub 때문에 [Git][]도 써봤으며, 최근에는 [Darcs][]도 쓰게 되었다. 각 버전 관리 시스템에 대한 나의 느낌은 이렇다.
+
+### [Mercurial][] (Hg) ###
+
+Subversion과 명령어가 매우 유사하고, Subversion의 명령어 축약도 대부분 지원하기 때문에 당장 쓰기가 가장 편했다. 그리고 가장 오랫동안 사용해왔던 버전 관리 시스템이라 내게는 가장 익숙하다. 처음 Subversion으로부터 갈아탔을 때의 느낌은 “빠르다!”였던 것 같다. 대표적인 호스팅 서비스로는 [Bitbucket][]이 있고, 그걸 쓰지 않고 셀프호스팅하려고 해도 세팅이 매우 간편하다.
+
+Bitbucket이 분명 그리 나쁜 서비스가 아닌데다, 오히려 굉장히 잘 만들어져 있는 서비스인데도 불구하고, [GitHub][]과 종종 비교되기 때문에 상대적으로 안 좋게 느껴지는 것 같다. 하지만 내 생각에는 GitHub이 너무 잘 만들어져 있는 것이지 결코 Bitbucket이 구린 서비스가 아니다. (Bitbucket만한 리파지토리 호스팅 서비스를 찾아보려고 해도 GitHub를 제외하면 딱히 없다는 것을 보면 확실히 그렇다.) 게다가 무료 계정이라도 제한 없이 비공개 리파지토리를 만들 수 있다는 점도 많은 사람에게 장점으로 작용한다. 덕분에 [야간개발팀][lunant] 역시 돈 한푼 들이지 않고 모든 리파지토리를 Bitbucket에서 호스팅받는다.
+
+내 Bitbucket 계정은 <https://bitbucket.org/dahlia>이고, 야간개발팀 페이지는 <https://bitbucket.org/lunant>[^2]이다.
+
+### [Git][] ###
+
+Mercurial보다도 빠르다. 하지만 내게는 Subversion처럼 느리지만 않으면 뭐든 빠르다고 느끼기 때문에 속도가 큰 장점으로 여겨지지 않았다. 명령어는 Subversion이나 Mercurial과 유사성이 전혀 없기 때문에 처음에 익숙해지는데 시간이 걸렸던 것으로 기억한다.
+
+Bitbucket에 비교하면 [GitHub][]이 무척 좋다. 특히 오픈 소스 프로젝트를 프로모션하는 데는 오히려 [Google Project Hosting][]보다 더 효과가 좋은 것 같다. 하지만 비공개 리파지토리를 쓰려면 무조건 결제를 해야 하기 때문에, 딱 오픈 소스 프로젝트를 운영할 때 가장 큰 잇점이 있는 것 같다.
+
+물론 결제를 해서 쓰면 그 만큼의 서비스를 제공받긴 하지만, 그건 GitHub 자체가 좋아서 그렇지 GitHub의 유료 서비스가 딱히 더 좋아서는 아니기 때문에 굳이 결제하고 싶은 마음이 들지는 않는다.
+
+만약 Linus Torvalds가 만든 소프트웨어가 아니였다면 이렇게까지 강세를 보였을까 생각하지만, 애초에 Linus Torvalds가 아니였다면 이렇게 쾌적한 소프트웨어를 만들 수도 없었을테므로 쓸모 없는 가정이다.
+
+내 GitHub 계정은 <https://github.com/dahlia>이고, 야간개발팀 페이지는 <https://github.com/lunant>[^3]에서 볼 수 있다.
+
+### [Darcs][] ###
+
+다른 둘에 비해 역사가 좀더 오래된 초창기 DVCS 소프트웨어이지만, 나는 가장 최근에 사용하기 시작했다. 오래됐기 때문인지 다른 두 버전 관리 시스템에 비해 명령어가 무척 생소하다. 게다가 내가 써본 DVCS 소프트웨어 중에 가장 느리다. 하지만 이 부분은 앞서 얘기했듯 Subversion처럼 느리지만 않으면 내겐 문제가 되지 않기 때문에 별로 단점으로 여겨지지는 않았던 것 같다.
+
+아직은 Mercurial만큼 익숙하지는 않은데 오히려 1년 넘게 써본 Git보다는 더 편한 것 같다. (Darcs를 써본 지는 한 달 좀 넘었음.)
+
+사실 Darcs를 갑자기 쓰게 된 이유는 [Theory of patches][1]인데, 어려워서 읽다가 말았다;; 그리고 Haskell로 작성된 소프트웨어라는 점도 흥미를 부추겼다. 어차피 쓰는데는 별 상관이 없는 요소들이긴 하다.
+
+호스팅 서비스가 별로 없는데, 유명한 것으로 [Patch-Tag.com][]이 있다. 근데 이건 디자인이 아주 별로다. 나는 좀더 최근에 나왔고 개발중이며 서비스 자체가 오픈 소스인 [darcsden][]을 쓰고 있는데 꽤나 만족 중이다. 심플하게 딱 내게 필요한 만큼만 있어서 기분 좋게 사용하고 있다. 게다가 이걸 만들고 운영하는 [Alex Suraci][]는 [Atomo][]라는 Haskell로 구현된 재미있는 언어를 디자인하기도 했는데, IRC의 #atomo 채널에서 말을 걸면 서비스의 장애도 그 자리에서 해결해주기 때문에 개발 초기 단계임에도 잘 쓰고 있다.
+
+내 darcsden 계정은 <http://darcsden.com/dahlia>[^4]이다.
+
+ [^1]: 명령어가 `hg`이기 때문에 보통 Hg라고도 불린다. 명령어의 유래는 물론 수은의 화학 기호인 Hg.
+
+ [^2]: 주로 비공개 저장소들을 관리하고 있기 때문에 볼 게 별로 없다.
+
+ [^3]: Lunant의 오픈 소스 프로젝트는 대부분 GitHub에 공개되어 있다.
+
+ [^4]: 여기에는 내가 디자인하고 있는 언어에 관한 것들만 모아놨다.
+
+ *[DVCS]: Distributed Version Control System
+ [mercurial]: http://mercurial.selenic.com/
+ [git]: http://git-scm.com/
+ [darcs]: http://darcs.net/
+ [github]: http://github.com/
+ [bitbucket]: http://bitbucket.org/
+ [google project hosting]: http://code.google.com/hosting/
+ [patch-tag.com]: http://patch-tag.com/
+ [darcsden]: http://darcsden.com/
+ [Alex Suraci]: http://toogeneric.com/
+ [atomo]: http://atomo-lang.org/
+ [lunant]: http://lunant.com/
+ [1]: http://darcs.net/manual/node9.html
1  2906351242-python-perl.json
@@ -0,0 +1 @@
+{"date-gmt": "2011-01-24 06:49:00 GMT", "url": "http://blog.dahlia.kr/post/2906351242", "url-with-slug": "http://blog.dahlia.kr/post/2906351242", "format": "markdown", "-slug": "-python-perl", "id": "2906351242", "unix-timestamp": "1295851740", "date": "Mon, 24 Jan 2011 15:49:00", "type": "regular", "slug": "python-perl", "reblog-key": "W1HqKjFd"}
42 2906351242-python-perl.md
@@ -0,0 +1,42 @@
+잘 알려져있다시피 Python과 Perl은 상이한 철학을 가지고 있다. 하나의 문제를 해결하는데 여러 방법이 있을 수 있다고 하는 Perl의 철학은 오래되었고 또 매우 널리 퍼져 Ruby의 철학에도 깊은 영향을 주었다.
+
+> There’s more than one way to do the same thing.
+
+반면 Python의 철학은 하나의 문제를 해결하는데는 가장 명확한 하나의 답이 존재한다는 쪽이다.
+
+> There should be one — and preferably only one — obvious way to do it.
+
+내가 비록 Python만큼 Perl에 능숙하지는 않지만, 철학에 있어서는 Perl에 마음이 기운다. 아무튼 갑자기 철학 얘기를 꺼낸 이유는 따로 있다. Perl과 Python의 이러한 철학과 다르게, 막상 구현체의 종류에 있어서는 상대의 철학에 더 가깝다는 생각이 들어서이다.
+
+Python의 경우 JVM 위에서 돌아가는 [Jython][]이 나온 이후 본격적인 다중 구현체가 존재하는 언어[^1]가 되어 현재는 성숙한 구현체만 따져도: 가장 널리 쓰이는 레퍼런스 구현인 [CPython][], CLR에서 돌아가는 [IronPython][], 다른 각도의 병렬 프로그래밍 가능성을 보여준 [Stackless Python][], Nokia의 S60 플랫폼에서 동작하는 [Python for S60][], CPython 3.x에서 머지될 것 같은 [Unladen Swallow][], Python으로 Python을 구현하여 부트스트랩에 성공한 [PyPy][][^2] 등 다양한 것들이 존재하는 상황이다.
+
+반면 Perl 5는 현재까지 명백히 단일구현체이고[^3], Perl 6의 경우 레퍼런스 구현인 [Rakudo][]부터가 아직 명세의 모든 부분을 충족할만큼 성숙하지는 않은 상태라 Python의 여러 구현체가 평균적으로 매우 성숙해있는 것을 감안하면 아직은 좀더 지켜봐야하는 상황이다.
+
+항상 함께 비교되곤 하는 Ruby만 해도 [MRI][], [JRuby][], [IronRuby][], [MacRuby][], [Rubinius][] 등의 여러 구현체가 있는데 유독 Perl만 단일구현체에서 벗어나지 못하고 있는 듯하다. 이렇게 된 원인을 짐작하자면 역시 언어 명세가 복잡해서 구현이 힘들기 때문이 아닌가 싶은데,[^4] 내가 Perl 명세를 잘 알지 못하므로 이에 대해 자세히 아는 분이 계시다면 자세히 설명해주시면 좋을 것 같다.
+
+언어의 표현력이 중요하다고는 생각하지만 역시 이런 걸 생각해보면 Lisp이나 Io처럼 극미니멀리즘으로 가는게 편한 것 같기도 하고.
+
+[^1]: 생각해보면 Lisp 방언들을 제외하면 C, C++, Java, C# 정도 말고는 다중 구현체가 존재하는 언어가 그렇게 많지는 않다.
+
+[^2]: Python 창시자 GvR도 밀어주고 있어서 새로운 레퍼런스 구현이 될 공산이 크다.
+
+[^3]: Perl 6가 나온 마당에 언어 구현자가 Perl 5를 구현할 동기가 생기지 않는 것도 Perl 5의 새로운 구현이 나오기 힘들게 만드데 한몫 하는듯 싶다.
+
+[^4]: 일단 파서부터가 Python이나 Ruby는 명세에 존재하는 BNF를 가지고 파서 제너레이터나 파서 컴비네이터를 쓰면 비교적 쉽게 달성 가능하지만 Perl은 필터 등의 기능 때문에 그렇게 간단하게 구현될 수 있는 문법이 아닌 것으로 알고 있다.
+
+[Jython]: http://www.jython.org/
+[CPython]: http://www.python.org/
+[IronPython]: http://ironpython.net/
+[Stackless Python]: http://www.stackless.com/
+[Unladen Swallow]: http://code.google.com/p/unladen-swallow/
+[Python for S60]: http://www.pys60.org/
+[PyPy]: http://pypy.org/
+[Rakudo]: http://rakudo.org/
+[MRI]: http://www.ruby-lang.org/
+[JRuby]: http://jruby.org/
+[IronRuby]: http://ironruby.codeplex.com/
+[MacRuby]: http://www.macruby.org/
+[Rubinius]: http://rubini.us/
+
+*[GvR]: Guido van Rossum
+*[MRI]: Matz Ruby Implementation
1  2920519622.json
@@ -0,0 +1 @@
+{"link-url": "http://vlaah.com/", "date-gmt": "2011-01-25 05:06:00 GMT", "url": "http://blog.dahlia.kr/post/2920519622", "url-with-slug": "http://blog.dahlia.kr/post/2920519622", "id": "2920519622", "format": "markdown", "photo-url": "http://29.media.tumblr.com/tumblr_lfjplduNJa1qz6t91o1_75sq.png", "-slug": "", "height": "776", "width": "917", "photo-postfix": "png", "photo-urls": ["http://29.media.tumblr.com/tumblr_lfjplduNJa1qz6t91o1_75sq.png", "http://24.media.tumblr.com/tumblr_lfjplduNJa1qz6t91o1_100.png", "http://30.media.tumblr.com/tumblr_lfjplduNJa1qz6t91o1_250.png", "http://25.media.tumblr.com/tumblr_lfjplduNJa1qz6t91o1_400.png", "http://24.media.tumblr.com/tumblr_lfjplduNJa1qz6t91o1_500.png", "http://blog.dahlia.kr/photo/1280/2920519622/1/tumblr_lfjplduNJa1qz6t91"], "unix-timestamp": "1295931960", "date": "Tue, 25 Jan 2011 14:06:00", "photo-link-url": "http://vlaah.com/", "type": "photo", "slug": "", "reblog-key": "C2BoDB9d"}
38 2920519622.md
@@ -0,0 +1,38 @@
+아, 최근 정신없이 작업해놓고 블로그에 소식 올리는 것을 까맣게 잊고 있었다.
+
+[VLAAH][]가 대규모로 업데이트되었다. 정확히는, 내부적으로는 처음부터 다시 만들어졌다. 뭐 그 부분은 사용하는 입장에서는 흥미롭지 않은 부분이지만, 그 외에도 서비스의 여러 개념이 많이 달라졌다. 이게 대해서는 [공지][1]가 이미 되어있으나 짧게 요약하자면 다음과 같은 주요 차이점이 있다.
+
+ - 예전에는 투표가 곧 의견이었으나, 이제는 투표와 의견이 분리되었다. **즉, 투표를 하지 않고 의견만 쓸 수도 있게 되었다.** 예전에는 중복 투표 문제 때문에 하나의 주제에는 한 사람 당 하나의 의견만을 쓸 수 있었고, 이미 의견이 있는데 하나를 더 쓰면 예전에 썼던 의견이 가려졌으나, 이제는 **하나의 주제에 여러 의견을 올릴 수도 있게 되었다.** 또한 명칭도 “의견”에서 “생각”으로 바뀌었다.
+
+ - 예전에는 의견(생각)이 어떤 주제에 관한 것인지를 정하는 숨겨진 필드가 있었으나, 이제는 그런 필드가 있는 대신 생각(의견) 내용에 특정 주제를 언급(링크)하면 그 주제에 관한 생각(의견)으로 취급하게 되었다. 이 부분이 가장 큰 변화인데, 당연히 생각(의견) 내용에는 갯수에 제한 없이 여러 주제를 언급(링크)할 수 있으므로… **생각(의견) 하나가 여러 주제에 걸쳐서 보일 수 있다.**
+
+ - 이전에는 의견(생각)에 부가적으로 태깅을 할 수 있었는데, 이젠 태깅을 따로 하지 못하게 되었다. 예전의 주제 필드와 태그 필드가 명시적인 언급(링크) 문법으로 대체되었다고 이해하면 된다.
+
+ - 이전에는 의견(생각)은 한 줄만 쓸 수 있었는데 이제 여러줄도 된다.
+
+ - 생각(의견) 주제의 모양이 과거에는 `/^?\d+$/` 꼴이었으나 지금은 `/^\*\d+$/` 꼴이 되었다. 쉽게 말해 **물음표(`?`) 대신 별표(`*`)를 쓰게 되었다**는 소리다. 이 블로그를 읽는 대부분의 개발자들은 짐작할 수 있겠지만, 쿼리 스트링과 충돌하는 문제 때문에 그렇게 되었다.
+
+ - 의견(생각) 마크업 문법이 있었는데 주제를 링크(언급)하는 `[[…]]` 빼고는 다 없앴다. 그래도 Twitter처럼 URL을 그냥 붙여두면 자동 링크는 된다. 강조 문법 등이 사라졌다고 생각하면 된다.
+
+그리고 암담한 소식이 하나 있는데 아직 API가 제대로 동작하지 않는다. 게다가 하위호환성을 전혀 제공하지 않고 있다;; 내가 예전에 API 상하위호환 관련해 여러 말을 했던 것을 생각하면 매우 부끄러운 부분이고 반성중이다… 현재는 읽기 전용 API만 제공하는데 아직 명세가 확실히 정해진 것은 아니니 사용하더라도 바뀔 수 있다는 점을 감안해주기 바란다. 아무 페이지에 가서 `Accept` 헤더를 원하는 포맷으로 날려주면 된다. 현재는 XML (`text/xml`), JSON (`application/json`), YAML (`text/yaml`), Property List (`application/plist+xml`), PHP `serialize()`/`unserialize()` 데이터 (`application/vnd.php.serialized`) 정도를 지원하고 있다. 간단하게 `curl`을 사용해서 요청을 날려보면 다음과 같은 응답이 온다.
+
+ $ curl -H"Accept: text/yaml" http://vlaah.com/~dahlia
+ birthday: 1988-08-04
+ followers count: 174
+ followings count: 478
+ gender: male
+ minuses count: 0
+ name: ~dahlia
+ nick: 홍민희
+ normalized name: ~dahlia
+ pluses count: 174
+ thoughts count: 208
+ type: person
+ usual name: ~dahlia
+ $ curl -H"Accept: application/json" http://vlaah.com/VLAAH
+ {"plusesCount": 83, "normalizedName": "vlaah", "name": "VLAAH",
+ "usualName": "VLAAH", "minusesCount": 32, "thoughtsCount": 184,
+ "type": "topic"}
+
+[VLAAH]: http://vlaah.com/
+[1]: http://vlaahkr.blogspot.com/2010/11/vlaah%EB%A5%BC-reboot%ED%95%A9%EB%8B%88%EB%8B%A4.html
BIN  2920519622.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1  2968635983-java-collections-framework.json
@@ -0,0 +1 @@
+{"date-gmt": "2011-01-28 02:05:00 GMT", "url": "http://blog.dahlia.kr/post/2968635983", "url-with-slug": "http://blog.dahlia.kr/post/2968635983", "format": "markdown", "regular-title": "Java Collections Framework", "-slug": "-java-collections-framework", "id": "2968635983", "unix-timestamp": "1296180300", "date": "Fri, 28 Jan 2011 11:05:00", "title": "Java Collections Framework", "type": "regular", "slug": "java-collections-framework", "reblog-key": "upt9rHAO"}
9 2968635983-java-collections-framework.md
@@ -0,0 +1,9 @@
+Java Collections Framework는 확실히 잘 디자인되어 있다. 다음 몇 가지 아쉬운 점을 제외하면.
+
+ - 자료구조가 항상 mutable하다는 가정을 깔고 있다. 예를 들어 immutable list를 구현하려면 `java.util.List`를 구현하고 `add()` 등 자료 구조에 변경을 가하는 연산에 대해서는 `java.lang.UnsupportedOperationException` 예외를 내도록 구현해야 하는데 이건 분명 넌센스다.
+
+ - Python이나 Clojure 같은 언어에서 자주 사용되는 lazy data structure에 대한 고려가 딱히 없다. Clojure나 Python 같은 언어를 보면 확실히 언어에서 제공하는 자료 구조의 laziness는 엄청나게 강력하다는 것을 알 수 있는데, 애초에 Java는 이런 문화와 거리가 멀다.
+
+ - Java에 mixin이나 다중 상속이 없고 인터페이스만 제공되기 때문에, 굳이 구현할 필요 없는 것들을 구현해야 하고 boilerplate code가 등장하기 시작한다. 예를 들어 `java.util.List` 인터페이스의 `toArray()` 메서드는 `iterator()``size()`를 구현했으면 알아서 채워질 수 있는 메서드이다.
+
+역시 Java는 함수형 프로그래밍 스타일에서 배울 것들이 아직 너무나 많아보인다.
1  379524623.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-02-09 06:26:00 GMT", "url": "http://blog.dahlia.kr/post/379524623", "url-with-slug": "http://blog.dahlia.kr/post/379524623", "format": "markdown", "regular-title": "\ube14\ub85c\uadf8 \uc774\uc0ac", "-slug": "", "id": "379524623", "unix-timestamp": "1265696760", "date": "Tue, 09 Feb 2010 15:26:00", "title": "\ube14\ub85c\uadf8 \uc774\uc0ac", "type": "regular", "slug": "", "reblog-key": "r2aZ0m97"}
27 379524623.md
@@ -0,0 +1,27 @@
+원래 WordPress로 만들었던 블로그를 Tumblr로 옮겼다. 주소도 기존에는 blog.dahlia.pe.kr이었는데 이제 blog.dahlia.kr이다(_.pe_가 빠졌다).[^1] 사실 전부터 blog.dahlia.pe.kr라는 주소를 폐기하고 싶었는데 잘됐다.
+
+내가 WordPress를 버리고 Tumblr로 갈아탄 이유는 여러가지가 있다. 일단 더이상 내 서버 위에서 WordPress를 설치하고 운영하는 식으로 셀프호스팅을 하기 싫어졌다. 사실 셀프호스팅을 하는 가장 큰 이유들은 도메인, 플러그인, 맘대로 디자인을 커스터마이즈할 수 있다는 점 따위인데, 어차피 요즘 대부분의 블로그 서비스들은 커스텀 도메인도 지원하는데다[^2] 내가 만 3년을 블로그 써보면 설치한 플러그인이라곤 스팸 차단을 위한 Defensio에 Markdown 서식을 이용하기 위한 PHP Markdown Extra + PHP SmartyPants 뿐이더라. 이건 Markdown을 지원하는 블로그 서비스를 쓰면 해결된다. 디자인 수정 역시 요즘 대부분 블로그 서비스에서는 가능하다.
+
+그래서 이사갈 블로그 서비스들을 이것 저것 찾아봤는데, 나만의 [블로그 소프트웨어 선택 기준][1]에 따라…
+
+ - Tumblr는 커스텀 도메인 기능을 지원한다.[^3]
+ - Markdown을 지원하는 블로그 서비스가 생각보다 많지 않다. 아니, 내가 아는 것 중에서는 사실 Tumblr밖에 없더라. 게다가 Tumblr는 그냥 Markdown이 아니라 Markdown Extra 스펙까지 구현하고 있다.
+ - Tumblr는 애초에 반쯤은 디자인으로 유명해졌다고 볼 수 있을 정도로 고품질의 테마들이 이미 많이 있고, 테마를 내 입맛에 맞게 수정하는 것도 가능하고, 그걸 기여할 수도 있게 되어 있다.
+ - 초고(draft) 기능은 물론, 예약 포스팅 같은 기능까지 있다.
+ - 당연히 RSS를 지원하고 있다. FeedBurner URL로 교체하는 것도 가능하다.
+ - 플러그인 지원 안하는데 나한테는 상관 없다.
+ - Tumblr에는 댓글 기능이 없다. 댓글 기능 있으면 좋지만 없어도 그만이라 나한테는 괜찮다.
+
+…Tumblr를 선택하게 된 것이다. (사실 대부분의 블로그 서비스들이 Markdown 지원 여부에서 탈락된다.)
+
+아무튼 블로그도 이사했으니까 조금 부끄러운 과거는 잊고 새 마음으로 글을 써야겠다.
+
+덧. 예전 블로그는 전체적으로 URL을 유지할 생각이지만, 유지에 노력을 엄청나게 할 것 같진 않으니까 실수로 언젠가 날려먹을지도 모르겠다.
+
+ [^1]: dahlia.pe.kr 도메인은 개인적인 레거시다. 이제는 dahlia.kr을 사용하지만, 예전 URL들을 유지하기 위해 dahlia.pe.kr을 계속 연장하고 있다. 사실은 hongminhee.org 같은 도메인을 쓰고 싶지만 너무 길다.
+
+ [^2]: 사실 나는 URL이 너무 길거나 이상하지만 않으면 크게 신경쓰지 않는다.
+
+ [^3]: 이게 CNAME으로 설정하지 않고 A 레코드 설정하는 식이라 조금 그렇긴 하다.
+
+ [1]: http://blog.dahlia.pe.kr/articles/2008/07/22/%eb%82%b4%ea%b0%80-%eb%b8%94%eb%a1%9c%ea%b7%b8-%ec%86%8c%ed%94%84%ed%8a%b8%ec%9b%a8%ec%96%b4%ec%84%9c%eb%b9%84%ec%8a%a4%eb%a5%bc-%ea%b3%a0%eb%a5%b4%eb%8a%94-%ea%b8%b0%ec%a4%80
1  381793093-vlaah-api.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-02-10 13:34:00 GMT", "url": "http://blog.dahlia.kr/post/381793093", "url-with-slug": "http://blog.dahlia.kr/post/381793093", "format": "markdown", "regular-title": "VLAAH API\uac00 \ub098\uc544\uac08 \uae38", "-slug": "-vlaah-api", "id": "381793093", "unix-timestamp": "1265808840", "date": "Wed, 10 Feb 2010 22:34:00", "title": "VLAAH API\uac00 \ub098\uc544\uac08 \uae38", "type": "regular", "slug": "vlaah-api", "reblog-key": "D831HdNt"}
27 381793093-vlaah-api.md
@@ -0,0 +1,27 @@
+[VLAAH API][1] 1.0을 릴리즈하고 나서 VLAAH API에 대해 여러가지 고민을 했다. 어떻게 하면 VLAAH API를 매력적으로 만들 수 있을 것인가? VLAAH API를 쓰고 싶도록 만들어야 한다. 내 생각에 API를 쓰게 만드는 요인은 크게 세 가지이다.
+
+ 1. **리소스 아웃소싱**(resource outsourcing)—그러니까 자원에 대한 부담을 외부로 돌리기 위해서. 웹 서비스의 API는 이 관점에서 대부분 읽기 위해서든 쓰기 위해서든 **스토리지**의 역할을 해낸다. Flickr API의 주요 기능들 따위가 여기에 속한다.
+ 2. 복잡하고 귀찮은 **계산**(calculation)의 추상화. Google 검색 API 같은 것들이 여기에 속한다.
+ 3. 편하고 마음에 드는 **인터페이스**. 기능이 좀 부족해도 쓰기 편한 인터페이스면 개발자로 하여금 쓰고 싶게 만든다.
+
+VLAAH API는 기본적으로 1에 해당하는 것을 제공한다고(해왔다고) 생각한다. 3에 해당하는 것은 좀 부족할 수도 있겠다는 생각이 최근 들었다. HTTP에 대해 어느 정도 이해하고 내용 협상(content negotiation) 같은 것에 대해 알아야 하기 때문이다. 그리고 단순히 브라우저에서 응답을 확인해보기 힘들다는 지적도 있었다.[^1] 나는 이 부분에 대해서는 추상화된 각 언어별 클라이언트 라이브러리를 제공하는 것으로 어느정도 해결했다고 생각한다.[^2] 게다가 Atom 피드에 API의 주요 기능을 이미 집어넣었기 때문에, 그걸로도 충족되는 부분이다.[^3]
+
+VLAAH API가 부족한 부분은 현재 2에 해당하는 것이다. 이를테면 VLAAH API는 사용자 간의 취향 집합이 어느 정도의 유사도를 가지고 있는지라거나, 두 주제가 어느 정도의 관련성을 가지고 있는지, 아직 투표하지 않은 주제에 대해 사용자가 어느 정도의 선호도를 가질지 예측해주는 식의 기능을 전혀 갖고 있지 않다. 그러니까 현재의 VLAAH API는 사용해봤자 저런 기능들은 클라이언트 코드에서 직접 구현해줘야 한다는 뜻이다. 구현하려고 해도 HTTP를 통해 통신하는 RPC이므로 대량의 데이터를 가지고 분석하기도 힘들다.
+
+그래서 현재 VLAAH 마일스톤의 큰 두 줄기 중 하나는 바로 이러한 계산 추상화를 구현해서 API로 노출시키는 것이다. 빠르면 올해 상반기 내에 오픈할 수 있을 것 같다. 아마 그쯤 되면 버전도 2.0이 되지 않을까 생각한다.
+
+ [^1]: 그래서 `curl` 같은 유틸리티를 써야 한다. 예를 들면 다음과 같이.
+
+ curl -H"Accept: text/xml" \
+ -H"User-Agent: AppName/1.0 (appkey/appkey-goes-here)" \
+ http://vlaah.com/~dahlia
+
+ [^2]: 맨 처음에는 내가 [VLAAH-Ruby][]를 작성했지만 지금은 업데이트가 잘 안되고 있고, [강성훈][2] 씨가 작성한 [vlaah-python][]을 메인으로 생각하고 있다. 둘 다 처음 작성했을 때는 VLAAH API 0.9 스펙만 구현하고 있었지만, VLAAH API 1.0을 만드는 과정에서 내가 직접 코드를 기여하여 vlaah-python이 현재로서는 유일한 VLAAH API 1.0을 구현하는 클라이언트 라이브러리가 되어있다. 그 외에도 Objective-C와 Go로 작성된 것도 있으니, 자세한 것은 [클라이언트 라이브러리 목록][3]을 참고.
+
+ [^3]: <http://vlaah.com/~dahlia/comments/atom.xml>로 접속해보시라. `http://vlaah.com/` 네임스페이스로 부가적인 정보들을 함께 제공하고 있다. 당연히 이 URL에 대해서는 애플리케이션 키 따위를 요구하지 않는다.
+
+ [vlaah-ruby]: http://dahlia.github.com/vlaah-ruby/
+ [vlaah-python]: http://mearie.org/projects/vlaah-python/
+ [1]: http://api.vlaah.com/
+ [2]: http://mearie.org/
+ [3]: http://api.vlaah.com/libraries/
BIN  381959867-1.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1  381959867-1.json
@@ -0,0 +1 @@
+{"link-url": "http://www.flickr.com/photos/hongminhee/sets/72157623275629373/", "date-gmt": "2010-02-10 15:58:00 GMT", "url": "http://blog.dahlia.kr/post/381959867", "url-with-slug": "http://blog.dahlia.kr/post/381959867", "id": "381959867", "format": "markdown", "photo-url": "http://30.media.tumblr.com/tumblr_kxmv0z7eR11qz6t91o1_75sq.jpg", "-slug": "-1", "height": "375", "width": "500", "photo-postfix": "jpg", "photo-urls": ["http://30.media.tumblr.com/tumblr_kxmv0z7eR11qz6t91o1_75sq.jpg", "http://30.media.tumblr.com/tumblr_kxmv0z7eR11qz6t91o1_100.jpg", "http://29.media.tumblr.com/tumblr_kxmv0z7eR11qz6t91o1_250.jpg", "http://27.media.tumblr.com/tumblr_kxmv0z7eR11qz6t91o1_400.jpg", "http://25.media.tumblr.com/tumblr_kxmv0z7eR11qz6t91o1_500.jpg", "http://25.media.tumblr.com/tumblr_kxmv0z7eR11qz6t91o1_500.jpg"], "unix-timestamp": "1265817480", "date": "Thu, 11 Feb 2010 00:58:00", "photo-link-url": "http://www.flickr.com/photos/hongminhee/sets/72157623275629373/", "type": "photo", "slug": "1", "reblog-key": "ZQtozUDX"}
16 381959867-1.md
@@ -0,0 +1,16 @@
+[앞서][1] 댓글 기능은 없어도 괜찮다고 짐짓 아무렇지 않은 척 얘기하긴 했지만, 역시나 없으면 허전하긴 하다. Tumblr에는 댓글 기능이 없는 대신, 사용자가 원할 경우 [DISQUS][]를 붙여서 댓글을 달 수 있게 할 수 있다. DISQUS를 쓸까 잠깐 생각하다가, [VLAAH][]로도 비슷하게 만들 수 있지 않을까 하는 생각이 들었다.
+
+[VLAAH][]에서는 URL도 주제가 될 수 있는데, URL에 대한 투표는 URL 내용에 대한 투표로 볼 수 있으므로[^1] DISQUS 같이 외부에서 삽입 가능한 스크립트를 제공하면 비슷하게 쓸 수 있다. 다른 점이라면,
+
+ 1. VLAAH의 **의견**은 사실 **생각**에 가까우므로, 한 사람이 하나의 주제(여기서는 포스팅)에 대해 하나의 내용만을 쓸 수 있고[^2]
+ 2. 플러스 혹은 마이너스 중 하나를 꼭 선택해야 하는 부담이 있다
+
+는 것 정도? 일단 간단하게 프로토타입을 만들어볼까 하는데 역시 귀차니즘이 문제다. 다른 사람이 만들어줄 수 없으려나?
+
+ [^1]: 당연히 의도한 기능이다.
+
+ [^2]: 그래서 다음 버전의 VLAAH에서는 **의견**(comment)이라는 말 대신 **생각**(thought)이라는 말을 쓰려고 한다.
+
+ [vlaah]: http://www.vlaah.com/
+ [disqus]: http://disqus.com/
+ [1]: /post/379524623
1  412167974-the-heungsub-vlaah-embed.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-02-26 01:07:06 GMT", "url": "http://blog.dahlia.kr/post/412167974", "url-with-slug": "http://blog.dahlia.kr/post/412167974", "format": "markdown", "-slug": "-the-heungsub-vlaah-embed", "id": "412167974", "link-url": "http://the.heungsub.net/post/404573524", "link-text": "The Heungsub: VLAAH Embed \uacf5\uac1c", "unix-timestamp": "1267146426", "date": "Fri, 26 Feb 2010 10:07:06", "title": "The Heungsub: VLAAH Embed \uacf5\uac1c", "type": "link", "slug": "the-heungsub-vlaah-embed", "reblog-key": "VaWzRuo4"}
16 412167974-the-heungsub-vlaah-embed.md
@@ -0,0 +1,16 @@
+> ![VLAAH Embed 로고][1]
+
+> 지난주에 [VLAAH Embed][]를 공개했습니다. VLAAH Embed는 HTML문서에 [VLAAH][] 캔디바를 간단하게 추가할 수 있도록 도와주는 스크립트입니다. 여러분은 VLAAH Embed를 이용해 자신의 글, 어떤 주제, 어떤 사진이 얼마나 인기 있는지 손쉽게 알 수 있습니다.
+
+> VLAAH Embed는 당 블로그에서도 사용하고 있는 코멘트 시스템 [Disqus][]에 아이디어를 얻어 만들게 되었습니다. [사용법][2]도 매우 유사합니다.
+
+> VLAAH Embed의 주소를 서비스와는 독립적으로 유지하기 위해 VLAAH 본서버가...
+
+얼마 전에 [VLAAH로 DISQUS 같은 서비스를 만드는 것][3]에 대해 쓴 적이 있는데, DISQUS 같은 것은 아니지만 해당 페이지 URL에 대해 플러스/마이너스 투표를 할 수 있게 해주는 서비스가 생겼다. (**내가 만든 건 아니다.** 후배가 만들었다.) 질의 문자열(query string)의 인수를 조정해서 URL 말고 다른 주제에 대해서도 투표할 수 있고, 테마도 변경 가능한 모양이다. 쉽게 적용 가능하다.
+
+ [vlaah embed]: http://vlaah-embed.appspot.com/
+ [vlaah]: http://www.vlaah.com/
+ [disqus]: http://disqus.com/
+ [1]: http://media.tumblr.com/tumblr_ky8jdwHXvs1qz6t1v.png
+ [2]: http://vlaah-embed.appspot.com/#usages
+ [3]: http://blog.dahlia.kr/post/381959867
1  417606841.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-02-28 14:27:00 GMT", "url": "http://blog.dahlia.kr/post/417606841", "url-with-slug": "http://blog.dahlia.kr/post/417606841", "format": "markdown", "-slug": "", "id": "417606841", "link-url": "http://www.slideshare.net/dahlia/ss-3295488", "link-text": "\uc0ac\uc6a9\uc790 \uc778\ud130\ud398\uc774\uc2a4\ub85c\uc11c\uc758 \ud504\ub85c\uadf8\ub798\ubc0d \uc5b8\uc5b4", "unix-timestamp": "1267367220", "date": "Sun, 28 Feb 2010 23:27:00", "title": "\uc0ac\uc6a9\uc790 \uc778\ud130\ud398\uc774\uc2a4\ub85c\uc11c\uc758 \ud504\ub85c\uadf8\ub798\ubc0d \uc5b8\uc5b4", "type": "link", "slug": "", "reblog-key": "jHU6mjBa"}
15 417606841.md
@@ -0,0 +1,15 @@
+<object width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100228025243-phpapp01&rel=0&stripped_title=ss-3295488" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=random-100228025243-phpapp01&rel=0&stripped_title=ss-3295488" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
+
+28일(토요일) 어제 [UXCamp Seoul][1]에서 [CREVATE][2]의 [박성연 대표님][3]과 같은 슬롯을 공유하며 함께 발표했던 내용에서 내가 준비했던 부분의 발표 자료다. 처음으로 SlideShare를 써서 공유해본다.
+
+기조(基調)는 대충 이랬는데, 박성연 대표님께서 **UX 이노베이션**을 주제로,
+
+> 사람들이 창의성에 대해 너무 대단한 것으로 여기는 편견을 가지고 있다.
+> 다행히 YouTube와도 같은 것들이 아마추어 아티스트(일반 사용자)와 프로 아티스트의 구분을 모호하게 하고 있다.
+> 개발 직군에서도 기획자와 개발자, 디자이너의 구분도 모호해지는 것이 이노베이션을 만들어낼 수 있다.
+
+라는 식으로(엉터리 요약) 발표를 하셨고, 이어서 “그렇다면 프로그래밍은 어떨까?”하는 식으로 약간 어색하기도 하고 자연스럽기도 한 바톤 터치를 했다. 그 이후의 내용이 내가 한 발표.
+
+ [1]: http://uxcamp.co.kr/
+ [2]: http://www.crevate.com/
+ [3]: http://twitter.com/sypak
1  429521447-arachneng-on-everything.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-03-06 04:10:38 GMT", "url": "http://blog.dahlia.kr/post/429521447", "url-with-slug": "http://blog.dahlia.kr/post/429521447", "format": "markdown", "-slug": "-arachneng-on-everything", "id": "429521447", "link-url": "http://j.mearie.org/post/428642046", "link-text": "Arachneng on Everything: \ud50c\ub808\uc778 \ud14d\uc2a4\ud2b8\uc758 \ubbf8\ub355\uc740 \uc81c\uc57d\uc774\ub2e4. \uc544\uc8fc \uba3c \uc61b\ub0a0, \ud50c\ub808\uc778 \ud14d\uc2a4\ud2b8\uc758 \uc2e4\uc9c8\uc801\uc778 \ud615\ud0dc\uac00 \ud0c0\uc790\uae30 \ucd9c\ub825\uc774\uc5c8\ub358 \ub54c\ub294 \uc57d\uac04 \uc544\ub2c8\uc5c8\uc9c0\ub9cc,...", "unix-timestamp": "1267848638", "date": "Sat, 06 Mar 2010 13:10:38", "title": "Arachneng on Everything: \ud50c\ub808\uc778 \ud14d\uc2a4\ud2b8\uc758 \ubbf8\ub355\uc740 \uc81c\uc57d\uc774\ub2e4. \uc544\uc8fc \uba3c \uc61b\ub0a0, \ud50c\ub808\uc778 \ud14d\uc2a4\ud2b8\uc758 \uc2e4\uc9c8\uc801\uc778 \ud615\ud0dc\uac00 \ud0c0\uc790\uae30 \ucd9c\ub825\uc774\uc5c8\ub358 \ub54c\ub294 \uc57d\uac04 \uc544\ub2c8\uc5c8\uc9c0\ub9cc,...", "type": "link", "slug": "arachneng-on-everything", "reblog-key": "WJ2mtj9o"}
3  429521447-arachneng-on-everything.md
@@ -0,0 +1,3 @@
+> 플레인 텍스트의 미덕은 제약이다. 아주 먼 옛날, 플레인 텍스트의 실질적인 형태가 타자기 출력이었던 때는 약간 아니었지만, 지금의 플레인 텍스트로 복잡한 효과를 넣으려고 하는 사람은 ASCII 아트 만드는 사람 빼고는 없다. 대신 그들은 오로지 제한된 문자만으로 효과적으로 글의 내용을 전달하는 방법을 배우고, 어떻게 단순한 구조화가 글의 내용을 이해하는 데 굉장한 도움을 주는지 알게 되며, 글을 쓸 때 글의 내용에만 집중하는 방법을 익히게 된다. 플레인 텍스트의 제약을 기계가 이해할 수 있도록 정형화하면 마크다운 같은 경량 마크업 언어나 TeX 같은 조판 언어가 나오지만 기본 원칙은 변하지 않는다: 플레인 텍스트로 좋은 글을 쓸 수 없다면 워드프로세서 나부랭이로도 좋은 글을 쓸 수는 없다. 아이들에게 글쓰기보다 워드프로세서를 먼저 가르치면 _안 되는_ 이유 중 하나이다.
+
+서식이 글쓰기의 마(魔)이다. 서식에 신경을 쓰다보면 주화입마(走火入魔)에 빠져 정작 글의 내용은 형편없게 된다.
1  432774871-pastedown-the-pastebin-service-for-markdown-documents.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-03-07 18:30:00 GMT", "url": "http://blog.dahlia.kr/post/432774871", "url-with-slug": "http://blog.dahlia.kr/post/432774871", "format": "markdown", "-slug": "-pastedown-the-pastebin-service-for-markdown-documents", "id": "432774871", "link-url": "http://pastedown.lunant.net/", "link-text": "Pastedown: the pastebin service for Markdown documents", "unix-timestamp": "1267986600", "date": "Mon, 08 Mar 2010 03:30:00", "title": "Pastedown: the pastebin service for Markdown documents", "type": "link", "slug": "pastedown-the-pastebin-service-for-markdown-documents", "reblog-key": "1BbK7YT1"}
23 432774871-pastedown-the-pastebin-service-for-markdown-documents.md
@@ -0,0 +1,23 @@
+최근에 짬짬이 시간을 내서 만들었다. 전부터 스스로 필요하다고 생각했던 서비스다. Markdown 문서 전용 [붙여넣기][1](pastebin) 서비스다. 붙여넣기 서비스가 무엇이냐면, 여러줄로 된 긴 글을 쓰기는 곤란한 IRC 같은 채팅이나 Twitter 같은 마이크로블로그 등에서 인용을 위해 따로 본문 URL을 만들어 링크하는 서비스다.[^1]
+
+로그인을 할 경우 자신의 글을 수정할 수 있게 된다. 그리고 모든 수정 사항은 위키처럼 이력 관리가 된다. 다만 아직 차이점을 보기 위한 diff는 구현하지 않았다. 로그인은 [VLAAH][] 계정으로 하면 된다.
+
+문서를 포크(fork)할 수도 있다. 수정 권한이 없는 문서에 대해 나만의 변경을 가하고 싶을 때 쓰면 된다. 다만 원본 문서에는 누가 포크를 했다고 링크가 걸리고, 포크한 문서에도 원본 문서에 대해 링크가 생기긴 한다.
+
+아직 디자인은 완성되지 않은데다 내가 직접 한 거라서 좀 촌스럽다. 하지만 문서를 보는데는 별 지장이 없다. (IE6에서는 지장이 있을지도…)
+
+서비스 URL은 다음과 같다.
+
+<http://pastedown.lunant.net/>
+
+소스 코드도 AGPL 라이센스 하에 제공한다.
+
+<http://bitbucket.org/lunant/pastedown/>
+
+덧. 참고로 [Google App Engine][2] 위에서 돌아간다.
+
+ [^1]: 아는 사람은 알겠지만, 처음에는 프로그램 소스 코드를 인용하기 위한 것이었다.
+
+ [vlaah]: http://www.vlaah.com/
+ [1]: http://en.wikipedia.org/wiki/Pastebin
+ [2]: http://code.google.com/appengine/
1  433917521-universal-namespace.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-03-08 04:19:00 GMT", "url": "http://blog.dahlia.kr/post/433917521", "url-with-slug": "http://blog.dahlia.kr/post/433917521", "format": "markdown", "regular-title": "Universal Namespace", "-slug": "-universal-namespace", "id": "433917521", "unix-timestamp": "1268021940", "date": "Mon, 08 Mar 2010 13:19:00", "title": "Universal Namespace", "type": "regular", "slug": "universal-namespace", "reblog-key": "MdmkGxBZ"}
33 433917521-universal-namespace.md
@@ -0,0 +1,33 @@
+**유니버설 네임스페이스**(universal namespace)[^1]를 만들고 관리하는 것은 매우 어렵다. 하지만 유니버설 네임스페이스가 필요한 경우는 많다. 이를테면 도서를 위한 ISBN이나 우리가 인터넷을 하면서 흔히 접하는 도메인 네임, URI 따위가 바로 유니버설 네임스페이스인데, 이걸 개인이나 소규모 표준 위원회가 정의하고 관리하는 것은 거의 불가능하다.
+
+특히 숫자 등의 코드로 된 식별자가 아닌, 사람이 비교적 쉽게 알아볼 수 있으면서도 정규화(normalization)가 용이하게 알파누메릭컬(alphanumerical)한 네임스페이스를 정의하고 관리하는 것은 더욱 힘들다. 왜냐하면 사람이 알아볼 수 있게 하는 것이 네임스페이스 디자인의 의도 중 하나라면, 모든 이름이 똑같이 사람에게 알아보기 쉬울 수는 없기 때문에[^2] 충분히 권위적인 사람이나 자원에 더 알아보기 쉬운 이름을 우선적으로 할당해주는 관리 작업이 들어가야 하기 때문이다. 도메인 네임은 그것을 꽤 잘 정의하고 관리한 편인데, 이를테면 마침표(`.`)로 구분하는 위계(hierarchy)를 만들고 국가 등의 공인된 기관에 그 관리 구역을 위임하는 식으로 이루어졌기 때문이다. 이렇게 되면 관리 비용의 총량이 변하는 것은 아니지만, 관리 비용은 전체적으로 분산되기 때문에 어느 누가 크게 부담하는 일은 피할 수 있다. 그럼에도 대부분의 도메인 네임은 현금에 의해 거래되기 때문에 권위를 측정하는 일을 경제 시스템에 위임했다고 볼 수 있다. 현존하는 가장 잘 정의되고 관리되는 유니버설 네임스페이스라고 할 수 있는 도메인 네임도 현실적으로 모든 것을 통제하지는 못하고 있다는 뜻이다.
+
+URI나 이메일 주소 같은 경우도 유니버설 네임스페이스라고 할 수 있지만, 사실은 둘 모두 도메인 네임에 이미 크게 위임을 한 상태이기 때문에, 도메인 네임 안쪽에서의 네임스페이스를 관리하는 정도의 부담이다.
+
+글을 읽으면서 느낀 사람도 있겠지만, 이 네임스페이스라는 것은 관리 책임을 위임할 수 있다는 특징이 있다. 이것은 굉장히 중요한 특성인데, 이 위임이라는 것을 잘 엮으면 적은 비용(혹은 분산된 비용)으로 충분히 쓸만한 유니버설 네임스페이스를 누구나 얻을 수 있기 때문이다.
+
+예를 들면 Java 언어의 경우 패키지의 고유성을 위해 유니버설 네임스페이스가 필요했는데, 이를 위해 패키지 네임을 도메인 네임의 역순으로 정의하길 권고하는 것으로 어느 정도 해결했다. 이를테면 내가 어떤 패키지를 만든다면 `kr.dahlia.xxx`와 같은 이름을 쓰면 되는 것이다. 하지만 도메인 네임의 규칙과 Java 식별자의 규칙은 서로 다르기 때문에[^3] 개인적으로는 썩 좋은 위임이라고 생각하지 않는 사례이다.
+
+또 예를 들자면 [OpenID][] 표준은 개인 식별자의 고유성을 확보하기 위해 URL을 그대로 위임한 바 있다. 그 외에도 많은 웹 서비스들이 사용자 계정 이름으로 이메일 주소를 사용하는 것으로 서비스 내에서의 이름 중복 문제를 위임해버리는 경우는 흔히 찾아볼 수 있다.
+
+사실 내가 갑자기 유니버설 네임스페이스에 대해 썰을 푼 이유는, 내가 만드는 언어의 패키지 네임스페이스를 어떻게 관리할지 고민하고 있기 때문이다. “방금 네가 말했잖아. 네임스페이스는 위임하면 된다며”라고 말할 수 있겠지만, 그게 말처럼 쉬운 문제는 또 아니다. 앞서 말했다시피 도메인 자체는 권위를 평가하고 높은 권위에 좋은 이름을 주는 관리 책임을 자본에 어느 정도 위임하여 회피했기 때문에, 도메인 네임을 사용할 경우 그러한 문제도 고스란히 가져오게 된다. 즉 좋은 라이브러리 이름을 얻기 위해서는 돈이 필요해지는 것이다. 또한 Java의 사례를 보면 알 수 있는 것인데, 애초에 도메인 네임은 특정 언어로 작성된 라이브러리 패키지를 위해 디자인된 네임스페이스가 아니기 때문에 필요 이상으로 이름이 길어지게 된다. 웬만하면 `xxx`라고 할 수 있는 것을 `kr.dahlia.xxx`라는 식으로 늘려 써야 하는 경우가 많다.
+
+Perl의 [CPAN][]의 경우 프로그래밍 언어 중에서는 그러한 문제를 가장 열심히 해결하려고 시도한 경운데, 대신 CPAN 모듈들은 재치있고 특이한 이름을 가지지 못하는 경우가 많다. 또한 CPAN 같은 방식으로 가려면 공동체의 관리 비용이 든다.
+
+그래서 결론이 뭐냐하면, 사실 결론은 없고 그냥 내가 요즘 이런 고민을 하고 있다는 얘기를 써보고 싶었다.
+
+ [^1]: 한국어로 뭐라고 해야할지 고민했으나 결국 찾지를 못했다.
+
+ [^2]: 이를테면 `apple`과 `a8jkd`은 글자수는 같지만 전자는 사람이 알아보기 쉬운 반면,
+ 후자는 알아보기도 어렵고 읽거나 외우기도 힘들다. 읽기 힘들기 때문에 음성 통화 등으로
+ 다른 사람에게 전달하는 것도 힘들다.
+
+ [^3]: 이를테면 `1st-name.com`을 Java 식별자로는 표현할 수 없다. 하이픈도 포함되어 있고, 숫자로 시작하기 때문이다.
+
+ [openid]: http://openid.net/
+ [cpan]: http://www.cpan.org/
+
+ *[ISBN]: International Standard Book Number
+ *[URL]: Uniform Resource Locator
+ *[URI]: Uniform Resource Identifier
+ *[CPAN]: Comprehensive Perl Archive Network
BIN  436379667-pengdo-jiyul.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1  436379667-pengdo-jiyul.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-03-09 06:52:47 GMT", "url": "http://blog.dahlia.kr/post/436379667", "url-with-slug": "http://blog.dahlia.kr/post/436379667", "id": "436379667", "format": "markdown", "photo-url": "http://28.media.tumblr.com/tumblr_kywuw9v6bF1qzr04eo1_75sq.jpg", "-slug": "-pengdo-jiyul", "height": "531", "width": "400", "photo-postfix": "jpg", "photo-urls": ["http://28.media.tumblr.com/tumblr_kywuw9v6bF1qzr04eo1_75sq.jpg", "http://28.media.tumblr.com/tumblr_kywuw9v6bF1qzr04eo1_100.jpg", "http://26.media.tumblr.com/tumblr_kywuw9v6bF1qzr04eo1_250.jpg", "http://25.media.tumblr.com/tumblr_kywuw9v6bF1qzr04eo1_400.jpg", "http://25.media.tumblr.com/tumblr_kywuw9v6bF1qzr04eo1_400.jpg", "http://25.media.tumblr.com/tumblr_kywuw9v6bF1qzr04eo1_400.jpg"], "unix-timestamp": "1268117567", "date": "Tue, 09 Mar 2010 15:52:47", "type": "photo", "slug": "pengdo-jiyul", "reblog-key": "edPPpPvG"}
8 436379667-pengdo-jiyul.md
@@ -0,0 +1,8 @@
+<p><a href="http://p-paradigm.com/post/436264070/jiyul" class="tumblr_blog">pengdo</a>:</p>
+
+<blockquote><p><a href="http://tbr.jeeeyul.net/post/436055917">jiyul</a>:</p>
+<blockquote>
+<p>애플과 블랙베리가 그저 과일이었던 시절, 삶은 훨씬 더 쉬웠어.</p>
+</blockquote></blockquote>
+
+<p></p>
1  449446558-vlaah-9.json
@@ -0,0 +1 @@
+{"link-url": "http://www.vlaah.com/", "date-gmt": "2010-03-15 06:25:00 GMT", "url": "http://blog.dahlia.kr/post/449446558", "url-with-slug": "http://blog.dahlia.kr/post/449446558", "id": "449446558", "format": "markdown", "photo-url": "http://26.media.tumblr.com/tumblr_kzb8ioBKp11qz6t91o1_75sq.png", "-slug": "-vlaah-9", "height": "856", "width": "972", "photo-postfix": "png", "photo-urls": ["http://26.media.tumblr.com/tumblr_kzb8ioBKp11qz6t91o1_75sq.png", "http://28.media.tumblr.com/tumblr_kzb8ioBKp11qz6t91o1_100.png", "http://30.media.tumblr.com/tumblr_kzb8ioBKp11qz6t91o1_250.png", "http://26.media.tumblr.com/tumblr_kzb8ioBKp11qz6t91o1_400.png", "http://25.media.tumblr.com/tumblr_kzb8ioBKp11qz6t91o1_500.png", "http://blog.dahlia.kr/photo/1280/449446558/1/tumblr_kzb8ioBKp11qz6t91"], "unix-timestamp": "1268634300", "date": "Mon, 15 Mar 2010 15:25:00", "photo-link-url": "http://www.vlaah.com/", "type": "photo", "slug": "vlaah-9", "reblog-key": "n6IDljef"}
3  449446558-vlaah-9.md
@@ -0,0 +1,3 @@
+오랜만에 [VLAAH][] 대문을 바꿨다. 오랫동안 “디스트릭트 9”이 첫 화면에 있다보니 서비스가 망한 느낌이 너무 강했기 때문이다.
+
+ [vlaah]: http://www.vlaah.com/
BIN  449446558-vlaah-9.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  464608892.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1  464608892.json
@@ -0,0 +1 @@
+{"link-url": "http://www.flickr.com/photos/hongminhee/sets/72157623530288849/", "date-gmt": "2010-03-22 02:05:59 GMT", "url": "http://blog.dahlia.kr/post/464608892", "url-with-slug": "http://blog.dahlia.kr/post/464608892", "id": "464608892", "format": "markdown", "photo-url": "http://28.media.tumblr.com/tumblr_kznv60nUO61qz6t91o1_75sq.jpg", "-slug": "", "height": "500", "width": "375", "photo-postfix": "jpg", "photo-urls": ["http://28.media.tumblr.com/tumblr_kznv60nUO61qz6t91o1_75sq.jpg", "http://30.media.tumblr.com/tumblr_kznv60nUO61qz6t91o1_100.jpg", "http://26.media.tumblr.com/tumblr_kznv60nUO61qz6t91o1_250.jpg", "http://27.media.tumblr.com/tumblr_kznv60nUO61qz6t91o1_400.jpg", "http://27.media.tumblr.com/tumblr_kznv60nUO61qz6t91o1_400.jpg", "http://27.media.tumblr.com/tumblr_kznv60nUO61qz6t91o1_400.jpg"], "unix-timestamp": "1269223559", "date": "Mon, 22 Mar 2010 11:05:59", "photo-link-url": "http://www.flickr.com/photos/hongminhee/sets/72157623530288849/", "type": "photo", "slug": "", "reblog-key": "fFeqKzWc"}
1  464608892.md
@@ -0,0 +1 @@
+요즘 바나나맛우유에 꽂혀서 매일 먹다보니 집에 다 먹고 빈 바나나맛우유 통이 널려있길래 그걸 보고 영감(?)을 얻어서 찍었다. 작품명은 **공동묘지**.
1  469328703-vlaah-api-part-1-api.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-03-24 03:01:00 GMT", "url": "http://blog.dahlia.kr/post/469328703", "url-with-slug": "http://blog.dahlia.kr/post/469328703", "format": "markdown", "-slug": "-vlaah-api-part-1-api", "id": "469328703", "link-url": "http://www.ibm.com/developerworks/kr/library/opendw/20100323/index.html", "link-text": "VLAAH API\ub85c \uc27d\uac8c \ud22c\ud45c \uae30\ub2a5 \uad6c\ud604\ud558\uae30, Part 1: \uc544\ud1b0 API \ud65c\uc6a9", "unix-timestamp": "1269399660", "date": "Wed, 24 Mar 2010 12:01:00", "title": "VLAAH API\ub85c \uc27d\uac8c \ud22c\ud45c \uae30\ub2a5 \uad6c\ud604\ud558\uae30, Part 1: \uc544\ud1b0 API \ud65c\uc6a9", "type": "link", "slug": "vlaah-api-part-1-api", "reblog-key": "46TWjtVT"}
1  469328703-vlaah-api-part-1-api.md
@@ -0,0 +1 @@
+한국 IBM developerWorks에 VLAAH API를 주제로 기고했다. 제목에서 보면 알 수 있지만 시리즈로 기획했고, 그 중 첫번째 글이다.
1  473660929-vlaah.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-03-26 01:15:00 GMT", "url": "http://blog.dahlia.kr/post/473660929", "url-with-slug": "http://blog.dahlia.kr/post/473660929", "format": "markdown", "-slug": "-vlaah", "id": "473660929", "link-url": "http://www.slideshare.net/dahlia/vlaah-3551537", "link-text": "\ubcf4\ub178\ubcf4\ub098\uc787 VLAAH \ubc1c\ud45c", "unix-timestamp": "1269566100", "date": "Fri, 26 Mar 2010 10:15:00", "title": "\ubcf4\ub178\ubcf4\ub098\uc787 VLAAH \ubc1c\ud45c", "type": "link", "slug": "vlaah", "reblog-key": "UvedNHRa"}
8 473660929-vlaah.md
@@ -0,0 +1,8 @@
+<object width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=vlaah-100325105643-phpapp02&stripped_title=vlaah-3551537" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=vlaah-100325105643-phpapp02&stripped_title=vlaah-3551537" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
+
+소셜 스타트업들의 모임인 [보노보나잇][1]에서 페차쿠차 형식으로 [VLAAH][] 발표를 했다. 사실 **소셜 스타트업**에서의 **소셜**이라는 말이 **사회적 기업** 같은 얘기를 할 때의 **소셜**이었는데 애초에 신청할 때부터 조금 잘못 이해하고 있던 게 사실이다. 그래서 VLAAH를 가지고 어떻게 연관성 있게 말을 할까 하다가 조금 망한 발표.
+
+발표 형식은 페차쿠차 형식으로, 슬라이드 하나에 20초를 쓰고, 총 20 슬라이드를 지켜야 했다.
+
+ [1]: http://bonobonight.tumblr.com/
+ [vlaah]: http://www.vlaah.com/
1  481322492.json
@@ -0,0 +1 @@
+{"quote-source": "<a href=\"http://lists.w3.org/Archives/Public/public-html/2010Jan/0107.html\">HTMLWG Mailing List</a> (via <a href=\"http://nohmad.tumblr.com/\" class=\"tumblr_blog\">nohmad</a>)", "date-gmt": "2010-03-29 09:06:18 GMT", "url": "http://blog.dahlia.kr/post/481322492", "url-with-slug": "http://blog.dahlia.kr/post/481322492", "format": "markdown", "-slug": "", "id": "481322492", "unix-timestamp": "1269853578", "date": "Mon, 29 Mar 2010 18:06:18", "type": "quote", "slug": "", "reblog-key": "Owbphvqv"}
1  481322492.md
@@ -0,0 +1 @@
+구현과 명세는 함께 어우러져 달콤한 춤을 춰야 한다. 명세가 끝나기 전에 구현이 나오는 것은 특정 구현의 세부에 의존하여 명세를 제한하게 되므로 바람직하지 않다. 구현이 끝나기 전에 명세가 완료되는 것도 바람직하지 않다. 명세의 저자가 그 구현을 경험해볼 수 있어야 하며, 피드백도 필요하기 때문이다. 여기에 피할 수 없는 긴장이 있다. 그러나 우리는 이 길을 헤쳐 나가야 한다.
1  488743743-mockcache.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-04-01 09:53:00 GMT", "url": "http://blog.dahlia.kr/post/488743743", "url-with-slug": "http://blog.dahlia.kr/post/488743743", "format": "markdown", "-slug": "-mockcache", "id": "488743743", "link-url": "http://pypi.python.org/pypi/mockcache", "link-text": "mockcache", "unix-timestamp": "1270115580", "date": "Thu, 01 Apr 2010 18:53:00", "title": "mockcache", "type": "link", "slug": "mockcache", "reblog-key": "4fsPDjJI"}
31 488743743-mockcache.md
@@ -0,0 +1,31 @@
+요즘에 memcached 쓸 일이 많은데, 로컬에서 작업할 때 memcached 설치하기 참 귀찮다. 어차피 memcached는 실제 배포했을 때만 작동하면 된다. 그래서 [mockcache][]라는 것을 만들었다. 테스트 용도로 써도 되는데, 꼭 그런 용도는 아니고 memcached 클라이언트 라이브러리가 하나도 없을 때 이걸 쓰도록 fallback을 구성할 때도 좋다.
+
+ try:
+ import memcache
+ except ImportError:
+ import warnings
+ import mockcache as memcache
+ warnings.warn("imported mockcache instead of memcache; cannot find "
+ "memcache module")
+
+ mc = memcache.Client(["127.0.0.1:11211"])
+
+Python에서 쓸 수 있는 memcached 클라이언트 구현이 여럿 있는데, Python 특유의 낙관적인 인터페이스 문화 덕분에 별 표준이 있는 것도 아닌데도 다들 거의 동일한 인터페이스를 제공한다.[^1] 그것에 착안해서 만든 것이라 mockcache 역시 그 인터페이스를 따른다.
+
+내부적으로는 그냥 `dict` 객체를 하나 생성해서 그걸로 상태를 관리하는 식이다. 그래도 expiration 같은 것도 구현은 했다.
+
+PyPI에 올렸으니 `easy_install` 등으로 설치가 가능할 것이다. (관리자 권한으로 실행해야 한다.)
+
+ $ easy_install mockcache
+
+Bitbucket에 소스 코드를 올렸다. MIT 라이센스다. <http://bitbucket.org/lunant/mockcache/> Mercurial로 클론할 수 있다.
+
+ $ hg clone http://bitbucket.org/lunant/mockcache/
+
+버그 등의 이슈는 [Bitbucket에서 제공하는 이슈트래커][1]에 올려주시라.
+
+
+ [^1]: 그래서 보통 `import` 문만 수정하면 어떻게든 비슷하게 쓸 수 있는 것이다. 모듈 단위의 폴리모피즘(polymorphism)이랄까.
+
+ [mockcache]: http://pypi.python.org/pypi/mockcache
+ [1]: http://bitbucket.org/lunant/mockcache/issues/new/
1  505107383-php.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-04-08 06:30:30 GMT", "url": "http://blog.dahlia.kr/post/505107383", "url-with-slug": "http://blog.dahlia.kr/post/505107383", "format": "markdown", "-slug": "-php", "id": "505107383", "unix-timestamp": "1270708230", "date": "Thu, 08 Apr 2010 15:30:30", "type": "regular", "slug": "php", "reblog-key": "PKmBp6YX"}
23 505107383-php.md
@@ -0,0 +1,23 @@
+예전에 알바했을 때 PHP 코딩을 하는데, 옆 사람의 배열 쓰는 컨벤션이 많이 이상했다.
+
+ $array = array(
+ 'element'
+ , 'element'
+ , 'element'
+ , 'element'
+ , 'element'
+ , 'element'
+ , 'element'
+ );
+
+왜 쉼표를 앞에 쓰냐고 물어봤더니 vim에서 `dd`(한줄 잘라내기) 등의 줄단위 편집을 해도 문법이 깨지지 않게 하기 위해서라고 했다. 그땐 그냥 어이없어서 웃고 넘겼는데 나중에 생각해보니 저건 정말 어리석은 스타일이다. 왜냐면 요즘 대부분 언어에서는 배열/리스트 리터럴에서 맨 마지막에 쉼표를 허용하기 때문이다.
+
+ $array = array(
+ 'element',
+ 'element',
+ 'element',
+ 'element',
+ 'element',
+ );
+
+이렇게 쓸 수도 있는 것이다. 이렇게 써도 줄단위 편집은 쉽게 가능하다. 게다가 그 사람이 썼던 멍청한 방법은 맨 첫번째 요소를 `dd`로 지우면 문법이 깨진다.
1  505875176-1-internet-explorer-6.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-04-08 15:16:00 GMT", "url": "http://blog.dahlia.kr/post/505875176", "url-with-slug": "http://blog.dahlia.kr/post/505875176", "format": "markdown", "-slug": "-1-internet-explorer-6", "id": "505875176", "unix-timestamp": "1270739760", "date": "Fri, 09 Apr 2010 00:16:00", "type": "regular", "slug": "1-internet-explorer-6", "reblog-key": "9XaAFPBd"}
10 505875176-1-internet-explorer-6.md
@@ -0,0 +1,10 @@
+[이렇게][1] 적긴 했지만, Internet Explorer 6 이하의 JavaScript 구현에서는 배열 리터럴 등에서 마지막 쉼표를 허용하지 않는다. 이건 여러번 당해서 이미 알고 있었다…….
+
+그리고 [종텐][jong10] 님의 제보에 따르면, Erlang도 허용하지 않는다고 한다. 심지어 언어 창시자인 Joe Armstrong가 쉼표를 줄 처음에 쓰는 스타일을 권장하기까지 한다더라.[^1]
+
+덧. 보통 댓글창이 있어도 귀찮아도 안 다는데… 포스팅에 대한 댓글을 이메일로 보내주신 종텐 님께 감사를…;; ㅋㅋ
+
+ [^1]: 출처 없음. 종텐 님께 들은 이야기.
+
+ [jong10]: http://www.jong10.com/
+ [1]: http://blog.dahlia.kr/post/505107383
1  514838935-vlaah.json
@@ -0,0 +1 @@
+{"link-url": "http://www.vlaah.com/", "date-gmt": "2010-04-12 04:18:34 GMT", "url": "http://blog.dahlia.kr/post/514838935", "url-with-slug": "http://blog.dahlia.kr/post/514838935", "id": "514838935", "format": "markdown", "photo-url": "http://26.media.tumblr.com/tumblr_l0qxaytQwQ1qz6t91o1_75sq.png", "-slug": "-vlaah", "height": "813", "width": "1014", "photo-postfix": "png", "photo-urls": ["http://26.media.tumblr.com/tumblr_l0qxaytQwQ1qz6t91o1_75sq.png", "http://24.media.tumblr.com/tumblr_l0qxaytQwQ1qz6t91o1_100.png", "http://26.media.tumblr.com/tumblr_l0qxaytQwQ1qz6t91o1_250.png", "http://24.media.tumblr.com/tumblr_l0qxaytQwQ1qz6t91o1_400.png", "http://30.media.tumblr.com/tumblr_l0qxaytQwQ1qz6t91o1_500.png", "http://blog.dahlia.kr/photo/1280/514838935/1/tumblr_l0qxaytQwQ1qz6t91"], "unix-timestamp": "1271045914", "date": "Mon, 12 Apr 2010 13:18:34", "photo-link-url": "http://www.vlaah.com/", "type": "photo", "slug": "vlaah", "reblog-key": "5NZE8YgU"}
5 514838935-vlaah.md
@@ -0,0 +1,5 @@
+[VLAAH][] 홈을 조금 개편했다. 광고도 달아봤다.
+
+뭐 난 이 부분에 커밋한 것은 하나도 없지만…
+
+ [vlaah]: http://www.vlaah.com/
BIN  514838935-vlaah.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1  532183323-iphone.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-04-19 02:38:00 GMT", "url": "http://blog.dahlia.kr/post/532183323", "url-with-slug": "http://blog.dahlia.kr/post/532183323", "format": "markdown", "-slug": "-iphone", "id": "532183323", "unix-timestamp": "1271644680", "date": "Mon, 19 Apr 2010 11:38:00", "type": "regular", "slug": "iphone", "reblog-key": "G14B4wzI"}
17 532183323-iphone.md
@@ -0,0 +1,17 @@
+모바일 앱 개발에 대한 얘기가 들리지 않는 날이 없다. 대개 iPhone의 성공을 단일 플랫폼과 적절한 통제에 기인한다고들 말하는데, 맞는 말이긴 하다. 해상도나 장비에 포함된 기능 집합까지 똑같거나 거의 같기 때문에 배포할 때 곯머리도 안 썩고 만들 때도 편한 것이다.
+
+하지만 그것과 별개로 나는 여러 환경에 대한 고려가 좀더 나은 디자인을 만든다고 믿는 사람이다. 여러 환경을 고려하다보면 결국 적절한 추상화를 하게 되는데, 객체 지향 프로그래밍이라면 다형성을 적절히 쓸 것이고, 함수형 프로그래밍이라면 특수화를 잘 쓸 것이다.
+
+단위 테스트가 있는 코드가 대개 없는 코드보다 디자인이 나은 경우가 많다. 왜 그렇냐면 단위 테스트 자체가 클라이언트 코드를 두 개 이상으로 만드는 효과를 주기 때문이다. 클라이언트 코드가 두 개 있는 것과 세 개 있는 것은 별 차이가 없지만, 하나 있는 것과 여럿 있는 것은 꽤 크게 차이가 난다. 클라이언트 코드라면 호출하는 쪽, 사용하는 쪽을 얘기하는데 결국 클라이언트 코드 자체가 환경이라는 말이다.
+
+하지만 모바일 앱을 만드는데는 이런건 부질 없는 이야기다. 모바일 앱은 대체로
+
+ - 적은 비용으로
+ - 짧은 기간에
+ - 적당한 완성도로
+
+마무리 짓는게 관건[^1]인데, 여러 환경 고려하며 품질 높고 좋은 디자인의 코드를 만들어 내다간 반쯤 농담으로 대작 MMORPG 만드는 비용이 들어가게 된다. 후 하고 불면 불꽃이 흔들리는 앱 하나 만들겠다고 그런 비용을 지불하려는 사람은 별로 없을 것이다.
+
+결론: Apple은 사악하고 Android는 갈 길이 멀다.
+
+ [^1]: 사실 그렇다기 보다는 트렌드.
1  537084437-io-part-1.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-04-21 01:37:08 GMT", "url": "http://blog.dahlia.kr/post/537084437", "url-with-slug": "http://blog.dahlia.kr/post/537084437", "format": "markdown", "-slug": "-io-part-1", "id": "537084437", "link-url": "https://www.ibm.com/developerworks/kr/library/opendw/20100420/index.html", "link-text": "\uc791\uace0 \uc544\ub984\ub2e4\uc6b4 \uc5b8\uc5b4 Io, Part 1: \uc124\uce58\uc640 \uae30\ubcf8 \ubb38\ubc95", "unix-timestamp": "1271813828", "date": "Wed, 21 Apr 2010 10:37:08", "title": "\uc791\uace0 \uc544\ub984\ub2e4\uc6b4 \uc5b8\uc5b4 Io, Part 1: \uc124\uce58\uc640 \uae30\ubcf8 \ubb38\ubc95", "type": "link", "slug": "io-part-1", "reblog-key": "yZ1XuJqa"}
5 537084437-io-part-1.md
@@ -0,0 +1,5 @@
+지난번 한국 IBM developerWorks에 썼던 [VLAAH API 관련 글][1]을 미뤄두고 같은 곳에 또다른 연재를 시작했다. 내가 꽤나 좋아라 하는(했던?) 언어인 Io 튜토리얼이다. 사실 VLAAH API에 대한 연재를 계속하려고 했는데, 요즘 VLAAH API에 작업이 한창이라 훗날 틀린 내용이 될 지도 모르겠다 싶어[^1] 일단은 Io 연재를 대신 시작했다.
+
+ [^1]: 그리고 요즘엔 또 지긋지긋한 것도 있어서…
+
+ [1]: http://blog.dahlia.kr/post/469328703
1  537294542-ui.json
@@ -0,0 +1 @@
+{"quote-source": "<a href=\"http://j.mearie.org/post/537276168\" class=\"tumblr_blog\">Arachneng on Everything</a>\n\n\uc704 \uc774\uc57c\uae30\ub294 \ub370\uc2a4\ud06c\ud0d1 \ud658\uacbd\uc5d0 \uad00\ud55c \uc774\uc57c\uae30\uc9c0\ub9cc, [Facebook][]\uc774 \uc2e4\uc81c\ub85c \ub3c8 \uc548\ub4e4\uc774\uace0 \uc0ac\uc6a9\uc790\ub4e4\uc758 \ucc38\uc5ec\ub97c \ud1b5\ud574 \uc5ec\ub7ec \uc5b8\uc5b4\ub85c \ubc88\uc5ed\uc744 \uc9c4\ud589\ud560 \uc218 \uc788\uc5c8\ub2e4. (\ubb3c\ub860 \uadf8\ub7ec\ud55c \uc2dc\uc2a4\ud15c\uc744 \ub9cc\ub4dc\ub294 \ube44\uc6a9\uc740 \ub4e4\uc5c8\uaca0\uc9c0\ub9cc, \ubc88\uc5ed \ube44\uc6a9\uc774 \ub4e4\uc5b4\uac04 \uac83\uc740 \uc544\ub2c8\ub2e4.) VLAAH\ub3c4 \ub2e4\uc74c\uc5d0\ub294 \ubc88\uc5ed\uc744 \uaf2d \uadf8\ub807\uac8c \uc9c4\ud589\ud574\uc57c\uc9c0.\n\n [facebook]: http://www.facebook.com/", "date-gmt": "2010-04-21 03:09:00 GMT", "url": "http://blog.dahlia.kr/post/537294542", "url-with-slug": "http://blog.dahlia.kr/post/537294542", "format": "markdown", "-slug": "-ui", "id": "537294542", "unix-timestamp": "1271819340", "date": "Wed, 21 Apr 2010 12:09:00", "type": "quote", "slug": "ui", "reblog-key": "VZ9NaBeW"}
1  537294542-ui.md
@@ -0,0 +1 @@
+가장 이상적인 건 UI 차원에서 “이 문자열의 번역을 개선하기” 같은 컨텍스트 메뉴를 제공해서 바로 피드백이 가게 하는 것이겠지만 그 정도를 바라진 않고, 적어도 사용자 참여를 아주 방해하지만 않았으면 정말 좋겠는데.
1  567481297-imac.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-05-03 05:29:49 GMT", "url": "http://blog.dahlia.kr/post/567481297", "url-with-slug": "http://blog.dahlia.kr/post/567481297", "format": "markdown", "-slug": "-imac", "id": "567481297", "unix-timestamp": "1272864589", "date": "Mon, 03 May 2010 14:29:49", "type": "regular", "slug": "imac", "reblog-key": "JRi6vGtS"}
13 567481297-imac.md
@@ -0,0 +1,13 @@
+내가 **주소록**에 꼭 있어야 한다고 생각하는 기능들.
+
+일단 내 iMac과 MacBook Air, iPhone, 두 개의 Google Apps[^1], 세 개의 서로 다른 Gmail 계정[^2]의 주소록이 모두 동기화되어야 한다. 일단 이게 작동하지 않으면 아무리 좋은 주소록이라도 내가 쓸 수가 없다. 그럼 지금은 어떻게 해결하냐면, 사실 전혀 해결되어 있지 않다. iMac의 주소록을 메인으로 사용하는데, iPhone은 그것과 동기화하고 있다. 나머지는 관리가 전혀 안되는 상태.
+
+또한 identity map이 가능해야 한다. “홍민희” 항목에 그 사람의 모든 전화번호가 있어야 하고, 모든 이메일 주소가 있어야 하며, 그 사람의 개인 웹 사이트 주소 뿐만 아니라 MSN 메신저 주소와 Twitter 아이디와 미투데이 아이디, VLAAH 아이디 등이 모두 들어갈 수 있어야 한다.
+
+이러한 identity map을 해놔야 IRC의 “Hong_MinHee”가 MSN 메신저로는 나와 어떤 대화를 한 그 사람이고, 내가 그 사람한테 지난 가을에 어떤 메일을 보냈었는지, 어제 저녁에 떡볶이 야식 사진을 Twitter에 올렸던 바로 그 사람이라는 것을 알 수 있다. 5년 넘게 사용하고 있는 MSN 계정에 등록된 사람 가운데 맨날 보이긴 하는데 언제 왜 등록했는지 누군지도 모르겠는 사람이 수두룩하다. 그런 걸로 헤매고 싶지 않기 위해선 이런 identity map이 필요하다.
+
+마지막으로 언제 어디서나 그 사람과 나 사이에 어떤 대화와 어떤 사건이 있었는지 (로깅이 되고 있었다는 가정 하에) 바로 검색이 가능해야 한다. MSN에서 어떤 사람이 2년만에 말을 걸어왔는데 그 사람은 날 아는 눈치인데 나는 기억이 나지 않는다. 이럴 때 옆에 이전 기록 검색 버튼이 있어서 2년 전에 Twitter에서 날 언급했던 포스팅을 바로 찾아내고 누군지 기억해낼 수 있어야 한다.
+
+ [^1]: 하나는 `dahlia.kr`, 다른 하나는 `lunant.net`.
+
+ [^2]: `mydahlia`, `2ndahlia`, `hong.minhee`.
1  575152478-rocket-dive.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-05-06 03:24:00 GMT", "url": "http://blog.dahlia.kr/post/575152478", "url-with-slug": "http://blog.dahlia.kr/post/575152478", "format": "markdown", "-slug": "-rocket-dive", "id": "575152478", "link-url": "http://pypi.python.org/pypi/rocketdive/", "link-text": "ROCKET DIVE", "unix-timestamp": "1273116240", "date": "Thu, 06 May 2010 12:24:00", "title": "ROCKET DIVE", "type": "link", "slug": "rocket-dive", "reblog-key": "lWrLG0RE"}
32 575152478-rocket-dive.md
@@ -0,0 +1,32 @@
+![ROCKET DIVE 창](http://media.tumblr.com/tumblr_l1z9p9ZVzI1qz6t91.png)
+
+Python으로 웹 개발을 하려면 개발용 WSGI[^1] 컨테이너가 필요하다. 하지만 Python을 잘 모르는 사람이 개발 환경을 꾸리기는 쉽지 않다. 이를테면 디자이너는 .html 템플릿 파일을 수정해야 하는데, 그걸 위해서 [Green Unicorn][gunicorn]이니 [Rocket][]이니 하는걸 설치해서 커맨드라인으로 서버를 켜고 끄는 것은 너무 복잡하다. 그래서 GUI로 뭔가 간단하게 켜고 끄는 걸 가능하게 해야겠다 싶어서 하나 만들었다.
+
+Rocket의 GUI 프론트엔드고, 이름은 그래서 **ROCKET DIVE**다.[^2] Tkinter를 써서 인터페이스가 구린데, Rocket 외의 다른 라이브러리에 의존성을 만들고 싶지 않았기 때문에 어쩔 수 없었다. 참고로 Tkinter는 Python 표준 라이브러리에 들어있다.
+
+Windows를 기준으로 설치 방법을 설명하자면: Python 2.6과 [setuptools][](`easy_install` 명령어를 위해)를 먼저 설치하고 커맨드 프롬프트에서 `easy_install`로 다음과 같이 설치한다. 이때 Windows Vista 이상일 경우 커맨드 프롬프트를 관리자 권한으로 실행해야 한다.
+
+ C:\> easy_install distribute
+ C:\> easy_install rocketdive
+
+([Distribute][]는 Rocket이 의존하고 있는데, setuptools의 대안으로 등장한 물건이다. 이게 setuptools를 덮어쓰다보니 그냥 `easy_install rocketdive`로 설치해버리면 중간에 스스로를 갈아치우려다가 오류가 나버린다. 그래서 먼저 Distribute를 설치해야 한다.)
+
+설치가 끝나면 `pythonw.exe -m rocketdive`로 단축 아이콘을 만들면 된다.
+
+![단축 아이콘 만드는 화면](http://media.tumblr.com/tumblr_l1zamhay271qz6t91.png)
+
+[소스 코드는 Bitbucket에 올려뒀으니][1], Mercurial로 받을 수 있다.
+
+ $ hg clone https://dahlia@bitbucket.org/dahlia/rocketdive
+
+ [^1]: Python과 웹 서버 사이의 통신 규약. Java의 Servlet이나 Ruby의 Rack 같은 것이라고 보면 된다. [PEP 333][pep-333] 참고.
+
+ [^2]: 아는 사람은 알겠지만 hide의 노래 제목인데, 음악과의 연관성은 딱히 없고 Rocket의 프론트엔드니 이름을 로켓 어쩌고로 해야겠네 해서 생각나서 썼다.
+
+ *[WSGI]: Web Server Gateway Interface
+ [gunicorn]: http://gunicorn.org/
+ [rocket]: http://pypi.python.org/pypi/rocket/
+ [setuptools]: http://pypi.python.org/pypi/setuptools/
+ [distribute]: http://pypi.python.org/pypi/distribute/
+ [pep-333]: http://www.python.org/dev/peps/pep-0333/
+ [1]: http://bitbucket.org/dahlia/rocketdive
1  613490344-sqlalchemy-werkzeug.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-05-19 16:19:00 GMT", "url": "http://blog.dahlia.kr/post/613490344", "url-with-slug": "http://blog.dahlia.kr/post/613490344", "format": "markdown", "regular-title": "SQLAlchemy, Werkzeug", "-slug": "-sqlalchemy-werkzeug", "id": "613490344", "unix-timestamp": "1274285940", "date": "Thu, 20 May 2010 01:19:00", "title": "SQLAlchemy, Werkzeug", "type": "regular", "slug": "sqlalchemy-werkzeug", "reblog-key": "bQ6oQpgd"}
72 613490344-sqlalchemy-werkzeug.md
@@ -0,0 +1,72 @@
+나는 기본적으로 야크 쉐이빙(yak shaving) 충동을 자주 느끼는 편인데, 가끔 그걸 무찌르는 엄청난 작품을 보곤 한다. 야크 쉐이빙을 무찌를 정도의 물건은 두 가지 조건을 충족시킨다.
+
+ 1. 철학에 납득이 감은 물론 훌륭해서 내 생각을 바꿀 정도다. 혹은 기존의 내 관점과 일치한다.
+ 2. 그런 철학 위에서, 내가 스스로 구현하자면 엄두가 안날 정도의 피쳐셋으로 날 압도한다.
+
+최근에 웹 개발 관련된 라이브러리 중에서는 딱 두 개가 그렇다. 하나는 1년 전쯤부터 사용한 [SQLAlchemy][]고 다른 하나는 요 며칠간 써본 [Werkzeug][]이다. 오늘은 저 둘에 대해 설명하고 이왕이면 전도까지 해볼까 한다. 공교롭게도(?) 둘 다 Python 라이브러리다. (그나저나 둘 다 이름이 문제다. 이름이 멋이 없으니 아무리 좋아도 쉽게 사람들의 관심을 얻지 못한다.)
+
+**SQLAlchemy**의 철학은 대략 이렇다. RDBMS와 객체는 서로 다른 디자인 원칙을 따른다. 원칙이 다른 두 개념을 연결시키는 것이 ORM이다. 그런데 대부분의 ORM은 RDBMS의 원칙을 무시하고 RDBMS의 일부 자주 사용하는 기능만을 노출한 채 나머지는 거세하는 경향이 강하다. 이를테면 Rails의 ActiveRecord 같은 것들의 RDBMS에 대한 생각은 “똑똑한 스토리지일뿐”이다. 이는 대부분의 ORM 제작자들이 RDBMS에 대해 알지 못할뿐더러 관심조차 없기 때문에 일어나는 일이다. SQLAlchemy는 그 둘의 불일치를 이해하고, 양쪽 모두의 원칙을 지켜야 한다는 철학이다. SQLAlchemy의 맵핑 방식이 일견 다른 ORM 프레임워크에 비해 복잡해보이는 것은 사실이다. 하지만 그것은 철학을 위해 의도적으로 디자인된 부분이다. 서로 다른 컨셉을 연결애햐 하니 온갖 종류의 연결 방식을 다 제공한다. ActiveRecord마냥 모든 릴레이션이 `id`라는 이름의 프라이머리 키(primary key)를 갖는다는 가정따위는 전혀 없다. 기본적으로 나는 그런 철학에 깊게 동의했고, 거기다가 이미 성숙할대로 성숙해서 내가 스스로 구현하자면 끝도 없는 기능들을 이미 다 제공하고 있어서 거기에 압도되어 버렸다.
+
+ - 아이덴티티 맵(identity map)[^1]
+ - Python 표현식을 SQL로 변환하는 컴파일러 셋[^2]
+ - 타입 시스템[^3]
+ - 사용자 정의 타입 만들기
+ - 여러 필드로 프라이머리 키 만들기
+ - 제약 조건(constraint) 정의
+ - 특정 표현식을 프로퍼티(property)로 사용하기[^4]
+ - 셀프 조인
+ - RDBMS에서 여러 필드로 관리되는 것을 객체에서는 하나의 애트리뷰트로 연결하기[^5]
+ - 다양한 방식의 상속 지원
+ - 특정 컬럼의 데이터를 가지고 다형성(polymorphic)을 구현하는 [단일 테이블 상속][1](single table inheritance)
+ - [조인으로 구현하는 테이블 상속][2](joined table inheritance)
+ - 각각 나눠진 테이블을 마치 하나의 클래스 계통(class hierarchy)인 것처럼 보이게 해서 맵핑하는 [컨크리트 테이블 상속][3](concrete table inheritance)
+ - 둘 이상의 테이블을 하나의 클래스로 연결하기 (RDBMS의 뷰와 비슷하지만 DML이 가능하다는 점이 다르다.)
+ - 관계 매핑을 딕셔너리(`dict`) 등으로 하기[^6]
+ - 다양한 RDBMS 벤더 지원 [^7]
+
+사실 위에서 적은 것만도 일부일 뿐이고 정말 방대한 기능들을 제공하고 있어서 메뉴얼을 차근차근 읽어보면 압도될 수밖에 없게 만드는 ORM 프레임워크다. 왜 이렇게 쓸데없이 많은 기능들을 제공하는지 모르겠다고 하면 SQLAlchemy의 철학에 수긍하지 못해서 그럴 것이다. 저렇게 많은 맵핑 방법을 제공하기 때문에 **RDBMS를 RDBMS답게 쓰면서 객체를 객체답게 디자인할 수 있게 된다.**
+
+참고로 난 ORM 프레임워크에 특별히 관심이 많고, 기준도 제법 높은 편이라 Ruby의 DataMapper 같은 제법 똑똑하다는 ORM 프레임워크를 보고도 “병신이네”하고 말았던(오만하기 짝이 없지만;) 정도인데 SQLAlchemy는 정말 날 매료시켰다. 다만 기능이 너무 많아 제대로 쓰려면 꽤 오랫동안 배워야 하는게 문제. 나도 제대로 잘 쓰는데 1년 정도 걸린 것 같다.
+
+**Werkzeug**은 비교적 최근에 발견했는데 기존에 잔뜩 쏟아지고 있는 Rails, Django 류의 풀스택 프레임워크와도 전혀 다르고, 그렇다고 해서 [djng][]이나 [Sinatra][], [Flask][][^8] 같은 최근 유행하는 마이크로프레임워크와도 다른 물건이다.
+
+일단 Werkzeug은 프레임워크가 아니라 라이브러리다. 프레임워크는 기본적으로 앞으로 작성될 코드가 그 프레임워크에 맞춰지도록 강요한다. Django에서 Django ORM만 갖다 쓴다거나 Rails에서 `app/{models,controllers,views}` 디렉토리 구조를 거부할 수는 없으며 할 수 있다고 해도 그 프레임워크를 쓰는 의미가 사라진다.
+
+Werkzeug은 MVC를 강요하지도 않으며 ORM으로 어떤 걸 쓸지도 정해놓지 않았고, 디렉토리 구조도 전혀 제시하지 않는다. 그럼 Werkzeug은 어디에 쓰냐 하면, 내 생각에는 인하우스 프레임워크를 만들기 위한 도구들이라고 생각한다. 앞서 얘기한 것만 보면 기능이 별로 없고 가벼울 것 같지만, 실제로 Werkzeug은 HTTP와 WSGI 프로토콜 안에서 생각할 수 있는 모든 기능을 다 제공한다. 이를테면 내용 협상(content negotiation)부터 세션, 시큐어 쿠키, 정적 파일들을 서빙해주는 WSGI 미들웨어, 디버깅을 위한 미들웨어, 프로파일러, 가상 호스트, URL 라우팅, 캐시, 날짜 및 시간 관련 유틸리티, HTML 헬퍼……. 그런데도 프레임워크는 아니다. 필요한 만큼만 `import`해서 쓰게 되어있기 때문이다. 열거한 기능들 중에 이를테면 시큐어 쿠키 기능 딱 하나만 쓰려고 `import werkzeug.contrib.securecookie`해서 써도 전혀 이상하지 않게 되어있다.
+
+저런 디자인이 가능한 것은 Python에 WSGI가 있기 때문이다. Werkzeug의 primitive는 WSGI이고, WSGI 인터페이스 이상의 추상화가 없기도 하다. 딱 WSGI의 인터페이스만으로 모든 것을 해결한 라이브러리다. 프레임워크를 만들 수 있게 해주는 프레임워크, 즉 메타프레임워크쯤 된달까.
+
+게다가 클래스, 함수 하나하나의 디자인이 모두 센스 넘치게 잘 되어있다. 현대적인 Python 프로그램 디자인의 모범이라 할만하다. 철학부터 제공되는 기능들 모두가 날 만족시킨다. 최근 몇년동안 이렇게 날 만족시킨 웹 개발 관련 라이브러리도 처음이다.
+
+요즘 SQLAlchemy + Werkzeug + [Jinja2][]으로 웹 개발을 하고 있는데, 최근 몇년간 했던 웹 개발 중에서 가장 행복하다. 정말로.
+
+ [^1]: 같은 레코드에 대한 객체는 레퍼런스도 같도록 매핑하는 것. 그러니까 하나의 레코드에 대해서는 하나의 객체만 존재하게 해준다.
+
+ [^2]: 사실 SQLAlchemy에서 가장 핵심적인 모듈이면서 가장 강력한 모듈이다. 이게 있기 때문에 SQLAlchemy의 다른 방대한 기능이 존재할 수 있다. SQL 컴파일러가 존재하니 그 윗단에서는 SQL 해킹을 할 필요 없이 추상화 레이어를 쌓아올리면 되기 때문이다.
+
+ [^3]: 컴파일러 셋을 만들어야 하니 당연히 의미에 맞는 번역을 하기 위해서는 타입 시스템이 필요해진다.
+
+ [^4]: 예를 들어 `deleted_at`이라는 컬럼이 있고 그 컬럼은 해당 레코드가 삭제되지 않았다면 `NULL`이고, 삭제되었다면 삭제된 시각이 채워진다. 이런 경우 `deleted`라는 또다른 불리언(boolean) 컬럼을 객체에서 가상으로 만들 수 있다.
+
+ deleted = sqlalchemy.orm.column_property(deleted_at != None)
+
+ 위와 같이 `deleted`를 지정하면 사용할때 `record.deleted`와 같이 쓸 수 있을 뿐만 아니라, 쿼리할 때도 크라이테리아를 지정하기 위해 `Record.deleted`처럼 사용 가능하다. 그렇게 하면 SQL으로는 `WHERE deleted_at IS NOT NULL`과 같이 컴파일되는데 이 얼마나 똑똑한 작동인가.
+
+ [^5]: 지저분한 예지만 이를테면 RDBMS에서는 전화번호를 `tel1`, `tel2`, `te3`로 저장하고 있는데 그걸 객체에서는 `telephone`이라는 하나의 프로퍼티로 관리하고 그 타입은 [`collections.namedtuple`][collections.namedtuple]을 이용해 `Telephone(tel1, tel2, tel3)` 같은 식으로 맵핑할 수 있다.
+
+ [^6]: 만약 `person(id pk, name)` 따위의 테이블이 있고 또 `post(id pk, category pk, author_id fk, body)` 따위의 테이블이 있다면 `person.posts[category]`처럼 맵핑하는 것을 말한다. 꼭 `dict`가 아니라도 아무 컬렉션 타입으로든 맵핑이 가능하다.
+
+ [^7]: 대부분의 ORM 프레임워크들은 자신이 지원하는 RDBMS 벤더의 기능 집합들 사이에 교집합만을 지원하고, 나머지 특정 벤더에서만 존재하는 기능들(vendor-specific features)은 지원하지 않고 거세하는 경향이 강하지만, SQLAlchemy는 전혀 그렇지 않고 각 벤더 고유의 기능들을 그대로 살린다. 이를테면 PostgreSQL의 배열 타입(array type) 같은 것을 그대로 사용 가능하다.
+
+ [^8]: 사실 이것도 Werkzeug 기반이다.
+
+ [sqlalchemy]: http://www.sqlalchemy.org/
+ [werkzeug]: http://werkzeug.pocoo.org/
+ [collections.namedtuple]: http://docs.python.org/dev/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields
+ [djng]: http://github.com/simonw/djng
+ [sinatra]: http://www.sinatrarb.com/
+ [flask]: http://flask.pocoo.org/
+ [jinja2]: http://jinja.pocoo.org/2/
+ [1]: http://www.sqlalchemy.org/docs/mappers.html#single-table-inheritance
+ [2]: http://www.sqlalchemy.org/docs/mappers.html#joined-table-inheritance
+ [3]: http://www.sqlalchemy.org/docs/mappers.html#concrete-table-inheritance
1  623034732.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-05-22 21:00:00 GMT", "url": "http://blog.dahlia.kr/post/623034732", "url-with-slug": "http://blog.dahlia.kr/post/623034732", "format": "markdown", "-slug": "", "id": "623034732", "unix-timestamp": "1274562000", "date": "Sun, 23 May 2010 06:00:00", "type": "regular", "slug": "", "reblog-key": "a3FReAr9"}
5 623034732.md
@@ -0,0 +1,5 @@
+대부분의 프로그래밍 문제는 추상화 레이어를 더 삽입함으로서 해결할 수 있다고 하지만, 아직까지 대부분의 추상화는 성능에 대해서는 투명하지 않기 때문에 그게 만능이 아닐 수 있다. [이런 글][1]에서 제안하는 방식은 딱 내 취향이긴 하지만, 모바일 디바이스 성능을 생각한다면 차라리 멀티 타겟 컴파일러를 만드는게 맞는 (하지만 너무나 비효율적인)[^1] 답일 수도 있겠다.
+
+ [^1]: 그 컴파일러를 앞으로 무척 많이 써서 소셜 게임을 100개쯤 찍어낸다면 오히려 더 효율적이겠지만.
+
+ [1]: http://alankang.tistory.com/271
1  692534002-bitbucket-v-github.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-06-13 03:46:55 GMT", "url": "http://blog.dahlia.kr/post/692534002", "url-with-slug": "http://blog.dahlia.kr/post/692534002", "format": "markdown", "regular-title": "Bitbucket v. GitHub", "-slug": "-bitbucket-v-github", "id": "692534002", "unix-timestamp": "1276400815", "date": "Sun, 13 Jun 2010 12:46:55", "title": "Bitbucket v. GitHub", "type": "regular", "slug": "bitbucket-v-github", "reblog-key": "FeLAv5ek"}
18 692534002-bitbucket-v-github.md
@@ -0,0 +1,18 @@
+내가 분산형 버전 관리 시스템의 아주 기본적인 기능만을 주로 쓰기 때문에, 아무래도 인터페이스가 좀더 친절한[^1] Mercurial이 git보다 더 좋다. 하지만 두 버전 관리 시스템을 기반으로 하는 소셜 프로젝트 호스팅 두 서비스—[Bitbucket][]과 [GitHub][]를 비교하자면 정 반대이다. 내가 볼 때 Bitbucket은 현재로서는 무료 계정에서도 1개까지는 비공개 저장소를 생성 가능하다는 것 말고는 GitHub에 비해 이렇다할 장점이 없다. 디자인도 GitHub가 더 세련됐으며, GitHub는 자기네가 호스팅해주는 프로젝트 페이지를 프로젝트의 공식 홈페이지로 사용할 수 있을 정도로 만들어주는데 비해, Bitbucket은 그렇지 않다. 하지만 이런 기능 외에도 GitHub를 사용할 수밖에 없게 만드는 것이 하나 있는데, 바로 커뮤니티 크기이다. GitHub에는 너무나 유명한 프로젝트가 많은데, Bitbucket은 대체로 Python 쪽에서만 유명한 프로젝트가 전부다. 그리고 그 외에 사용자 수에도 차이가 많다.
+
+애초에 git은 Linus Torvalds가 C로 구현한 버전 관리 시스템이고, Mercurial은 Python으로 작성되어 있다. Mercurial은 Python을 쓰는 프로젝트에서는 사용할 명분이 충분하지만, 다른 언어에서는 조금 이상하게 느껴지기 쉽다. 이를테면 Ruby나 Perl로 작성된 오픈 소스 소프트웨어를 Mercurial을 사용해서 버전 관리를 한다고 하면 사용하는데 지장은 전혀 없음에도 Mercurial이 Python으로 작성되어있다는 사실 때문에 이상하게 여겨지는 것이다. 하지만 반대로 Python을 사용하는 프로젝트가 Mercurial 대신 git을 쓴다고 해서 어색하게 느껴지진 않는다. 이렇기 때문에 아무래도 git 사용자가 훨씬 많아질 수밖에 없고, Mercurial은 점차 Python 커뮤니티에서만 사용되는 버전 관리 시스템이 되어가는 것 같다.
+
+어찌됐든 결국 GitHub가 사용자가 훨씬 많기 때문에 프로젝트를 홍보하기 위해서는 GitHub를 이용하는 편이 훨씬 유리하다. 그래서 [야간개발팀][lunant]도 Bitbucket에서 Mercurial로 관리하던 오픈 소스 프로젝트들을 모두 GitHub로 옮겨버렸다. 인지도를 좀 더 올릴 기회가 많기 때문에 어쩔 수 없는 선택이었는데, 사용법 자체는 Mercurial이 편하기 때문에 내부의 비공개 저장소는 여전히 Mercurial을 사용해 관리하고 있다.
+
+한 줄 정리를 하자면, 홍보에 신경을 쓰고 있다면 어찌됐든 GitHub를 권한다. 그냥 편한 게 좋다면(그리고 Subversion에 익숙하다면) Bitbucket에서 Mercurial을 써도 문제 없다.[^2]
+
+ [^1]: Subversion에 익숙한 사람한테만 친절하게 느껴지는 걸지도 모른다.
+
+ [^2]: 예를 들어 [Pocoo Team][pocoo]의 [Armin Rochacher][mitsuhiko](mitsuhiko)도 [Flask][] 같은 프로젝트는 GitHub에서 공개했지만, Werkzeug 같은 다른 대부분의 프로젝트들은 Mercurial을 사용한다. 덕분에 Werkzeug은 나온지 2년이 넘었고 Flask는 올해 4월에 나왔지만 Flask가 훨씬 더 유명하고 뜨겁다.
+
+ [bitbucket]: http://bitbucket.org/
+ [github]: http://github.com/
+ [lunant]: http://lunant.net/
+ [pocoo]: http://www.pocoo.org/
+ [mitsuhiko]: http://lucumr.pocoo.org/
+ [flask]: http://github.com/mitsuhiko/flask
1  713985464-deprecated-v-obsolete.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-06-19 05:48:09 GMT", "url": "http://blog.dahlia.kr/post/713985464", "url-with-slug": "http://blog.dahlia.kr/post/713985464", "format": "markdown", "-slug": "-deprecated-v-obsolete", "id": "713985464", "link-url": "http://kldp.org/node/115500", "link-text": "deprecated v. obsolete", "unix-timestamp": "1276926489", "date": "Sat, 19 Jun 2010 14:48:09", "title": "deprecated v. obsolete", "type": "link", "slug": "deprecated-v-obsolete", "reblog-key": "6yFOQ2lD"}
3  713985464-deprecated-v-obsolete.md
@@ -0,0 +1,3 @@
+쉽게 말해 **deprecated**는 **아직 폐지되진 않았지만 곧 그럴 예정이니 사용을 지양하라**는 식의 뜻으로 쓰이고, **obsolete**는 아예 **이제 폐지되어서 작동도 안 된다**는 뜻이다.
+
+나도 처음 안 사실이라 링크 및 요약.
1  730070594.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-06-24 03:08:00 GMT", "url": "http://blog.dahlia.kr/post/730070594", "url-with-slug": "http://blog.dahlia.kr/post/730070594", "format": "markdown", "regular-title": "\uc190\uc73c\ub85c \ubbf8\uc138\ud55c \ucd5c\uc801\ud654\ub97c \ud558\uc9c0 \ub9d0\uc790", "-slug": "", "id": "730070594", "unix-timestamp": "1277348880", "date": "Thu, 24 Jun 2010 12:08:00", "title": "\uc190\uc73c\ub85c \ubbf8\uc138\ud55c \ucd5c\uc801\ud654\ub97c \ud558\uc9c0 \ub9d0\uc790", "type": "regular", "slug": "", "reblog-key": "1kU5CDzR"}
9 730070594.md
@@ -0,0 +1,9 @@
+[How to Micro-Optimize Your CSS][1][^1] 같은 글을 보면 한숨이 난다. 저런건 사람이 할 일이 아니다. 반복적이며 사소한 저런 최적화는 원래 프로그래밍 언어에서는 컴파일러 등이 해야할 문제다. 저기 나온 최적화 팁들은 [CSSTidy][] 쓰면 죄다 자동으로 할 수 있다. 사람은 그냥 자기가 가장 편한 방법으로 코딩하면 된다. 제발 저런 문제는 코딩할 때 신경쓰지 말자. 저건 배포의 문제니까, 배포할 때 자동화할 생각을 하자.
+
+Apache, lighttpd 모듈로 mod_csstidy라도 만들어야 하냐는 생각이 들었다.
+
+ [^1]: 파이어준 님이 한국어로 같은 내용을 포스팅하셨다: [스타일 시트를 경량화하는 11가지 팁 18][2]
+
+ [csstidy]: http://csstidy.sourceforge.net/
+ [1]: http://perishablepress.com/press/2010/06/21/how-to-micro-optimize-your-css/
+ [2]: http://firejune.com/1613
1  745079289.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-06-28 09:11:00 GMT", "url": "http://blog.dahlia.kr/post/745079289", "url-with-slug": "http://blog.dahlia.kr/post/745079289", "format": "markdown", "-slug": "", "id": "745079289", "unix-timestamp": "1277716260", "date": "Mon, 28 Jun 2010 18:11:00", "type": "regular", "slug": "", "reblog-key": "JJ6NvHoj"}
8 745079289.md
@@ -0,0 +1,8 @@
+요즘 느끼는 건데 상업적인 프로젝트에서 개발자들이 문서라고 남겨둔 것들은 대체로 불친절하고 누가 시켜서 억지로 했다는 느낌이 강하다. 불친절하다는 것을 어떻게 알 수 있냐면: 일단 상업적인 프로젝트의 문서에서 튜토리얼이 나오는 경우는 절대 없다. 왜냐면 튜토리얼은 꼭 있어야 하는 문서는 아니지만 이해를 더 쉽게 하기 위한 것이고, 나처럼 문서화를 좋아라하는 개발자들은 원래 적기 때문이다. 그걸 감안하더라도 오픈 소스 프로젝트에 비해 상업적인 프로젝트의 문서들이 더 형편없는 경우가 많은데, 오픈 소스 프로젝트의 경우 문서화를 잘 해야 프로젝트 홍보가 잘 되고 날개돋힌듯 널리 알려지고 쓰이며 발전하기 때문에 문서화를 중요하게 생각하기 때문이다.
+
+오픈 소스 프로젝트에게 있어서는 문서와 프로젝트 홈페이지가 프로덕트 패키지의 역할을 담당하는데다 오픈 소스 프로그램은 대부분 유형적인 패키지가 존재하지 않는 프로덕트이므로 문서화는 사용자를 유혹하는 가장 직접적인 수단이다. 예를 들어 인기있는 웹 프레임워크인 [Django][]를 써본 사람들은 처음 Django를 쓰게 된 이유가 홈페이지 디자인이 좋고 [Sphinx][]로 문서화된 매뉴얼이 훌륭해서라는 사실을 무시하지 못할 것이다. 이런저런 이유 때문에 인기 있는 오픈 소스 프로젝트는 대부분 훌륭한 매뉴얼이 존재하고, 튜토리얼도 꼭 함께 있다. 요즘엔 아예 동영상으로 찍어서 스크린캐스트를 제공하기도 할 정도니.
+
+어쨌거나 소스는 물론 API조차 외부에 알려지지 않더라도 Sphinx로 꼼꼼하게 문서화를 하는 편인 나에게 있어서는 상업적인 프로젝트에서의 전혀 이해에 도움을 주지 않는 구실뿐인 문서들은 괴롭기만 하다. “없는 것보단 낫다”라고들 하지만 나한테 그건 아예 고려 대상도 아니고.
+
+ [django]: http://www.djangoproject.com/
+ [sphinx]: http://sphinx.pocoo.org/
1  752419604-ipv6.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-06-30 04:42:52 GMT", "url": "http://blog.dahlia.kr/post/752419604", "url-with-slug": "http://blog.dahlia.kr/post/752419604", "format": "markdown", "-slug": "-ipv6", "id": "752419604", "unix-timestamp": "1277872972", "date": "Wed, 30 Jun 2010 13:42:52", "title": "\uc18c\ub97c \uc704\ud55c IPv6", "conversation-title": "\uc18c\ub97c \uc704\ud55c IPv6", "type": "conversation", "slug": "ipv6", "reblog-key": "9VYApLMM"}
15 752419604-ipv6.md
@@ -0,0 +1,15 @@
+wooil: 그런데 IPv6라도 1인 1 아이피는 안 되죠?
+darjeeling: 아뇨
+darjeeling: IPv6는
+kkung: IPv6는
+kkung: 미생물에게 하나씩 줘도
+kkung: 남는다는
+kkung: 계산을 누가 했던데
+kkung: =3=3
+wooil: -0-
+darjeeling: 아 모르셨군요.
+darjeeling: 저희가 앞으로
+darjeeling: 소를 키우면서
+darjeeling: 소에게 IP를 할당해서
+darjeeling: 멀티캐스트로 핑을 쏘면
+darjeeling: 죽었는지 살았는지 나올꺼임.
1  756689263-dahlia-kr-url-3.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-07-01 06:27:00 GMT", "url": "http://blog.dahlia.kr/post/756689263", "url-with-slug": "http://blog.dahlia.kr/post/756689263", "format": "markdown", "-slug": "-dahlia-kr-url-3", "id": "756689263", "unix-timestamp": "1277965620", "date": "Thu, 01 Jul 2010 15:27:00", "type": "regular", "slug": "dahlia-kr-url-3", "reblog-key": "G97f9Nna"}
5 756689263-dahlia-kr-url-3.md
@@ -0,0 +1,5 @@
+내 도메인인 dahlia.kr 아래쪽에 있는 URL 중에 3년 정도 된 게 하나 있다.
+
+<http://justhing.dahlia.kr/io-tutorial-for-programmer/>
+
+예전에 썼던 짧은 Io 튜토리얼인데, 까맣게 잊고 있다가 얼마 전에 다른 블로그에서 여기로 링크된 게 있어서 생각이 났다. 눌러 들어가서 오랜만에 봤더니 데이터가 날아가서 에러가 나고 있었다. 날아간 데이터를 어찌할 수 없어서 그냥 요즘 IBM developerWorks에 연재중인 Io 연재로 링크를 해놨다.
1  784275981-java-java-java.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-07-08 06:45:49 GMT", "url": "http://blog.dahlia.kr/post/784275981", "url-with-slug": "http://blog.dahlia.kr/post/784275981", "format": "markdown", "-slug": "-java-java-java", "id": "784275981", "unix-timestamp": "1278571549", "date": "Thu, 08 Jul 2010 15:45:49", "type": "regular", "slug": "java-java-java", "reblog-key": "X1JguQVl"}
7 784275981-java-java-java.md
@@ -0,0 +1,7 @@
+Java만 하는 사람들은 진짜 Java만 한다. Java는 한번 제대로 하려고 마음 먹으면 너무 배울 것이 많기 때문에 더 그렇다. Java밖에 안 하니까 우물안 개구리가 되기 십상이다.
+
+Java에 배울 것이 많다는 것이 Java의 심오함을 대변하는 것은 아니다. 사실은 그 반대다. Java에는 Java 자체가 해결해주지 못하는 문제들이 너무 많기 때문에 디자인 패턴부터 시작해서 온갖 workaround가 판을 치기 때문에 배울 것이 더 많아진다. 정작 Java에 몰두한 사람들은 그것들이 workaround가 아니라 굉장히 우아한 해결책이라고 느끼는 것이 더 큰 문제다. 그 사람들이 workaround를 우아한 해결책이라고 믿는 이유는 그것들이 Java의 문제를 해결하는 것이 아니라, 프로그래밍 본질적인 문제를 해결하는 것이라고 착각하는 경우가 많기 때문이다. 예를 들어 디자인 패턴의 꽤 많은 전략이 다른 언어에서는 필요하지 않은 경우가 많다. 하지만 Java만 하던 사람은 Java 외의 다른 언어를 진지하게 배워볼 시간이 없었기 때문에[^1] Java가 갖는 문제를 프로그래밍 본질의 문제로 보기 쉽다. 그렇게 Java 진영에서 우아한 해결책들로 알려진 workaround를 하루하루 체득해가며 세월을 보내는 것이다.
+
+Hibernate가 좋은 ORM이라고 칭찬하는 글을 보며 문득 저 사람에게 SQLAlchemy를 보여주면 뭐라고 할지 궁금하다는 생각이 들어 이런 글을 쓴다.
+
+ [^1]: 뭐 C++ 정도를 더 알고 있을 수는 있지만, 나는 C++와 Java 사이의 거리가 Java와 Haskell, Lisp 사이의 거리에 비하면 “거기서 거기인” 언어라고 본다.
1  796511696-unfortunately-more-and-more-people-use-scripting.json
@@ -0,0 +1 @@
+{"quote-source": "_Masterminds of Programming_, Roberto Ierusalimschy", "date-gmt": "2010-07-11 05:12:00 GMT", "url": "http://blog.dahlia.kr/post/796511696", "url-with-slug": "http://blog.dahlia.kr/post/796511696", "format": "markdown", "-slug": "-unfortunately-more-and-more-people-use-scripting", "id": "796511696", "unix-timestamp": "1278825120", "date": "Sun, 11 Jul 2010 14:12:00", "type": "quote", "slug": "unfortunately-more-and-more-people-use-scripting", "reblog-key": "FmGqmT3E"}
3  796511696-unfortunately-more-and-more-people-use-scripting.md
@@ -0,0 +1,3 @@
+Unfortunately, more and more people use “scripting language” as a synonym for “dynamic language.” Nowadays even Erlang or Scheme are called scripting languages. That is sad, because we lose the precision to describe a particular class of dynamic languages. Lua is a scripting language in the original meaning of the expression. A language to control other components, usually written in another language.
+
+불행히도 점점 많은 사람들이 “스크립트 언어”를 “동적 언어”의 동의어로 사용한다. 요즘에는 Erlang이나 Scheme까지도 스크립트 언어라고 불린다. 슬픈 일이다. 왜냐하면 우리는 동적 언어의 개별적인 종류를 설명하기 위한 한 정밀성을 잃었기 때문이다. Lua는 본래 뜻에서의 스크립트 언어이다. 보통 또다른 언어로 씌어진 다른 컴포넌트를 다루기 위한 언어.
1  810525751-irc.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-07-14 11:00:00 GMT", "url": "http://blog.dahlia.kr/post/810525751", "url-with-slug": "http://blog.dahlia.kr/post/810525751", "format": "markdown", "regular-title": "\ud300 IRC", "-slug": "-irc", "id": "810525751", "unix-timestamp": "1279105200", "date": "Wed, 14 Jul 2010 20:00:00", "title": "\ud300 IRC", "type": "regular", "slug": "irc", "reblog-key": "Mf3F94HF"}
53 810525751-irc.md
@@ -0,0 +1,53 @@
+아주 큰 집단이거나, 혹은 함께 있는 시간이 적은 팀에서 소통하는 방법 중 하나가 아마 네이트온 같은 IM일 것이다. 하지만 나는 IM보다는 IRC를 더 추천한다. 여러 이유가 있는데, 한번 적어보겠다. (IM과 IRC가 대충 어떤 건지는 안다고 가정하고 글을 쓴다.)
+
+ *[IM]: Instant Messenger
+ *[IRC]: Internet Relay Chat
+
+
+#### 셋 이상이서 대화 ####
+
+MSN이나 네이트온 등의 IM에도 초대 기능이 있어서, 셋 이상이서 대화하는 것이 가능하다. 하지만 IM은 직접 초대하기 전까지는 단 둘만의 대화창이고, 직접 IM에서 누군가에게 먼저 말을 건다는 메타포가 부담이 있다. 그에 비해 IRC는 원래 채널이 존재하고, 그 채널에 들어가기만 하면 된다. 컴퓨터를 킨 사람은 그냥 IRC 채널에 들어온다. 원래 그 채널은 여럿이서 대화하는 곳이니 “말을 건다”는 부담은 없다. 오히려 “나 말고 다들 있다는 그 채널”에 나도 들어가는 것이다.
+
+쉽게 생각해 항상 친구들이 놀고 있는 놀이터에 간다고 생각하면 된다. 그에 비해 IM은 친구네 집에 불쑥 찾아가는 것에 가깝다.
+
+야간개발팀 같은 경우 멤버 전원이 IRC 채널에 상주하고 있다. (주말에는 잘 안들어오는 멤버도 있긴 하지만, 평일엔 다들 있다.)
+
+
+#### 로그 ####
+
+팀에게 유리하게 작용하는 IRC의 또다른 특징은 로그라고 할 수 있다. 약간의 설정을 통해 (봇 등을 마련해서) 로그를 기록하게 하면 누군가가 없던 시간에 다른 사람들이 어떤 대화를 했는지 알 수 있다. 사람이 많아질수록 모두 모이기 힘든 것을 감안하면 꽤나 좋은 점이라고 할 수 있다.
+
+야간개발팀의 경우 인트라넷에 아예 IRC 로그 메뉴가 있고, 1년전 기록도 볼 수 있고, 아예 특정 키워드로 검색도 가능하다.
+
+
+#### 작업 방해 ####
+
+IM은 대화창이 한 번 열리면, 그 뒤에 상대방이 말을 한 번이라도 보내면 내가 확인할 때까지 작업표시줄 등에서 번쩍거리며 관심을 요구한다. 그래서 작업에 집중하기 힘든 경우가 많고, 힘들게 집중했는데 누가 말을 걸어서 방해를 받는 경우도 있다. IRC는 기본적으로 다대다 소통 방식이기 때문에, 누군가가 하는 말이 꼭 내게 하는 소리라고는 볼 수 없으므로 대개의 IRC 클라이언트는 그런 걸로 사용자에게 주의를 요구하지 않게 되어있다.
+
+물론 대화 내용 중에 자신의 이름이 언급되면 IRC 클라이언트가 주의를 요구하긴 한다. IRC를 많이 쓰는 사람에겐 아주 익숙한 것인데, 대부분의 IRC 클라이언트가 이 “하이라이트” 기능을 제공하고 하이라이트를 쉽게 할 수 있도록 “사용자 이름 자동완성” 기능도 제공한다. 이를테면 대화창에서 “홍”까지만 쓰고 탭 키 따위를 누르면 “홍민희, ” 혹은 “홍민희: ”로 펼쳐지는 식이다. (내용 중간이라면 쉼표나 콜론 없이 이름만 완성된다.) 이렇게 말을 걸면 불리운 사람의 IRC 클라이언트는 사용자에게 “네 얘기를 하고 있다”라는 뜻에서 사용자에게 주의를 준다.
+
+[Twitter가 잘 엔지니어링되지 못한 IRC 클론][1]이라고 말하는 사람도 있는데, 실제로 이런 IRC 사용 패턴은 Twitter의 언급(mention) 기능에 영향을 준 것 같다. 사실 앞서 말한 IRC의 특징들을 가만히 보고 있으면 결국 [Yammer][] 같은 기업용 마이크로블로깅 서비스가 해주는 일을 대부분 해준다는 것도 알 수 있다.
+
+“하이라이트” 외에 채팅방에서의 “귓속말”이라고 할 수 있는 “쿼리”라는 것도 IRC에 있다. 이 “쿼리”로 하는 대화는 일반 IM과 비슷하게 작동하는 편이다. 그러니까, 대부분의 IRC 클라이언트가 쿼리로 오가는 말에는 사용자에게 계속 주의를 요구한다.
+
+ [1]: http://pub.mearie.org/%ED%8A%B8%EC%9C%84%ED%84%B0 "트위터 | 메아리 풉;"
+ [yammer]: https://www.yammer.com/
+
+
+#### IRC를 시작하려면? ####
+
+IRC를 시작하는 것은 어찌보면 조금 번거롭기도 하고, 쉽기도 하다. 적당한 IRC 클라이언트를 골라 적당한 IRC 네트워크에 채널을 만들어서 들어가면 된다. 하지만 여력이 된다면 직접 IRC 네트워크 서버를 구축해서 운영하는 편이 좋긴 한다.
+
+“적당한 IRC 클라이언트”라는 말이 생각보다 어려운데, Mac이라면 엄청나게 심플한 [LimeChat][]을 추천하고, Linux라면 대부분의 배포본에서 패키지로 제공되어 설치하기 쉬운 [XChat][]을 권한다. 문제는 Windows인데 대부분 mIRC를 사용하는 모양이지만 나는 추천하지 않는 편이다. 주변 몇 사람들은 IRC 클라이언트로 [Opera][] 브라우저를 추천하기도 한다.[^1] 이도저도 싫다면 [랜덤여신][2] 님이 만든 [인클 웹 IRC][3]를 추천한다. 워낙 다른 Windows용 IRC 클라이언트들이 UI가 후져서 이게 제일 깔끔한 편이다. 게다가 Google Chrome의 [web application shortcuts][4] 기능을 쓰면 일반 애플리케이션처럼 사용할 수도 있다.
+
+“적당한 IRC 네트워크”로는 주저없이 [오징어 IRC 네트워크][ozinger]를 추천한다. 비교적 가장 최근에 구축된 네트워크이기 때문에 EUC-KR을 사용해야 하는 등의 레거시가 없다(UTF-8을 쓴다).
+
+ [limechat]: http://limechat.net/mac/
+ [xchat]: http://xchat.org/
+ [opera]: http://www.opera.com/
+ [ozinger]: http://ozinger.org/
+ [2]: http://barosl.com/
+ [3]: http://barosl.com/webirc/
+ [4]: http://www.google.com/support/chrome/bin/answer.py?answer=95710
+
+ [^1]: Opera 브라우저가 괜히 쓸데없는 기능을 잔뜩 안고 있는 편이다. IRC 클라이언트 기능도 그 중 하나다. Opera를 IRC 클라이언트로 쓰는 사람들의 말에 의하면 브라우저로는 쓰기 싫지만 IRC 클라이언트로는 썩 좋기 때문에 IRC 클라이언트로만 쓴다고 한다.
1  841264469-fontface-kr.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-07-21 17:03:59 GMT", "url": "http://blog.dahlia.kr/post/841264469", "url-with-slug": "http://blog.dahlia.kr/post/841264469", "format": "markdown", "-slug": "-fontface-kr", "id": "841264469", "link-url": "http://fontface.kr/", "link-text": "fontface.kr", "unix-timestamp": "1279731839", "date": "Thu, 22 Jul 2010 02:03:59", "title": "fontface.kr", "type": "link", "slug": "fontface-kr", "reblog-key": "V7iHVOCs"}
11 841264469-fontface-kr.md
@@ -0,0 +1,11 @@
+<img src="http://img199.imageshack.us/img199/6377/fontfacekr.png" alt="fontface.kr" height="337" width="474" />
+
+이번에 [야간개발팀][1]에서 [fontface.kr][2]이라는 한글 웹 글꼴 호스팅 서비스를 만들어서 공개했다. [Typekit][3]의 한국/한글 버전이라고 생각하면 될 것 같다. 아직은 나눔고딕 등 나눔 시리즈 폰트만 호스팅하고 있는데, 앞으로 여러 공개 폰트들을 더 추가할 생각이다.[^1]
+
+많이들 이용해주시라.
+
+ [^1]: 혹시 아는 한글 공개 글꼴이 있으면 제보해주시라. 아마 금방 추가될 수 있을 것이다.
+
+ [1]: http://lunant.net/
+ [2]: http://fontface.kr/
+ [3]: http://typekit.com/
1  857328074-distribute-pip.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-07-25 16:23:09 GMT", "url": "http://blog.dahlia.kr/post/857328074", "url-with-slug": "http://blog.dahlia.kr/post/857328074", "format": "markdown", "regular-title": "distribute, pip", "-slug": "-distribute-pip", "id": "857328074", "unix-timestamp": "1280074989", "date": "Mon, 26 Jul 2010 01:23:09", "title": "distribute, pip", "type": "regular", "slug": "distribute-pip", "reblog-key": "nYEAOjtB"}
27 857328074-distribute-pip.md
@@ -0,0 +1,27 @@
+최근에 [`setuptools`][setuptools] 대신 [`distribute`][distribute]를, [`easy_install`][easy_install] 대신 [`pip`][pip]를 쓰기 시작했다.
+
+조금 설명하자면, `setuptools`는 Python 표준 라이브러리에 있는 `distutils`를 확장한 것인데, `distutils`는 Makefile 같은 빌드 스크립트의 Python 버전이다. Ruby의 `rake`나 Java의 Ant를 생각하면 된다. 표준 라이브러리에 있기 때문에 Python에서 프로젝트를 패키징하고 빌드 자동화를 하는 가장 기본적이고 표준적인 방법이라고 보면 된다. `setuptools`는 `distutils`의 확장 인터페이스를 이용해[^1] 의존성 해결(dependency resolution)도 해주게 만든 것이다. 보통은 setup.py 파일을 아래처럼 작성하므로 `setuptools`가 설치되어 있지 않아도 빌드는 가능하다.
+
+ try:
+ from setuptools import setup
+ except ImportError:
+ from distutils.core import setup
+
+`distribute`는 `setuptools`를 대체하기 위해 리팩토링한 버전이다. 사실 `setuptools`의 차세대 대안이라고들 말해서 쓰긴 하지만 나도 정확히 어떤 잇점이 있는지는 모른다. 다만 요즘 여러 패키지들이 `distribute`로 패키징을 하다보니까 가끔 `setuptools`에서 설치되지 않는 경우가 있어서 설치하게 되었다. `distribute`의 가장 큰 목표가 `setuptools`를 완전히 대체하는 것이기 때문에 저게 설치되면 `setuptools`를 완전히 갈아치워서 `import setuptools`를 해도 실제로는 `import distribute as setuptools`한 것처럼 작동한다. `setuptools`와의 호환성도 유지하지만 `distribute`에만 있는 기능을 쓴다면 제대로 `setuptools`만으로는 당연히 제대로 설치되지 않는다. 그리고 가끔 의존성에 아예 `distribute`를 넣어두는 패키지가 있어서, 그걸 설치하면서 쥐도 새도 모르게 설치되기 쉬운게 바로 `distribute`라고 할 수 있겠다.
+
+`setuptools`나 `distribute`는 정확히 말해서 의존성의 전체 목록과 설치 순서를 계산해주며, 실제로 의존하는 패키지들을 [PyPI][]에서 다운로드하고 순서대로 설치하는 것은 `easy_install` 명령어가 구현한다. 다만 `easy_install` 명령어가 `setuptools` 패키지를 설치하면 생기기 때문에 보통 `setuptools`가 `easy_install`이라고 기억하는 사람도 적지 않다. `pip`는 `easy_install` 명령어의 차세대 대안이다. 이건 라이브러리가 아니라 프론트엔드이기 때문에 명령어의 하위호환성을 갖는 것은 아니며, 더 나은 인터페이스를 제공하기 위해 중간 명령어를 추가했다. 예를 들어 `easy_install SQLAlchemy`라고 쓰던 것을 `pip install SQLAlchemy`처럼 쓰게 한 것이다(그래도 글자수는 더 적다). 눈에 띄는 가장 큰 개선점으로 두 개가 있는데:
+
+ - 설치했던 패키지를 `uninstall` 명령어로 쉽게 삭제할 수 있다.
+ - 일단 의존하는 모든 패키지를 다운로드를 받고 나서 설치한다. 따라서 설치하다가 중간에 네트워크 문제로 중단되더라도 일부만 설치되는 일이 없다.
+
+`pip`는 `distribute`가 나오기 전에 만들어진 것이고, `easy_install`만을 대체하기 위해 만들어졌으므로 `setuptools`와 `pip`를 함께 쓰는 경우도 많다. 물론 반대로 `distribute`를 설치해서 `easy_install` 명령을 여전히 사용하는 경우도 있다. 내가 바로 얼마 전까지`distribute`와 `easy_install`을 함께 사용하다가 최근부터 `pip`를 쓰기 시작했는데, 아무래도 `pip`는 프론트엔드이기 때문에 사용자로서 개선되었다는 느낌을 더 강하게 받는 것은 `distribute`보다는 `pip`인 것 같다.
+
+ [^1]: 사실은 꼭 주어진 확장 인터페이스만 곧대로 쓰는 것은 아닌 모양이다.`distutils`가 원래 의도하지 않은 방향으로 핵(hack)도 조금 하는듯.
+
+ [setuptools]: http://peak.telecommunity.com/DevCenter/setuptools
+ [distribute]: http://packages.python.org/distribute/
+ [easy_install]: http://peak.telecommunity.com/DevCenter/EasyInstall
+ [pip]: http://pip.openplans.org/
+ [pypi]: http://pypi.python.org/
+
+ *[PyPI]: Python Package Index
1  891307068-nintendo-dsl.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-08-02 03:06:00 GMT", "url": "http://blog.dahlia.kr/post/891307068", "url-with-slug": "http://blog.dahlia.kr/post/891307068", "format": "markdown", "-slug": "-nintendo-dsl", "id": "891307068", "unix-timestamp": "1280718360", "date": "Mon, 02 Aug 2010 12:06:00", "type": "regular", "slug": "nintendo-dsl", "reblog-key": "KuRQXOav"}
7 891307068-nintendo-dsl.md
@@ -0,0 +1,7 @@
+며칠 전에 여자친구로부터 Nintendo DSL을 빌려서 포켓몬스터 소울실버를 플레이하고 있다. 그래픽도 많이 좋아지고 이게 정말 포켓몬스터 게임이 맞나 싶을 정도.
+
+![악어♥의 할퀴기 공격!](http://me2day.phinf.naver.net/20100728_250/me2photo_1280309256976n6VBL_jpg/crocodile_1280309256_33466_me2photo.jpg)
+
+문제가 하나 있는데 NDSL은 배터리가 얼마나 남았는지 표시해주는 불이 너무 작고 신경쓰기 힘들게 되어 있어서 사용자에게 전원이 꺼질 위험을 잘 알려주지 못하는 것 같다. 게다가 게임의 상태가 롬에 저장되기 때문에 세이브하는데 무척 오래걸린다. 세이브가 오래 걸리다보니 자꾸 기다리는게 싫어서 세이브를 띄엄띄엄하기 십상인데, 내가 어제 그러다가 배터리를 단 쓴줄도 모르고 불시에 전원이 꺼져서 피봤다. 거의 세 시간 가량 플레이했던 게 날아갔다. <del>내 레벨 22 롱스톤 내놔!</del>
+
+내 생각엔 분명 전원이 위험하기 전에 게임 모니터 안쪽에서 소프트웨어적으로 표시해줄 수 있을 것 같은데 Nintendo가 그걸 고려하지 않은 것 같다. 어쩌면 내부 API에는 그런 상황에 호출될 수 있는 이벤트 핸들러를 제공하는데 포켓몬스터 소울실버 만든 쪽에서 콜백 등록을 하지 않았을 수도 있다. 하지만 둘 다 같은 회사에서 만든 건데 설마 그럴까.
1  905808670.json
@@ -0,0 +1 @@
+{"date-gmt": "2010-08-05 03:10:27 GMT", "url": "http://blog.dahlia.kr/post/905808670", "url-with-slug": "http://blog.dahlia.kr/post/905808670", "format": "markdown", "-slug": "", "id": "905808670", "link-url": "http://me2day.net/dahlia/2010/08/05#12:07:35", "unix-timestamp": "1280977827", "date": "Thu, 05 Aug 2010 12:10:27", "type": "link", "slug": "", "reblog-key": "BSDfbRV7"}
6 905808670.md