Software Development

Threads Considered Harmful

Threads Considered Harmful

Summary

쓰레드(thread)의 문제점을 지적한 것으로 상당히 유명한 글 중에 하나가 바로 Kuro5hin에 올라온 ‘Threads Considered Harmful ‘이라는 글이다. 이 글의 주요 논지는 shared state에 대한 synchronization을 제대로 하는 것과 dead lock을 방지하는 것이 어렵고, 이를 탐지하기가 어렵기 때문에, 쓰레드(thread)를 사용하지 말아야하고, 그 대안으로 Multiple processes, Event-based programming, Co-operative threads (co-routines) 등의 방법을 사용해야한다는 것이다.

Detailed Review

맨 첫 문단에서 이 글의 저자는 다음과 같이 얘기하고 있다.

once you have spawned a thread, there is no way to know anymore which line is being executed in parallel with yours.

이 얘기는 ‘Go To Considered Harmful‘에서 Dijkstra가 주장하고 있는 프로세스의 진행 정도를 표현할 수 있는 의미있는 좌표가 존재해야한다는 아이디어를 thread에 적용한 것이다. 하지만, 적어도 구조적인(structured) 프로그램을 수행하는 여러 thread의 진행 정도를 표현하는 의미있는 좌표는 존재한다. ‘Go To Considered Harmful’ 논문에 대한 리뷰 글에서 설명한 방식을 빌려오자면, 우리가 여러 쓰레드를 사용하는 프로그램을 디버깅하기 위해 멈췄을 때, 우리는 모든 쓰레드의 진행 정도를 각 쓰레드의 stack trace를 통해서 알 수 있다. 글의 저자는 문제를 약간 잘못 설명하고 있다. 진짜 문제는, 서로 간에 side-effect를 미칠 수 있는 쓰레드들이 어떤 식으로 수행되느냐에 따라 결과가 달라지기 때문에, 프로세스의 진행 정도를 알 수 있다고 해서 디버깅을 할 수 없게된 것이다. Dijkstra가 위의 논문 처음에서 내세웠던, 정적인 프로그램과 동적인 프로세스 간의 상응성을 단순하게 만들기 위해서는 프로세스의 진행 정도만으로는부족한것이다.

예를 들어, a-b-c-d라는 프로그램을 수행하는 두 thread가 있어서 어떤 시점의 프로세스들의 진행 정도가 둘다 d라는 걸 알더라도, 실제로 수행된 순서가 ababcc인지 aabbcc인지를 알지 못하면 디버깅을 불가능한 것이다.

여담으로, 쓰레드를 하나의 프로세스로 보지 않고,모든 thread를 각 쓰레드가 수행하는 프로그램이 랜덤하게 수행되는 하나의 프로세스로 본다면, 프로세스의 진행 정도를 표현할 수 있는 좌표 자체가 존재하지 않는다고 볼 수도있다. 이 문제에 여러 프로세서(SMP)의 문제까지 끼어들면 더욱 복잡한 모델이 된다.

한편, 다음 문장이 여러 쓰레드를 사용하는 프로그램의 디버깅이 힘든 이유를 한마디로 표현하고 있다.

The chief problem with threads are race conditions and dead locks. Both tend to occur randomly.

친절하게도 자세한 예를 들어 synchronization의 어려움과 dead lock을 방지하는 것의 어려움을 강조하고 있고, dead lock을 방지하기 위해 lock들의 순서를 지키는 것이 부담스러워서 coarse-grained lock을 쓴다면 performance 저하의 문제가 있음을 지적한다.

저자가 쓰레드를 사용하는 것에 어떠한 이익도 없다고 결론 내리고 대안으로 내세운 것은 Multiple processes, Event-based programming, Co-operative threads (co-routines)가 있다.

