Code Metaphor

Programming, Writing, Reading, Thoughts…

이 블로그는 더이상 운영되고 있지 않습니다. 단지 예전 URL을 유지하는 용도로만 남아 있습니다. 새 블로그의 주소는 blog.dahlia.kr입니다.

Archive for October, 2009

전역적인 상태

Monday, October 19th, 2009

전역 변수(global variables)나 싱글톤 패턴(singleton pattern)을 두고 어떤 사람은 악이라고도 하고, 어떤 사람은 필요악이라고도 한다. 어쨌든간 나는 저러한 구체적인 것에 대해 좋으니 나쁘니 하는 것은 사실은 별 생각이 없다는 증거라고 생각한다.

나는 전역적인 상태(global state)가 문제라고 보는데, 방점을 찍을 부분은 “전역”보다는 “상태”이다. 반대로 상태를 가지는 것이 아니라면 전역적이어도 아무런 문제가 없다는 뜻이다. 기본적으로 전역적인 것은 아무데서나 참조 가능하다는 이야기다. 그런 식이면 클래스 이름이나 함수 이름도 결국은 전역적인 것이 된다. 그러나 아무도 전역 상수(global constants)에 대해 뭐라고 떠들지는 않는다. 결국 실행 시간에 바뀌는 것이 아무데서나 간섭받으면 프로그램이 꼬이기 십상이라는 말이다. 바뀌지 않으면 문제가 되지 않는다.

값 객체(value object)라고도 하고 상태 없는 객체(stateless object)라고도 하고 변형되지 않는 객체(immutable object)라고도 하지만, 이름이야 어쨌든 객체는 변경되지 않도록 디자인되는 게 좋다고 생각한다. 모든 연산은 가능하면 자기 자신을 수정하는 대신, 새로운 객체를 반환하는 편이 낫다. 성능의 문제가 있지만, 이런 부분은 컴파일러 등의 언어 구현이 잘 해내야 할 몫이라고 생각하는 편이다.

나는 비슷한 관점에서 Ruby의 열린 클래스(open class) 정책이 안 좋은 면도 많이 포함한다고 생각한다. 물론 Python 등의 언어도 클래스가 런타임에 수정 가능한 객체이긴 하지만, Ruby 공동체는 실행 시간에 클래스를 수정하는 짓을 장려하는 문화를 갖고 있다는 점이 큰 차이다. 게다가 Ruby 언어는 그것을 깔끔하게 해낼 수 있도록 문법이 설계되어 있다.

전역적인 상태의 또 다른 문제는 여러 상태가 존재해야할 필요성이 생기면 바로 문제가 생기는 디자인이라는 점이다. 예를 들어 간단한 웹 서버를 내장한 애플리케이션이 있다고 치자. 원래는 80 포트에 하나의 웹 서버만 있으면 됐지만, 둘 이상의 포트에 연결되어 여러 웹 서버를 돌릴 필요가 생기게 되는 식의 상황은 생각보다 적지 않다. (웹 서버 대신 예를 들 다른 것들도 많을 것이다.) 처음에 전역적인 웹 서버를 가지고 있었다면, 여러 웹 서버 인스턴스를 생성할 수 있도록 고치는 작업은 꽤 성가신 일이 될 것이다. 게다가 어떤 객체가 전역성을 띄게 디자인되었다는 것은 그 객체가 다중화될 여지가 없다는 확신이 있어야 가능하기 때문에, 그러한 확신 아래 코드 곳곳에서 신나게 전역 객체와 직접적으로 참조를 하고 있을 가능성이 높다.

서상현 씨가 프레임워크와 라이브러리의 차이에 대한 훌륭한 아포리즘을 적으신 적이 있는데,

내가 부르면 라이브러리고, 내가 불리면 프레임워크다. 같은 값이면 라이브러리가 프레임워크보다 낫다.

프레임워크 역시 그 자신이 전역적인 상태를 가진다는 점에서 같은 문제를 공유한다. 여러 프레임워크 인스턴스를 가질 수는 없다. 만약 그게 가능하다면 라이브러리라고 불러야 한다. “같은 값이면 라이브러리가 프레임워크보다 낫다”는 이야기는 정말 지당한 말이다.

물론 여기서도 문제가 되는 것은 그 객체가 상태를 가질 때 뿐이다. 상태를 가지지 않는다면 굳이 다중화할 필요가 없다. 결국 라이브러리는 상태를 갖지 않거나 전역적이지 않고(둘 중 하나라도 만족하면 라이브러리다), 프레임워크는 전역적인 상태를 갖는다고 표현할 수도 있다.1

결국 정말 문제가 되는 것은 전역성이 아니라 상태를 가지고 있는지 여부이다. 전역성은 상태를 가지고 있는 객체의 문제를 특히 두드러지게 하는 요소일 뿐이다.


  1. 쓰고 보니 동어반복. 

Pandoku: Ruby에서 Pandoc 쓰기

Monday, October 12th, 2009

Pandoc은 Markdown, HTML, LaTeX, ReST, DocBook 등 굉장히 많은 포맷 간의 상호 변환을 해주는 도구인데,

Pandoc is a Haskell library for converting from one markup format to another, and a command-line tool that uses this library. It can read markdown and (subsets of) reStructuredText, HTML, and LaTeX, and it can write markdown, reStructuredText, HTML, LaTeX, ConTeXt, PDF, RTF, DocBook XML, OpenDocument XML, ODT, GNU Texinfo, MediaWiki markup, groff man pages, and S5 HTML slide shows.

커맨드라인 툴이기도 하고, Haskell 라이브러리이기도 하다. Pandoc의 특징은 모든 마크업 포맷을 내부 중간 표현 형식으로 한번 만든 다음에, 그것을 다시 출력한다는 점이다. 그래서 HTML 문서를 읽어서 MediaWiki 마크업으로 출력한다던가, Markdown 문서를 읽어서 유닉스 man 페이지를 만든다던가 하는 게 가능하다.

게다가 단순히 Markdown 구현으로 봐서도 사실 다른 구현과 비교하기 힘든 정확도성능을 가지고 있기도 해서, 내가 가장 애용하는 Markdown 구현이기도 하다.

아무튼 최근에 Ruby에서 이걸 써야할 일이 있어서 인터페이스 모듈을 만들어봤다. Ruby가 일본제니까 약간 일본 느낌 나게 이름을 Pandoku라고 지었다.

http://github.com/lunant/pandoku

처음에는 C 인터페이스로 라이브러리를 만들어서 붙이는 것을 생각했지만, Haskell에서 그게 쉽지 않아서 파이프로 통신하게 했다. Gem 배포는 Gemcutter를 이용해서 하고 있다. http://gemcutter.org/gems/pandoku

gem install pandoku

Pandoc 바이너리가 필요한데, 없으면 cabal로 설치하면 된다. Cabal은 Haskell 패키지 매니저다.

cabal install pandoc

Pandoku는 기본적으로 PATH 환경변수에서 pandoc을 찾는다. 만약 PATH에 없다면 별도로 PANDOC_PATH 환경변수를 정의해도 된다.

export PANDOC_PATH="$HOME/.cabal/bin/pandoc"

Ruby에서의 사용은 String#pandoku 메서드를 통해 가능하다. (좀더 복잡한 방식이 있긴 하다.)

require 'pandoku'
result = document.pandoku(:markdown => :html)

Powered by WordPress. Styled by Hong, MinHee. XML Feed, Comments XML Feed.