[html5-lint] console에서 html page validate하기

WebPage를 스펙에 맞게 작성하였는지 https://html5.validator.nu/ 를 이용하여 쉽게 확인할 수 있다. 하지만 이런 방식은 웹 페이지에서 확인하는 방식이기 때문에 autotest를 만들기 어려워진다. 모질라에서도 같은 고민을 하였는지 auto test를 위해 python과 node.js에서 사용할 수 있는 html5-lint 라는 것을 만들어서 사용하고 있다. html5-lint는 validator를 다시 구현하는 방식이 아니라 https://html5.validator.nu/ 로 post request를 날려 결과를 가져오는 방식으로 동작한다. 하지만 이렇게 하면 테스트할 때마다 https://html5.validator.nu/ 에 request를 요청하게 되므로 모질라에서는 클론 페이지 를 만들어서 사용하고 있었지만, 지금은 클론 페이지가 죽어서 다시 원래의 validator.nu/ 를 이용하여 테스트하여야 한다.

[CoffeeScript] undefined를 void 0로 compile하는 이유는 무엇일까

요새 재미삼아 만들고 있는 웹 프로그램이 있다. JavaScript를 약간 하드하게 사용하여야 하므로, pure한 JavaScript를 사용하지 않고, CoffeeScript를 이용하여 개발을 진행하고 있다. CoffeeScript 자체를 실행시키는 interpreter가 존재하지 않고, 언제나 JavaScript로 compile한 뒤 실행되어야 해서, 빠르게 코드 수정 내용을 테스트할 수 있다는 장점이 사라진다. 변환되는 과정에서 어떤 경우는 JavaScript로 직접 작성한 코드보다 비효율적인 코드가 나오기도 한다. 게다가 CoffeeScript는 기본적으로 모든 JavaScript 코드는 CoffeeScript 코드로, CoffeeScript 코드는 JavaScript 코드로 1:1로 변환 가능하게 해주는 것을 목표로 삼고 있기 때문에, JavaScript보다 더 powerful한 것도 아니다. 그럼에도 새 프로젝트에 JavaScript를 사용하지 않고 CoffeeScript를 사용하는 것은 다음의 두 가지 이유 때문이다. 우선 내가 c-style의 코드보다 ruby-style의 코드를 더 좋아한다. 별거 아니지만 오랜 시간 아무런 이득도 없이(쉽게 말해서 돈 받는 게 아니면서) 혼자서 쓸쓸히 작업하려면 내가 좋아하는 방식으로 작업하는 게 최고다. 다음으로 compile과정을 거치기 때문에 실수를 한번 걸러줄 수 있다. compile 과정에서 엄격한 정적 분석을 거치는 것은 아니지만, 기본적인 실수를 막아주는 역할 정도는 할 수 있다. CoffeeScript가 undefined 를 void 0 로 compile하는 이유도 여기에 있다. 위와 같이 undefined 를 사용하는 CoffeeScript 코드를 컴파일하면, 아래와 같이 undefined 를 void 0 로 변환한 JavaScript 코드를 돌려준다. void 함수는 분명히 언제나 undefined 를 return 하기는 하지만 굳이 멀쩡한 undefined 를 놔두고 v

RAII는 무엇인가

RAII 는 C++에서 자주 쓰이는 idiom으로 자원의 안전한 사용을 위해 객체가 쓰이는 스코프를 벗어나면 자원을 해제해주는 기법이다. C++에서 heap에 할당된 자원은 명시적으로 해제하지 않으면 해제되지 않지만, stack에 할당된 자원은 자신의 scope가 끝나면 메모리가 해제되며 destructor가 불린다는 원리를 이용한 것이다. 원래는 exception 등으로 control flow가 예상치 못하게 변경될 때를 대비하기 위해서 쓰이던 기법이다. 아래의 예제를 보자. 첫 번째 코드는 위험하다. thisFunctionCanThrowException() 함수에서 exception을 발생시킨다면 resource를 해제하지 못한다. 두 번째 코드는 일단은 resource 를 해제하고 있다. 하지만 보기에 좋은 코드는 아니다. 그리고 유지하기도 어려워진다. 세 번째 코드는 RAII를 위해 c++ 11의 스마트 포인터인 unique_ptr 을 이용하는 방법이다. unique_ptr 은 소멸할 때 자신이 들고 있는 메모리를 해제시켜주기 때문에 함수 밖으로 나가면 resource 가 해제되는 것이 보장된다. 여기서 말하는 자원은 단순히 heap 메모리만을 말하는 것이 아니다. heap 메모리 이외에도 파일이나 database connection과 같은 것들도 전부 RAII를 이용해 안전하게 사용할 수 있다. 여기에 더 나아가서 특정 scope를 벗어나면 반드시 실행돼야 하는 코드들도 RAII를 이용해 처리할 수 있다. 즉, 다른 언어에서 finally 에 해당하는 구문을 RAII를 이용해서 처리할 수 있다. 실제로 C++의 아버지이자 RAII라는 용어를 처음 만든 Bjarne Stroustrub는 c++에 finally 를 집어넣지 않는 이유를 "RAII가 있는데 굳이 있을 필요가 없다." 라고 말하고 있다.

잘못된 assert는 사용하지 말자