My Opinion

  1. 쓰레드의 필요 뿐만 아니라 쓰레드의 대안들에서 오는 복잡성은 모두 concurrently shared state (또는 resource)의 필요에서 발생한다. concurrently shared state가 전혀 없다면 물론 쓰레드를 사용할 필요는 없다. 글의 저자가 주장한 것과 같이 하나 또는 그 이상의 프로세스를 사용해도 되고, 설령 쓰레드를 사용한다고 하더라도 글의 저자가 우려하는 것과 같은 사태는 절대 발생하지 않는다. 하지만, 많은 프로그램은 어느 정도의 concurrently shared state를 필요로 한다. 그것이 메모리 조각이든, 객체든, 파일과 같은 커널 리소스든, 그것이 공유되기 시작하면, 여러 프로세스에서도 똑같은 문제가 발생하기 시작한다. 복잡성의 원인은 해결법(쓰레드)에 있는 것이 아니라 궁극적으로 우리가 풀어야하는 문제 자체에 내재하고 있는 것이다.
  2. shared state vs. messaging 문제. shared state와 messaging 사이에 어느 것을 선택할 것이냐 하는 것은 컴퓨팅의 역사에서 항상 반복되어온 문제다. OS의 디자인이나 구현을 보다보면, 어떤 resource (또는 state)에 대한 접근을 strict하게 제한할 것이냐, 아니면 시스템이 fragile하지 않는 한 느슨하게 허용할 것이냐의 trade-off 문제가 상당히 자주 등장한다. 여기에는 성능이나 디자인 등의 문제가 복잡하게 게재된다. 쓰레드를 쓸 것이냐의 문제도 trade-off 문제에 불과하다고 생각한다.
  3. 적절한 대안의 부재: 프로그래밍은 계속 더욱 높은 레벨의 abstraction을 지향해서 언젠가는 이런 고민을 하지 않아도 될 날이 올 것이다. 하지만, 현재로서는 만족할만한 대안이 없는 것이 사실이다. 프로세스는 concurrently shared state가 없다는 가정하에서 쓰레드와 다를 바는 없고, 이벤트 기반 프로그래밍은 쓰레드 만큼의 어쩌면 더 많은 복잡성을 프로그램 내에 도입할 뿐만 아니라, 쓰레드 지원이 허름하던 시절의 성능 이점을 가져다 주지도 않는다. (쓰레드 프로그래밍과 이벤트 기반 프로그래밍의 비교에 대해서는 다음 기회에 글을 써보도록 하겠다.) Parallel programming 문맥에서의 Co-routine은 go to를 대체하는 loop와 같은 programming constructs의 역할과 비슷한다고 생각되는데, 주요 프로그래밍 언어에서 구현되어 있지 않을 뿐만 아니라, (그 때문에) 보편적으로 practice가 확립되어있지 않다. (학교에서 가르치지 않는다.)

Conclusion

concurrently shared state라는 문제 자체의 복잡성이 쓰레드 프로그래밍이나 이벤트 기반 프로그래밍의 복잡성을 야기하고, 어느 해결책을 선택하느냐는 trade-off의 문제이나, 현재로서는 쓰레드가 더 나은 해결책으로 보인다. go to를 대체하는 loop constructs와 같이 쓰레드를 대체하는 프로그래밍 언어 레벨의 해결책이 필요하다는 것에는 크게 공감한다.

Threads Considered Harmful 더 읽기"

Prefer java.net.URI to java.net.URL

Prefer java.net.URI to java.net.URL

Problem of java.net.URL

URL의 host 부분의 equivalence가 host string의 equivalence를 기준으로 하는 것이 아니라, IP address의 equivalence를 기준으로 한다. 또한, equivalence 관련 메서드 (equils(), hashCode())이 일어날 때마다, IP address resolving을 동반한다.
equivalence 관련 operation이 사용되지 않는다면 별로 문제가 없으나, equivalence 관련 메서드를 자주 사용하면, 상당히 느릴 수 있으며, HashMap의 key로 java.util.URL을 사용할 경우, host 부분만 다르고 각 host들의 IP가 같다면, HashMap에는 하나의 key만이 등록되는 의도하지 않은 문제가 발생할 수 있다.

Solution

1. Overriding java.net.URLStreamHandler

java.util.URL 클래스의 equivalence 관련 구현은 모두 java.util.URLStreamHandler의 구현에 위임되어있다. 그리고 java.util.URL 클래스는 static 메서드인 setURLStreamHandler()를 통해, 이 구현을 변경할 수 있다.

2. Using java.net.URI

Java 1.4에 java.net.URI가 추가되었고, 이 클래스의 equivalence는 String representation의 equivalence와 동일하다. java.net.URL의 hashCode() 메서드는 각 파트에 해당하는 String.hashCode()의 합인 반면, java.net.URI의 hashCode() 구현은 제대로 된 hash 값을 구하도록 구현되어있다.

References

Prefer java.net.URI to java.net.URL 더 읽기"

Framework 2.1: RubyOnRails vs. TurboGears, Part 1

지난 토요일에 Framework 2.1이라는 행사에 다녀왔다. Framework 2.1은 웹 개발 프레임워크의 대안을 모색하기 위한 행사이고, 대안언어축제에서 파생된 행사인 듯 하다. 이번 행사는 RubyOnRails와 Django를 각각 소개하고, 그 둘을 비교하는 패널 토의를 하고, 다음번 행사에서 소개할 TurboGears와 Seaside를 간략하게 소개하는 형식으로 진행되었다.

