Blog

첫째 날에는 하루가 거의 끝날 무렵에야 간신히 좋은 세션을 들을 수 있었는데(Advanced JSON), 둘째 날엔 운 좋게도 오전부터 한 건 건졌습니다. 자바스크립트 계의 요다라고 불리는 Douglas Crockford의 "Javascript - The Good Parts" 입니다.

사용자 삽입 이미지사용자 삽입 이미지
(자바스크립트 계의 요다, Douglas Crockford)

이번 세션의 주제를 요약하자면:

자바스크립트는 장점도 많고 단점도 많은 언어이다. 단점을 피하고 장점을 슬기롭게 잘 살려서 쓰면 자바스크립트 안에 숨어있는 새로운 언어를 발견할 수 있다.

정도가 될 것 같습니다.

그가 첫번째로 지적한 자바스크립트의 단점은 for in 루프입니다. for in 루프는 자바스크립트 객체의 모든 속성들을 하나씩 열거하며 반복할 때 쓰이는 구문인데, 문제는 "모든 속성"이라고 했을 때 여기에 prototype 체인을 통해 상속된 속성도 포함되는지 여부 등 여러가지 혼란스러운 점이 있다는 사실입니다. 그는 다음과 같은 컨벤션을 제안하고 있습니다:

    for(var name in obj) if(obj.hasOwnProperty(name)) {
       ...
    }

즉, for-in 구문 안에는 반드시 filtering 조건을 명시하는 단 하나의 if 블럭이 오도록 하는 것이죠. 수월하게 읽히기도 하고 그렇게 너저분하지도 않은 괜찮은 방법 같습니다.

또 한가지 재미있는 지적은(자바스크립트를 어느 정도 써왔던 분들은 다들 이 문제 때문에 고생 좀 했을텐데요) 자바스크립트의 세미콜론 자동 삽입에 관련된 문제입니다. 그는 이 문제를 보여주기 위해 다음 예제를 제시했습니다:

    // 1
    return {
       ok: true
    };

    // 2
    return
    {
       ok: false
    };

1번 예제는 아무 문제 없이 잘 실행되는 코드입니다. 2번 예제도 그럴 것 같지만, 사실은 문제가 있습니다. 보통의 C 계열 언어들은 세미콜론(;)으로 문장의 끝을 구분하지만 자바스크립트는 몇몇 경우에 세미콜론이 없더라도 이를 자동으로 보정 해주는 특징(스팩에 의하면 "to accommodate non-professional programmers, some aspects of the language may be somewhat less strict"라고 합니다)이 있기 때문에 2번 예제는 1번 예제와 다른 방식으로 해석됩니다. 우선 return 문과 "{" 사이에 세미콜론이 자동으로 삽입되어 다음과 같이 변형되는 과정을 거치게 됩니다:

    return;
    {
       ok: false
    };

함수는 "return;" 부분에서 끝나고 그 뒤에 나오는 문장은 무시되는 것이죠. 하지만 에러는 나지 않습니다. 첫 번째 이유는 도달할 수 없는 문장(unreachable statment)은 자바스크립트에서 아무런 에러도 발생시키지 않기 때문이고, 두 번째 이유는 { ... } 부분이 그 자체로 "올바른" 자바스크립트 구문이기 때문입니다:

    {
        ok: false
    };