assert라는 함수는 인자로 받는 조건이 true가 아니면 예외를 발생시키는 함수로, 디버깅을 도와주거나, 코드의 가독성을 올리는 용도로 쓰인다. 게다가 릴리즈에서는 아무 일도 않기 때문에(c++의 경우 NDEBUG가 정의되었는가 아닌가로 동작이 달라진다.), 성능 저하 없이 검증 코드를 집어넣을 수 있다. 근데 릴리즈에서는 아무 동작도 하지 않는다는 특성 때문인지, assert가 가지는 implicit 한 의미를 이해 못 했는지 assert를 잘못 사용하는 때도 있다. 다음의 코드를 보고 이상한 점을 찾아보자. Connection이라는 class의 Send method에서 message를 받아서 platformConnection_(내부 구현이 어떻게 되었을지는 신경 쓰지 말자.)을 통해서 Send해주고 결과 값을 돌려준다. 그 전에 platformConnection_이 valid한지를 검사하여 valid하지 않다면 false를 돌려주는 평범한 코드다. 문제는 함수의 맨 앞에서 valid한지 아닌지 assert로 체크를 하고 있다는 것이다. 이 assert문이 가지는 의미는 절대로 valid하지 않을 때는 절대로 이 함수가 호출되지 않는다는 것이다. 그럼에도 그다음 문장에서 valid한지 않은지 검사하고 있다. 이에 대해 assert는 릴리즈 빌드에는 포함되지 않기 때문에 릴리즈 빌드를 위해서 안전한 코드를 작성해야 한다고 주장하는 사람도 있다. 하지만 이런 경우라면 애초에 assert를 쓰지 않고 조건문만을 써야 한다. assert를 썼다면 assert에 걸릴만한 조건이 들어오지 않도록 코드를 작성했어야 한다.

테스트 얼마나 만들어야 할까?

에자일한 소프트웨어를 만드는 방법의 하나로 TDD 에서는 test를 먼저 작성하는 것을 권장? 혹은 강요한다. 스펙에 맞춰 테스트를 하나하나 만들어가고, 그 테스트 케이스들을 초록색으로 만드는 것을 반복해 나가다 보면 에러 없는 코드가 완성된다는 것이다. 이 방법론에 대해 비난할 생각은 없다. 매우 좋은 방법이다. 근데 정말로 언제나 해야 하는 걸까? 부작용은 없을까? 내가 이것들에 대해 고민하게 된 것은 TDD를 처음 배우고 Rails를 사용하고 있던 3년 전 일이다. 그전에 했던 프로젝트가 C++로 서버를 만드는 일이었고 사소한 예외처리 몇 개를 실수해서 몇 일 밤을 새웠던 직후라서 더욱더 테스트에 매달리게 되었다. 다행히도 rails는 유닛테스트에 특화된 framework이었고 (당시에 DB까지 unit test가 가능하도록 지원해주는 framework이 얼마 없었다.), TDD의 원칙에 따라서 많은 테스트와 함께 코드를 작성해 나갔다. 그렇게 가끔 테스트가 없었으면 크게 삽질했을 버그를 잡아가면서, 그 프로젝는 내가 질릴 때까지 별문제 없이 진행되었다. 여기까지만 보면 TDD의 긍정적인 사례에 추가될 수 있을 것 같지만, 실상은 전혀 아니었다. 문제는 두 가지가 있었다. 첫 번째는 테스트 작성에 심취해서 개발에 너무 많은 시간이 들었다는 것이고, 두 번째는 너무 빨리 질렸다는 것이다. 당시에는 아직 TDD에 적응이 안 돼서라고 생각했는데, 정도의 차이가 있었지만 2번째 프로젝트에서도 비슷한 현상이 나타났다. 왜 그렇게 된 것일까? 이것에 대해 고민하다가 RubyOnRails의 제작자인 David Heinemeier Hansson의 글 을 보게 되었다. 논쟁이 많이 되었던 글이지만 David가 말하고자 하는 바는 단순하다. 테스트를 작성하는데 들어가는 비용도 기능 구현이나 디버깅에 들어가는 것과 같은 비용이니 overtest하지 않도록 노력해야 한다는 것이다. Unittest라는 도구를 처음 접해 아무 생각 없이 심취해버렸던 나는, test를

GateOne - HTML5 ssh client.

Surface RT를 8.1로 올린 뒤로 jailbreak가 안되는 바람에 Web기반 ssh client를 이것저것 찾아봤다. 위키 를 찾아보니 다양한 프로젝트들이 있어 이것저것 살펴봤는데 GateOne 이 가장 마음에 들었다. 일단 생각나는 장점은 아래와 같다. 오픈소스이다. github으로 소스 관리를 한다. 서버사이드가 파이썬으로 짜여있다. 클라이언트 UI가 섹시(?)하다. 플러그인 없이 HTML5로만 구현되었다. SSL을 쓸 수 있다. 서버를 실행시킬때 루트권한이 필요 없다. 정도가 될것 같다. 특히 과거 오픈소스 프로젝트로 서버 프로그램을 테스트하다가 해킹당했던 기억때문에 서버를 실행시킬때 루트권한이 필요 없다. 가 매력적이었다. virtualenv를 이용하여 설치하고, 실행옵션으로 넣을 수 있는 몇가 옵션만 변경시켜주면 쉽게 실행시켜줄 수 있다. 아쉬운점이 있다면 한글 입력이 불편하다는 건데, 다른 대부분의 클라이언트들은 한글 폰트가 깨져나오는 것을 보면 큰 단점은 아니라고 생각한다. 예전부터 만들고 싶었던 부류의 물건이기도 하고, 깔끔하게 구성되어 있어서 한동안 내 장난감은 이게 될것 같다.

레인지로버 무선 마우스

개발용 블로그와 그 외의 일상생활들에 대해 적는 블로그를 나누기 시작했다. 본래 있던 글은 https://www.seulgik.im/2013/09/blog-post.html 로 이동되었다.

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

RAII는 무엇인가

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

[Python] cache 데코레이터로 최적화하기

[Web] SpeechSynthesis - TTS API