행사장은 NCsoft에서 지원해주었는데, 참석한 인원이 꽤 많아서 행사장이 상당히 좁았다. 하지만, 이런 행사를 지원해주는 게 어딘가. 개발자들, 특히 뛰어난 개발자일 수록, 연봉이나 복지만으로 회사를 선택하지는 않는다. 치열해져가는 경쟁 속에서 뛰어난 개발자를 고용하기 해서는 이런 투자도 어느 정도 필요하다고 생각한다. NCsoft 외에도 어느 정도 업계에서 성공한 회사들이 개발자 커뮤너티를 지원해주는 문화가 앞으로는 널리 정착되었으면 좋겠다.

기조연설 – 이만용 님

기조연설은 이만용 님이 해주셨는데, 역시 연륜이 있으신만큼 (그렇게 보이시는 만큼) 언변도 좋으셔서서로 모르는 개발자들이 모인 자칫 딱딱할 수 있는 자리를 재미있고 부드럽게 만들어주셨다.

이만용님은 APM, Python CGI, Zope 등을 시도해보시다가 Django와 TurboGears들 중 최근 TurboGears를 선택했다고 하셨다. ‘Write-only code’라는 말로 웹 개발의 현주소를 표현하셨다. 애자일 프로그래밍 언어와 MVC가 필요하다는 언급을 하셨다.

RubyOnRails – 황대산

첫번째 세션은 황대산님의 RubyOnRails 세션이었다.

기본적인 튜터리얼을 진행하시고는 migrate, breakpoint, association, routing 등의 약간의 고급 기능도 설명해주셔서 재미있게 들을 수 있었다. 그 중에 migrate가 가장 흥미로웠는데, 대부분의 웹 어플리케이션들은초기에 DB 셋업이라는 벽을 뛰어넘어야하기 때문에, 대단히 사용하기가 어렵기 마련인데, migrate를 사용해 각 버전간의 변경사항에 대한 transaction을 ruby code로 기술해주는 것만으로, 초기 DB 셋업 뿐만 아니라 버전간 migration (원래의 목적으로 보이는)도 편하게 수행할 수 있었다.

breakpoint는 script를 통해서 설정된 breakpoint 시점의 환경에 접근할 수 있게 해주는 기능이고, association은 DB schema만으로 표현할 수 없는 객체간의 관계를 선언적으로 설정해주는 기능이다. association 선언에는 객체 이름 외에는 아무것도 필요하지 않기 때문에, 역시 rails의 전체를 관통하는 철학인 convention을 사용하고 있음을 알 수 있다. routing은 rails의 디폴트 URL convention에서 벗어나 이를 customize할 수 있는 방법을 제공한다.

이 외에도 기본적인 validation, javascript를 쓰지 않아도 되게 해주는 RJS, web services를 지원하기 위한 webresource와 같은 기능도 간략히 소개되었다.

질답 시간에는 웹 어플리케이션에서 자주 필요로 하는 기능 중 하나가 authentication/authorization인데, 이를 rails에서 어떤 방식으로 support하는가라는 질문을 던졌는데, rails에서는 이러한 기능이 core에 들어있진 않고 extension/plugin 수준에서 지원한다고 한다.

실제로 rails가 사용되는 곳이 어떤 곳이 있는가라는 질문이 2번씩이나 나왔는데, 미국에서는 역시 유명한 43things, basecamp, campfire, writeboard, 그리고 odeo라는 podcast directory 사이트가 있고, 한국에는 olaworks가 있다고 한다. (olaworks가 유일한 사이트?)

rails를 통해서 SQL, javascript, CSS를 쓸 필요가 없어진다고 한다. 여러가지 언어와 여러가지 환경에서 프로그래밍을 한다는 것은 생산성을 떨어뜨리는 요소중의 하나다임에 틀림없다. 하지만, SQL, javascript, CSS는 부차적인 문제다. 언제쯤이면 HTML을 쓰지 않고도 웹 어플리케이션을 만들 수 있을까? ;-)

Django – 김형용, 이정민

Django (장고, 혹은 쟁고) 는 웹 개발 프레임워크들간의 비교에서 흔히 등장하는터라 이름을 들어봤지만, 자세한 내용을 보게된 것은 처음이었다.

일단 Django는 Model과 View로 나누어지고, 여기에 template이 추가된다. 이 때 View는 Model 2의 Controller 역할, template은 View 역할이라고 보면 된다. (MFC에서도 사용되었던 Document-View pattern에 따라 모델링된 듯 하다.)