에서 "{"과 "}"은 블럭(block)으로 취급됩니다. 자바스크립트에서는 블럭이 자동변수를 위한 범위(scope)을 새로 만들지 않기 때문에 아무 의미가 없습니다. 블럭 뒤에 오는 세미콜론(")은 빈 문장(empty statment)으로 해석됩니다.  가운데 "ok: false"에서 "ok:" 부분은 레이블(label)로 해석되고( --; ), false 는 expression이자 statement이기도 하기 때문에 문제 없이 넘어갑니다. 물론 "false" 뒤에는 자동으로 세미콜론이 삽입되겠죠. 최종적으로, 다음과 같은 모양이 됩니다:

    return;

    // unreachable
   { // block-start
       ok: // label
            false; // expression statement
   } // block-end
    ; // empty statement

직접 당해보면 황당하고 억울하지만, 이렇게 분석해보면 재미있습니다. 요지는, 다른 C 계열 언어에서는 "개발자의 주관적인 스타일"로 볼 수 있는 것들이 자바스크립트에서는 그렇지 않은 경우가 있으므로 이를 일관된 방식으로 통일해서 표현하자는 것이죠. 비슷한 예로 파이선(python)에서는 들여쓰기(indentation)가 "주관적인 스타일" 문제 이상이죠.

그 밖에도, C 계열 언어로부터 받은 안 좋은 유산들(그는 자바스크립트를 "C의 옷을 입은 LISP"이라고 표현합니다)을 지적하고 있는데 간단히 언급하자면:
  • 표현식(expression)이면서 동시에 문장(statement)이기도 한 문법( foo; ),
  • 정확하지 않은 부동소수점 연산(0.1 + 0.2 != 0.3),
  • 단항 증감연산자(++, --),
  • break 문 없이 쓰면 fallback이 되는 switch 문
등입니다.

그렇다면 자바스크립트의 좋은 점에 대해서는 뭐라고 했을까요? 크게, Lambda, Dynamic Objects, Loose Typing을 이야기 했습니다. 이 중 Loose Typing은 생략하고, Lambda와 Dynamic Objects에 대해 이야기해보려고 합니다.

Lambda는 Alonzo Church(네, Church-Turing thesis의 바로 그 Church 입니다)의 "Lambda Calculus"에서 따온 말로 LISP과 같은 함수형 프로그래밍 언어의 핵심이라고 할 수 있는 강력한 개념입니다. 자바스크립트에서는 함수 자체가 일반 상수처럼 변수에 대입될 수도 있고, 다른 함수의 인자로 전달되거나, 함수의 결과로써 반환될 수도 있을 뿐 아니라(이를두고 "함수가 first class object이다"라고 표현합니다), 익명 함수(이름 없는 함수)를 만들 수도 있는데, 바로 이러한 특성이 자바스크립트의 가장 훌륭한 장점 중 하나라고 말하고 있습니다.

저도 이점에 대해 적극 동의합니다. 하지만 문제라면 익명 함수를 만드는 문법이 너무 너저분(verbose)하다는 점인데, 예를 들어 Groovy 같은 언어에서 다음과 같이 표현될 수 있는 문장이:

    [1,2,3].collect({it * it})

자바스크립트에서는 다음과 같이 표현되어야 합니다:

    [1,2,3].collect(function(it) {return it * it})

함수가 first-class object가 아닌 자바 같은 언어에서는 이와 동일한 것을 구현하기 위해 인터페이스 및 해당 인터페이스를 구현하는 익명 클래스를 만들어주어야 하기 때문에 더욱 너저분해지죠.

용기를 내서 이 문제에 대해 어떻게 생각하느냐는 질문을 했었는데, Douglas Crockford는 별로 중요하게 생각하지 않는 모양입니다. 답변은 간단했는데 "익명 함수를 만드는 문법이 일반적인 함수 선언 문법과 유사하여 개념적 혼동을 일으킬 소지가 있긴 한데, 그것만 잘 구분할줄 안다면 표현이 조금 길다는 것은 문제라고 생각하지 않는다" 라고 했습니다.

하지만 자바스크립트의 lambda 표현이 너무 너저분하다고 느끼는 사람은 저 뿐은 아니어서, 한 개발자는 String Lambda(이름을 보면 감이 오시죠?)라는 개념을 고안하여 이를 이용한 일종의 라이브러리(Functional Javascript)를 공개하기도 했습니다(간단하지만 훌륭한 아이디어라고 생각합니다. 이 라이브러리는 단순히 익명 함수 선언의 길이를 줄여주는 것 이상의 많은 일들을 해줍니다. 조만간 꼭 활용해볼 생각입니다).

두번째로, Dynamic Objects는 이미 만들어진 객체에 동적으로 속성을 추가하거나 제거할 수 있는 특정을 말합니다. 정적인 언어를 주로 쓰는 사람들은 자바스크립트의 이 같은 특성을 "허술한 것으로" 여기는 경우가 많은데, Douglas Crockford는 "동적인 객체" 개념이 자바스크립트의 훌륭한 점 중 하나라고 얘기합니다.

혹자는 "class" 키워드가 없기 때문에 자바스크립트는 객체지향언어가 아니라고 말하기도 하지만 이는 큰 오해입니다. 객체지향언어를 객체지향언어로 만드는 것은 키워드가 아니라 특정한 스타일 - 다형성(polymorphism) 등을 기반으로 한 의존성의 역전(dependency inversion) - 이니까요. 자바스크립트에서는 프로토타입 체인(prototype chaining)과 동적 객체 개념을 통해 이를 지원하고 있습니다. 이를 클래스 기반 객체지향 프로그래밍(class based OOP)에 대비되는 말인 프로토타입 기반 객체지향 프로그래밍(prototype based OOP)이라고 표현합니다.

그는 단순히 장/단점을 나열하는 것에서 그치지 않고, 자바스크립트를 향상시키기 위한 현실적은 방안들을 제시합니다(그가 요다라고 불리는 것은 아마 이런 면 때문이 아닐까 싶습니다. 현실적이고 현명한 조언을 해주니까요).

예를 들면, 그가 직접 개발한 JSLint라는 소스코드 분석기가 있는데, 이 프로그램은 자바스크립트 코드의 안 좋은 부분들(위에서 설명한 것과 같은)을 검사하여 좋은 스타일에 대한 가이드를 제공해줍니다. 자바스크립트의 좋지 못한 일부 문법을 제약하는 것이죠(제약이란 어떤 의미에서는 좋은 것입니다 ^^ ). JSLint가 제안하는 가이드는 이 문서들(Part 1, Part 2)과 밀접한 관련이 있습니다.

또는 문법을 변화시키지 않는 소소한 수정을 통한 개선에 대해서도 이야기하고 있습니다. 여기서 중요한 것은 "문법을 변화시키지 않는" 부분인데요, 그가 얘기하는 자바스크립트의 아주아주 훌륭한 점은 바로, 1999년 이후로 새로운 변화 없이(99년은 ECMAScript 3rd edition이 발표된 연도입니다) 현재까지 무려 8년 동안 유지될 수 있었다는 점입니다:
사용자 삽입 이미지
(약간 냉소적으로, 1999년 이후로 새로운 설계 오류가 없었다고 표현하고 있습니다)

이 덕에 Ajax라는 기술도 가능해진 것이라고 말하고 있는데, 적극 공감합니다. 각종 표준안이 실제로 널리 퍼지는데에 걸리는 시간이 극히 오래 걸린다는 사실을 감안하면 웹 개발자들은 자바스크립트가 지난 8년 간 바뀌지 않고 유지됐다는 점에 감사해야 합니다. 그가 제안하는 문법을 변화시키지 않는 개선에는 다음과 같은 것들이 있습니다:
  • Object, String, Array 등에 toJSONString과 parseJSON 추가하기
  • object.dontEnum(name) 추가하기(for-in을 개선하기 위해)
  • 안전한 eval 메서드
앞의 두 가지는 딱 들으면 알겠는데, 안전한 eval 메서드에 대해서는 잘 감도 안오고, 특별히 길게 설명을 해주지도 않아서 인터넷을 좀 뒤져봤습니다.

    result = "a + b * c".eval({a: 1, b: 2, c: 3}); // result is 7

eval의 문제는 동적으로 평가되는 코드가 전체 프로그램의 모든 부분에 대해 접근할 수 있다는 점인데, 위와 같이 제공된 컨텍스트( {a: 1, b: 2, c: 3} 부분)로만 접근을 제한할 수 있게 하자는 아이디어였습니다.

이 밖에도 더 많은 이야기들이 있었지만, 이 정도에서 마무리하도록 하겠습니다. Douglas Crockford는 다음날 JSON BoF에서도 만날 수 있었는데요, 여기에서도 재미있는 얘기들을 많이 들을 수 있었습니다.

--강규영

Trackback

트랙백 주소 :: http://blog.openmaru.com/trackback/171

Comment