[자바스크립트] 모듈
http://blog.davidpadbury.com/2011/08/21/javascript-modules/
자바스크립트에는 자바의 import나 C#의 using이라는 개념이 없다. 그래서 자바스크립트를 사용하는 개발자가 직접 그런 개념을 구현하고자 노력 중이다.
모듈 패턴
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth 이 글에 있는 최종적인 소스 코드가 다음과 비슷하다.
[gist id=1676434]
이 코드에는 다음과 같은 개념이 녹아있다.
Isolation
자바스크립트의 함수 스코프를 이용해서 글로벌 스코프 변수를 사용해서 발생할 수 있는 난감한 상황을 피할 수 있다. 함수 내부에 있는 모든것은 시스템의 영향을 받지 않는다.
namespacing
위 코드의 마지막 줄처럼 이미 window에 lab49라는 네임스페이스가 있는지 없는지 여부에 따라서 이미 있다면 기존의 것을 사용하고 없다면 비어있는 객체 리터널을 넣어서 새로 만들도록 할 수 있다. 위와 같은 함수 랩퍼를 여러 자바스크립트 파일이 사용한다고 가정했을 때 유용한 방법이다.
Private State
함수 안에 있는 모든건 외부에서 접근할 수 없기 때문에 코드를 격리시키기 좋긴하지만, 함수 밖에서 그 안에 있는 걸 아무것도 접근할 수 없다면, 별 쓸모없는 함수가 되고 만다. 그래서 lab49처럼 window 객체에 네임스페이스 역할을 할 객체를 붙이고, 거기에 외부로 공개할 것을 붙이는 형태로 코딩할 수 있다. 마치 add 함수처럼. 저렇게 코딩해두면 밖에서는 lab49.add(2, 2)처럼 호출할 수 있다.
CommonJS 모듈
CommonJS는 주로 서버 사이드 자바스크립트 런타임을 만든 사람들로 구성된 그룹으로 모듈 공개와 접근에 대한 표준화를 시도했다.
[gist id=1676504]
exports에 공개할 모듈을 추가하고, 모듈을 사용하는 쪽에서는 require를 사용해서 필요한 모듈을 가져다 사용한다.
CommonJS는 서버 사이드 자바스크립트 런타임을 주요 타겟으로 설계되었기 때문에 다음과 같은 이유로 클라이언트 사이드에 적용하기는 어려움이 있다.
- requrie는 반드시 즉시 리턴해야 한다: 스크립트를 비동기적으로 다운로드하는 스크립트 로더를 사용하기 어렵게 한다.
- 파일당 모듈: CommonJS 모듈을 만들려면 함수 하나로 감싸야하며 특정한 방법으로 구성해야 하는데, 그러려면 Stitch나 Browseify같은 노드 모듈을 사용해서 여러 모듈 자바스크립 파일을 하나의 자바스크립 파일로 묶어주는 컴포넌트를 사용하지 않고는 힘들어진다.
AMD(Asynchronous Module Definition)
AMD는 브라우저용 모듈 포맷으로 설계됐다. CommonJS 그룹에서 먼저 제안했지만, Github으로 자리를 옮기고 나서 테스트 스위트로 관리되고 있다.
AMD의 핵심 함수는 define 함수다. 이 함수를 세 개의 매개변수를 가지고 호출하는 코드가 가장 자주 사용하는 방법인데, 첫번째 매개변수로 모듈 이름을 넘기고, 두번째는 이 모듈이 의존하고 있는 모듈 식별자 배열을 넘기고, 마지막으로 모듈 정의를 반환할 팩토리 함수를 넘긴다.
[gist id=1676562]
모듈 정의가 define으로 감싸지기 떄문에 얼마든지 한 파일 안에 여러 모듈을 정의할 수 있다. 그리고 모듈 로더가 define 모듈 팩토리 함수를 호출할 때 그 의존성을 파악하여 필요로 하는 모듈을 먼저 비동기적으로 다운로드 할 수 있게 해준다.
자바스크립트가 구리다는 말이냐?
이런 개념 부재가 다른 언어를 사용해온 개발자에게 불편을 주긴하지만, 이런 개념 부재로 인해 자바스크립트 개발자 스스로가 원하는 패턴으로 모듈 구조를 만들어가고 있다.
10년 전에 이런 종류의 기능이 만들어졌다면 어땟을지 상상해보라. 지금처럼 서버 사이드에서 동작하는 자바스크립트 애플리케이션이나, 브라우저에서 비동기적으로 리소스를 로딩하는 기술도 없고 RequireJS 같은 로더처럼 텍스트 템플릿으로 리소스를 추가하는 것과 어울리는 기술은 아니었을 것이다.