Django는 하나의 project 아래에 다수의 application을 생성하는 구조를 가지고 있다. 어느 정도 규모가 있는 어플리케이션 쪽을 노리고 만들어진 느낌이 들었다. application을 추가(startapp)할 때마다 configuration에 해당 application을 추가하지 않으면 웹에 반영되지 않는 것이라든가 Model을 변경할 때마다 syncdb를 하는 것도 그런 느낌이 들게 만들었다.

project에는 admin application이 기본적으로 생성되는데 이를 이용해서 다른 application들의 데이터에 대한 기본적인 조회나 조작이 가능했다. 이 admin application은 authentiation까지 지원되는 대단히 완성도 있는 admin application으로 웹 어플리케이션을 만들 때 필요한 어드민 페이지를 만드는 수고를 어느 정도 덜어주고 있었다.

Django의 template은 variable의 값이나 variable에 (helper에 해당하는) filter를 적용한 값을 표시할 수 있고, 조건이나 반복을 위해서 미리 정의된 tag가 존재하며 이를 확장할 수 있었는데, 이는 JSP와 거의 유사한 것이었다. Django의 View도 Struts의 Controller와 거의 유사한 모양새를 가지고 있었다. 즉, Model에서 특정한 context들을 만들어낸 후, 각각에 적당한 이름을 부여하여 template에 넘겨주는 방식이었다.

Django의 middleware는 정해진 interception point에서 동작하는 일종의 filter로 최소한의 AOP를 구현하고 있었다.

Framework 2.1: RubyOnRails vs. TurboGears, Part 1 더 읽기"

소프트웨어 품질 희생의 일상화

"그렇게 하는 게 좋은 건 알겠는데, 개발이 느려지잖아."

소프트웨어 프로젝트에 있어서 빠른 개발 즉, 효율성이 중요하다는 것은 누구나 공감하는 사실일 것이다. 수많은 방법론들과 도구, 라이브러리, 프레임워크들은 한결같이 ‘효율성’을 강조한다. 그렇다면 소프트웨어 제품에 있어서 효율성이란 무엇인가? 시간당 코드 라인 수? 일주일에 구현하는 기능의 수?

가장 간단하게 정의한다면, 시간당 추가되는 소프트웨어의 기능과 품질이 될 것이다.* 하지만, 많은 사람들은 이 효율성이란 기준에서 품질을 무시한다. De Marco가 Peopleware에서 언급했듯이, time-to-market 압박에 가장 먼저 희생되는 것은 기능이 아니라 소프트웨어 품질이다. 소프트웨어의 품질**은 고객이나 매니저의 눈에 띄지도 않기 때문이다.

물론, 현실적으로 기능에 대비해 품질을 희생할 수 밖에 없는 상황은 비일비재하다. 어느 날 갑자기 사장이 인터뷰를 통해서 다음달에 어떤 소프트웨어 제품이 나올 거라고 공언해놓고, ‘자 이제부터 이러이러한 소프트웨어를 만들어라’ 하면서 일감을 던져주는 것을 받아본 경험은, 소프트웨어 개발자로서의 경험이 어느 정도 있는 사람이라면 한번 정도씩은 있을 것이다. 이러한 문제가 너무나 심각해서, 어떤 사람들은 품질을 희생하는 것이 아니라 오히려 기능을 희생해야 한다고 얘기하기도 한다. 무엇이 옳든 간에, 소프트웨어의 기능과 품질을 둘 다 만족시킬 수 없는 상황에서 이 문제는 전형적인 trade-off 문제가 된다. 현재 개발자 커뮤너티의 대체적인 의견은 이러한 trade-off에 의한 품질의 희생은 불가피하며 iterative development를 통해서 극복이 가능하다고 생각하는 편이다.

문제는, 효율성을 이유로 들어 소프트웨어 품질의 희생을 일상화하는 경우다. 소프트웨어 품질을 일상적으로 희생하게 되면, 소프트웨어 라이프사이클이 이어질수록 소프트웨어 효율성에 나쁜 영향을 미친다. 결국에는 그 소프트웨어를 버리거나 그냥 대충 때우는 것 외의 대안이 없는 상태가 되어버린다. 물론 모든 소프트웨어가 긴 수명을 가지지는 않는다. 학교에서의 소프트웨어 프로젝트와 같은 일시적으로 필요한 단순한 소프트웨어나, 빠르게 사용자 요구가 변화하고 사라지곤 하는 웹 어플리케이션과 같은 경우에는 품질을 희생하더라도 별 문제가 없을 수 있다. 하지만 반대로, 긴 수명을 가지는 소프트웨어도 존재한다. 그러한 소프트웨어를 매번 버리고 새로 만드는 것은 프로토타이핑의 목적이 아니라면 매우 비효율적이다. 설령 어떤 목적으로 (이를 테면, 경험이 부족한 도메인의 실험적인 프로젝트) 매번 버리고 새로 만든다 하더라도, 그럴 때마다 기존의 것을 가능한 한 재사용하는 방식을 추구해야 한다.

소프트웨어의 품질이 지속적으로 효율성에 영향을 미치는 장기적인 소프트웨어 프로젝트에서, 소프트웨어 품질의 희생을 일상적으로 받아들이는 태도는 잘못된 것이다. 마치 고급 아파트를 지을 때의 마감공사를 조립식 건물을 지을 때처럼 대충하는 것과 다를 바가 없다. 이러한 태도는 소프트웨어 품질 자체에 관해 무지하거나, 소프트웨어 프로젝트의 수명에 따라 품질에 대한 태도를 다르게 해야 한다***는 사실에 대해 무지하거나, 소프트웨어 프로젝트의 수명에 대해서 착각을 하고 있기 때문에 발생하는 것이다.

어떤 사람은 소프트웨어 품질에 대한 태도가 단지 개발자 개개인의 ‘스타일’의 문제이고 이를 받아들여야 한다고 얘기한다. 물론, 특정 도메인에서 소프트웨어 개발을 지속적으로 해온 사람은 소프트웨어 품질에 대한 특정한 태도를 내면화하여 그것을 ‘스타일’로 가질 수는 있다. 하지만, 그것이 ‘스타일’이라고 해서 합리화될 수는 없는 것이다. 소프트웨어 품질에 대한 태도는 개발자에 따라 달라지는 것이 아니라 소프트웨어 제품 또는 프로젝트에 따라 달라져야 하는 것일 뿐이다. 여기서 ‘스타일’이라고 지칭되는 것은 사실상 ‘습관’에 불과한데, 대부분의 평범한 소프트웨어 개발자들은 자신의 습관에 따라 행동하고, 때로 특정한 도메인이나 특정한 소프트웨어 프로젝트에서는 그 습관을 통해 최고의 능력을 보여줄 수도 있다. 하지만, 뛰어난 개발자들은 그러한 습관을 내면적인 규칙(discipline)을 통해 극복하고, 도메인이나 소프트웨어 프로젝트에 따라 서로 다른 적절한 태도를 취하고, 어느 곳에서나 최고의 능력을 보여줄 수 있다.

결국, 장기적인 소프트웨어 프로젝트에서 조차도, 소프트웨어 품질 희생의 일상화를, 효율성을 근거로 하여, 합리화하기를 즐기는 사람들은 대체로 자신의 습관이나 부족한 능력에 대한 변명을 하고 있을 뿐이다. 정말로 뛰어난 개발자는 거의 항상 (최고가 아니라) 적절한 – 기능과 품질 양쪽 모두에서의 – 효율성을 성취할 수 있기 때문이다.

* 소프트웨어의 특성을 기능과 품질로 양분한 것은 논의의 간결함을 위한 것이다. 소프트웨어는 그 복잡성만큼이나 요구되는 특성들이 많다.
** 이 때, 소프트웨어의 품질이란, 소프트웨어라는 제품이 가지는 특성으로서의 품질이 아니라, 소프트웨어 자체의 품질, 굳이 예로 들자면 코드의 품질과 같은 내부적인 특성을 얘기한다.
*** 소프트웨어의 수명만이 소프트웨어 품질에 대해 요구되는 태도를 결정짓는 것은 아니다. 다양한 비즈니스적인 요구나 도메인에 대한 개발자의 지식 등 여러 가지 요소들이 모두 영향을 미칠 수 있다.

소프트웨어 품질 희생의 일상화 더 읽기"

An Interview with Tim Converse

Yahoo! Content group의 engineering manager인 Tim Converse가 Crawler trap과 redirection에 대해서 언급하고 있다.

Excerpted from An Interview with Tim Converse, part 2 (emphasis made by me):

JQ: You talked about comprehensiveness. There’s this perception that there’s the web that most of us see and then this dark web: the stuff that the crawlers don’t reach. How do we try to get that data into the index? Are there barriers that webmasters put up that they should avoid to help us better index the content?

A: At it’s simplest, webmasters aren’t aware of robots.txt and it’s uses. Redirection can also be problematic if people create content by creating lots of domains or hosts so we encourage people to organize their sites in many documents before they get a new host.

And of course, there’s also the issue of crawler traps which some people do intentionally but much more often, they’ve unintentionally created crawler traps….

JQ: …and a crawler trap is…

A: A crawler trap is something where you crawl a page and it has a link, usually in the same site that’s dynamically created and then you follow that link and it has another analogous link that’s dynamically created and often, just because people make mistakes, you’re attaching on another directory every time which doesn’t exist and takes you back to an automatically generated error page which has the same link. So you can fall into traps where there are an infinite number of pages that don’t have any content.

Another thing people can do to help us is, this is sort of geeky but, don’t make page not found pages that return a status 200.

JQ: I was just about to ask that. 404 pages back in the day, were these ugly grey things with block text that all looked the same and now they’re done up to look like regular pages to be more appealing to users.

A: We do actually have ways of detecting that but it’s a lot easier for us if a web server just says, "this page doesn’t exist" as opposed to creating a nice page for the user that to a crawler looks like any other page. In general, if the server tells us 404, then we discard it.

YQ: I worked for a company that used CIDs instead of cookies to follow users through the site and it turned out to be a disaster. We went from having pretty much every page indexed to hardly any. So what about CIDs and how they affect the crawlers?

A: If you have differences in the URL that don’t actually make a difference in the site, that can be hard for us to untangle. We’re getting better at it. One of the scenarios you’re talking about there would just create a lot of duplicates for us. So it’s nicer for us if we have one URL per actual content but we understand that you’re not designing this just for us. And we obviously do a lot of duplicate detection–actually, we do duplicate detection in a couple of different ways. Finding out if documents are the same; finding out if sites are mirrors of each other.

JQ: This question came up today on a mailing list that I’m on. The concern for this particular company is that they want to move their site to a new domain but they don’t want to become invisible for the next six months or year or however long it’ll take for people to point to their new website. What can we tell people like that?

A: We can tell them that in the future, if you actually want to move your site, you want to use a 301 redirect which will do as much of the right thing as we can.

YQ: What actually happens there? I’ve heard of companies who have used 301 redirects and yet their old pages continued to show up in the search engines anyway. Why is that?

A: The underlying problem is that people out there haven’t changed their links and search engines do pay attention to links.

I can’t give you a date, but we’re changing how we deal with redirects. The thing about redirects is that everyone thinks it’s obvious how a search engine should treat them and the obvious answer is not really that helpful. Any policy you develop with redirects is going to make someone unhappy but what we’re about to roll out we will pay better attention to 301 redirects and the exact problem you’re talking about should be less.

[In the time since we met with Tim, the team has rolled out a fix for 301/302 redirects. Documents will be handled by the new redirect policy as they are re-crawled and re-indexed and webmasters will start to see many of the sites change in the next couple of weeks. The index should be fully propagated within a month. See Tim Mayer’s Webmaster World presentation for details.]

An Interview with Tim Converse 더 읽기"

Sliding Gallery from Flickr

http://lastmind.net/beta/sliding_gallery/

팀 분위기도 어수선하고, 심심하고 해서, Kevin LeAjax-ready sliding gallery library를 이용해서 잡질을 약간 해보았습니다. Flickr (Flickr는 오늘도 다운타임이군요. 쯧쯧.)의 제 공개된 사진들을 연동하는 것이었는데요. 일단은 sliding gallery library를 활성화하고 데이터(즉, 사진들의 URL) 를 집어넣는, 그러니까 사용하는 js 파일을 생성하는 방식으로 만들어두었습니다. Flickr에서 데이터를 가져오는 부분은 Flickr.rb를 사용했습니다. (물론 ruby 라이브러리입니다.) 웹디자인은 그냥 라이브러리의 데모 페이지를 긁어왔으니 놀라시지는 않으시길 바랍니다.

동적으로 Flickr와 연동해주는 것이 최선이겠지만, 아직은 그럴 필요까지는 못 느끼고 있고, 귀찮은 면도 있어서, 적당히 돌아가는 것을 확인하는 정도로 그만두었습니다. 좀 더 public한 demo를 만들려면 물론 사용자 아이디를 입력받아주는 것이 좋겠지만, sliding gallery library 자체에도 몇가지 문제가 보이고 해서 일단은 hold하기로 했습니다. 당장 제 눈에 띈 library의 문제들은 다음과 같습니다.

  • 스크롤 크기가 static하게 정해져있어서, 사진 단위로 스크롤 되지 않는다.
  • Thumbnail 이미지들이 한꺼번에 로딩되서 수가 많아지면 페이지를 로딩하는데 한참 걸린다.
  • 처음 나올 큰 이미지가 html에 코딩되어있고, 적절한 Trigger를 발생시킬 지점이 없다. (전 직접 javascript로 코딩해넣었습니다.)
  • 클릭 이벤트 외에 스크롤 이벤트에 반응하도록 하는 콜백이 없다. (스크롤할 때 선택 이미지를 전환한다든가 하는 효과를 줄 수 없죠.)
  • 몇가지 버그들.

시간이 나면 제작자에게 컨택해서 얘기해보거나 직접 고쳐볼 요량입니다만, 귀찮아서 말이죠.

최근 들어 javascript 언어 기반의 라이브러리나 프레임워크들이 상당히 많아지고 성숙되고 있는 듯 하군요. Sliding Gallery library 같은 경우도 아직은 순수하게 따로 제작된 것들이나 상용 솔루션들보다는 못하지만, 조금만 더 다듬으면 재사용이 쉽다는 이익을 통해 그런 것들을 넘어서는 것도 시간 문제인 것 같습니다.

Sliding Gallery from Flickr 더 읽기"

A Brief Look at C++0x

Bjarne Stroustrup의 글 A Brief Look at C++0x에서는 C++ 프로그래밍 언어의 다음번 표준안인 C++0x에 대해서 소개하고 있다. C++0x에서의 변경사항에 대한 기본 원칙들을 먼저 설명하고, 언어상의 변화, 그리고 라이브러리상의 변화 순으로 내용을 전개하고 있으므로, C++0x에 관심이 있는 사람이라면 반드시 한번 읽어봐야할 글이다.

C++0x에 들어갈 라이브러리상의 변화에 대해서는 이 블로그에 여러번 적었기 때문에 이 글에서는 언급하지 않기로 하고, 다만 언어상의 흥미로운 변경사항들에 대해서 간략하게 적어보기로 한다.

Template alias (a.k.a. template typedefs)

template<class T> using Vec = vector<T,My_alloc<T>>;

template을 많이 활용하기 시작하면서 가장 먼저 느끼게 되는 불편함 중의 하나가 특정 template의 특정specialization을 반복해서 사용해야하는 경우가 잦아진다는 것이다. C/C++ 프로그래머가 이 때 떠올리는 것은 typedef 시스템이다. 즉, template의 specialization은 typedef로 재정의할 수 없을까? C++0x에서는 typedef 키워드를 사용하지는 않았지만, using 키워드를 사용해서 이러한 요구를 반영하고 있다.

template parameter의 끝에 달라붙는 >가 반복될 경우에 space가 더이상 필요하지 않아진 것도 눈여겨볼 만한 점이다.

Sequence constructor

Vec<double> v = { 2.3, 1.2, 6.7, 4.5 };

n1711문서를 소개하는 글에서도 언급을 했지만, array나 struct 뿐만 아니라 일반적인 user-defined type도 initializer list를 사용한 construction이 가능해졌다. 이를 통해서 array를 써야하는 경우는 거의 없어지고, vector 등 container들의 활용 가치는 훨씬 높아지리라고 예상된다.

Concepts

template<Container C, Predicate Cmp>
    where Can_call_with<Cmp,typename C::value_type>
    void sort(C& c, Cmp less);

최근 부각되고 C#, D 등의 언어에서는 이미 활용되고 있는 programming constructs 중 하나인 concepts는 C++의 커다란 특징 중 하나인 template의 강점을 더욱더 강하게 만들어주는 특징이 될 것이다. C++ standard library나 체계적으로 만들어진 C++ 라이브러리들에서는 이미 concepts의 개념이 항상 문서화되어왔었고, C++0x에서는 다만 그것을 프로그램 상에서도 명시 그리고 강제를 할 수 있게 해준 것이다. 이를 통해서 프로그래머가 생각하는 바를 좀 더 명확하게 표현할 수 있고 오류에도 무엇이 문제인지 좀 더 명확하게 표현될 수 있을 것이다.

Automatic type deduction

for (auto p = v.begin(); p!=v.end(); ++p)
    cout << *p << endl;

static typing을 사용하는 언어라고 해서 불필요하게 변수의 타입을 선언해야하는 것은 아니다. 주어진 context에서 컴파일러는 타입을 deduce해낼 수 있기 때문이다. auto라는 키워드가 그리 마음에 들지는 않지만, 당연해 보이는 루프 변수의 타입 따위를 기억해내는 데 노력을 들일 필요가 없어진다는 것은 마음에 쏙 든다.

More Information

그동안 C++0x의 라이브러리상의 변화에만 관심을 기울여서 언어상의 변화에는 소홀했었는데, 여러가지 고무적인 변화가 많은 언어상의 변화쪽에 흥미가 생기기 시작했다. Draft와 Issue 리스트를 살펴봐야할 듯 하다.

A Brief Look at C++0x 더 읽기"

Vim 7의 새로운 기능 사용하기

Vim 7을 설치하더라도 기존 버전과 달라진 점을 쉽게 깨닫기는 힘들다. First look at Vim 7이라는 글을 참고하여 Vim 7의 새로운 기능을 쓰는 방법을 간단하게(?) 정리해보았다.

Spellcheck

:help spell
Spellcheck 기능에 대한 도움말.
:set spell spelllang=en_us
Spellcheck 기능 켜기.
zg
cursor 위치의 단어를 good word로 취급. (zug로 undo)
zw
cursor 위치의 단어를 wrong word로 취급. (zuw로 undo)
z=
cursor 위치의 단어를 대체하는 추천 단어를 리스팅.

Undo branches

특정 시간이나 변경수를 이용하여 undo/redo가 가능해진 기능. 자주 쓸모가 있을 것 같지는 않다.

:help undo-branches
Undo branches 기능에 대한 도움말.
:undolist
undo. 기존의 u와 동일.
g-
undo. 기존의 u와 동일.
g+
redo. 기존의 Ctrl-r과 동일.
earlier 3
3번의 변경 이전으로 undo.
later 3
3번의 변경 이후로 redo.
earlier 3s
3초 이전으로 undo.
later 3h
3시간 이후로 redo.

Tabs

탭기능.

:tabnew
새로운 탭 추가.
gt
다음 탭으로 이동.
:tabdo %s/oldvariable/newvariable/g
모든 탭에 특정 명령(replace) 수행.

Etc.

Ctrl-x Ctrl-o
code completion. html element 같은 경우에는 잘 동작하지만, 프로그래밍 언어에서는 어떻게 동작하는지 잘 모르겠다.
:sort
라인들을 알파벳순으로 정렬.

Vim 7의 새로운 기능 사용하기 더 읽기"

Can't replace files with Subversion

refactoring을 하다보면 AAA라는 클래스를 지우고, BBB라는 클래스를 AAA로 바꾸고 싶을 때가 있다. eclipse의 refactoring 기능을 사용하면 이러한 refactoring은 매우 자연스럽고 쉽게 수행할 수 있다. 하지만, commit할 때가 문제다. 다음은 이를 시도할 때 subclipse (정확히는 subversion) 에서 발생하는 에러다.

delete --force AAA.java
D AAA.java
move BBB.java AAA.java
Entry already exists
svn: 'AAA.java' is scheduled for deletion; it must be committed before it can be overwritten

subclipse의 문제가 아니라 file 이름 기반으로 entry들을 관리하는 subversion 자체의 문제로 보인다. 물론 해결하는 방법이야 존재한다. 가장 간단하게는 deletion과 rename을 따로 commit하는 것이 바로 그것이다. 하지만, 항상 code repository에는 working version 만을 넣겠다는 rule을 깨뜨려야하기도 하다.

Can't replace files with Subversion 더 읽기"

Annoying mod_ruby

현재 하고 있는 일이 간단한 웹 어플리케이션을 만드는 일이라 apache + mod_ruby를 사용하고 있는데, 그냥 단순히 apache + CGI + ruby를 사용하는 것에 비해서도 좋지 못한 선택이 되고만 것 같습니다.

라이브러리 등에 이미 존재하는 클래스를 override할 수 없는 문제라든가 HTTP header와 관련해서 시키는대로 했는데도 불구하고 제대로 동작하지 않아서, Apache Runtime에 접근해서 직접 조작해주어야 하는 짜증스러움이 있군요.

아햏햏한 문제는 또 있습니다. 다른 개발자가 항상 사용할 수 있어야하기 때문에, 테스트 버전과 개발 버전을 하나의 apache 서버에서 돌리고 있습니다만, 하나의 버전에 접근한 후 다른 버전에 접근하면 알 수 없는 에러가 발생합니다.

nohmad 옹에게 문의해보니 대뜸 mongrel + Nitro + Og + amrita2을 쓰시라고 하시는군요. 굳이 Nitro나 amrita는 아니더라도, 일단 mongrel이나 webrick 같은 ruby로 된 web server를 사용해보는 것도 괜찮을 것 같습니다. RoR과 같은 web application development framework를 선택하지 않은 것은 DB를 쓸 정도로 복잡한 어플리케이션이 아니었기 때문이었는데, 차후에 DB를 사용할 필요가 생기면 그 때 정도에 고려해도 무난할 듯 하군요.

Annoying mod_ruby 더 읽기"