티스토리 뷰

donaricano-btn
반응형

분업화가 낳은 생활의 달인

여러가지 일을 다 잘하는 사람은 드물어도 한 가지 일을 기가막히게 잘 하는 사람은 어렵지 않게 찾을 수 있습니다. 누구나 한 가지 일을 오랜시간 반복하다 보면 '생활의 달인'소리를 들을만큼 전문성을 갖출 수 있겠죠(물론 그게 영 안되는 저 같은 사람도 있긴 합니다). 그리고 생산라인을 전문성을 발휘할 수 있는 부문으로 나누어 구성하는 것을 '분업화' 라고 하지요. 분업화는 등장하는 동시에 이전에는 상상할 수 없었던 엄청난 생산성의 향상을 가져 왔습니다.

 

현재는 사회 전반에 걸쳐 이런 분업화가 잘 정착되어 있습니다. 제가 일하는 회사만 해도 서비스에 대한 기획과 개발, 운영이 각각 다른 팀에서 이루어지고 있고 개발팀은 다시 프론트엔드와 백엔드, 디자인 등의 분야로 나뉘어져 있습니다.

 

그런데 이렇게 분업화를 하면 효율이 향상되는 것은 사람이 맡은 업무 뿐만이 아닙니다. 개발자가 작성한 코드 역시 분업을 통해 효율성을 높일 수가 있습니다. 코드를 분업화 한다는 건 결국 코드를 기능별로 분리하는 것을 뜻하겠죠? 이 때, 효율성을 위해 분리된 코드의 조각을 모듈(Module)이라고 부릅니다. 그리고 코드를 모듈로 분리하는 것을 모듈화(modulmodularize)라고 합니다.

 

모듈화가 잘 된 코드는 유지보수를 편하게 만들어줍니다. 실제로 어떤 서비스를 개발하는 비용보다 유지보수에 몇 배의 비용이 더 필요하다는 것은 이제 상식적인 이야기 입니다. 이런 유지보수를 쉽게 만들어준다는 것은 결국 전체 비용의 감소를 의미합니다. 하지만 무엇보다 개발자에게 중요한 것은 모듈화가 잘 된 코드는 개발자의 퇴근 시간을 앞당길 수 있다는 것입니다. 

 

그러나 우리의 자바스크립트(JavaScript)는 애초에 모듈화와는 거리가 먼 언어였습니다. 언어차원에서 모듈을 위한 명시적인 키워드나 패키징 정책을 지원하지 않았기 때문입니다. 물론 ES6가 등장하면서 이야기가 조금 달라지기는 하지만 ES6가 등장하기 전 개발자들에게 자바스크립트의 모듈화는 자바스크립트의 범용적인 사용을 위해서는 반드시 해결해야 하는 선결 과제였습니다.

 

모듈화와는 거리가 먼 태초의 자바스크립트 코드를 한 번 생각해 보겠습니다. 이 코드에서 sum 함수는 인자로 전달받은 배열의 숫자를 모두 다 더해서 리턴하게 됩니다. 그런데 sum 함수 안에서 add 라는 함수를 호출합니다. add 함수는 인자로 전달받은 두 개의 숫자를 더해서 다시 리턴하게 되죠.

 

원래 자바스크립트는 이렇게 <script></script> 태그 사이에 인라인(inline)으로 상빕되게 됩니다. 여전히 많은 서비스에서 이런 식으로 자바스크립트 코드를 사용하고 있을 것입니다. 이렇게 인라인으로 모든 코드를 작업하게 되면 외부 파일이나 의존성 관계에 대해서는 크게 생각할 필요가 없습니다. 그러나 이 코드에는 몇가지 약점이 있습니다.

 

  1.  코드를 재사용 불가
  2.  글로벌 네임스페이스(global namespace)의 오염

일단 코드를 재사용 할 수가 없습니다. 만약 다른 HTML 파일에서 똑같은 자바스크립트 코드를 사용한다고 생각해 봅시다. 이미 작성된 코드가 있음에도 불구하고 필요한 HTML 파일에 이 코드를 그대로 복사해서 붙여 넣는 수 밖에 없습니다. 만약 스펙상 변경사항이 발생되어 코드를 수정해야 하는 경우에는 복사된 코드를 일일이 찾아 다니며 수정하는 수 밖에 없겠죠.

 

또 하나의 문제는 글로벌 네임스페이스가 오염된다는 것입니다. 모든 변수와 함수가 전역 객체에 선언이 되어 있습니다. 이 정도 길이의 한눈에 들어오는 짧은 코드라면 문제 없을지 모르지만 만약 수천라인이 넘어가는 긴 코드라면 어떨까요? 변수, 함수명을 실수하기 딱 좋지 않을까요?

 

이런 문제 때문에 자바스크립트 개발은 웹사이트의 규모가 커질수록 소스를 관리하고 배포하는 비용이 점점 더 커지는 경향이 있습니다. 

 

다행히도 자바스크립트는 자바스크립트 코드와 HTML 페이지를 분리할 수 있는 방법을 제공하고 있습니다. 이전의 코드를 자바스크립트 파일로 저장하고 <script src="..."></script> 태그를 사용해서 불러올 수 있습니다.

 

이렇게 자바스크립트 파일로 불리된 파일에 의해 코드를 재사용 할 수 있게 됩니다. 그러면 더 이상 다른 html 페이지에 코드를 복사 붙여넣기 할 필요가 없이 이 자바스크립트 파일을 포함시키기만 하면 됩니다. 그런데 위 코드는 여전히 몇 가지 문제점을 가지고 있습니다.

 

  1.  의존성 관계 확인 불가
  2.  글로벌 네임스페이스(global namespace)의 오염

위 코드에서 sum.js 에 있는 sum 함수가 동작하기 위해서는 add 함수가 먼저 정의되어 있어야 합니다(이런 것을 의존성 관계가 있다고 표현합니다). 그런데 add 함수는 add.js 파일에 들어있기 때문에 sum 함수를 사용하기 위해서는 무조건 add.js 파일이 먼저 로드되어 있어야 합니다.

 

sum 함수를 사용하기 위해서 sum.js를 로드하고 add.js를 로드하지 않는다면 그 페이지는 에러를 발생시킬 것입니다. 최초의 개발자가 아닌 다른 개발자가 유지보수를 맡아서 새로운 페이지를 만들 때 의존관계를 모두 파악하는 것은 쉬운 일이 아닐 것입니다.

 

그리고 여전히 글로벌 네임스페이스는 오염되어 있습니다. 로드된 파일에서도 모든 함수와 변수들은 전역객체에 선언되어 있습니다.

 

개발자들은 남은 문제를 해결하기 위해 여러가지 모듈 패턴(Module Pattern)들을 고안해 냈습니다.

 

새롭게 바뀐 코드에서는 calc 라는 이름의 객체에 필요한 코드(함수와 변수)를 포함시켜 모듈화 시킨 것을 볼 수 있습니다. 모듈 객체와 즉시실행함수표현식(Immediately Invoked Function Expression)을 사용한 이 모듈 패턴은 오로지 하나의 모듈 객체만 전역 스코프(scope)에 노출시킴으로서 네임스페이스의 오염을 줄이는 것을 확인할 수 있습니다. 이제 객체를 통해 함수에 접근하게 되는데 이것은 JQuery같은 대중적인 라이브러리에서 흔히 사용하는 패턴입니다.

 

그러나 여전히 모듈 객체를 전역에 선언해야만 하고 sum 함수를 사용하기 위해서 같은 페이지에 add 함수를 포함시켜야 한다는 점 등의 문제점은 해결되지 않았습니다.

 

이제 자바스크립트는 할만큼 했습니다. 더이상 자바스크립트의 기본적인 문법만 가지고는 남은 문제들을 해결할 수 없습니다. 그러나 개발자들은 포기하지 않았습니다.

 

자바스크립트를 범용적으로 사용하고자 하는 노력은 이전부터 계속되어 왔으나 가장 의미있는 결과물을 만들어 낸 것은 CommonJS라는 이름의 워킹그룹일 것입니다. 이들은 2009년, 자바스크립트를 서버사이드에서 사용하고자 하는 목적에서 ServerJS를 탄생시키고(금방 이름을 CommonJS로 바꿉니다) 자바스크립트를 데스크톱 애플리케이션이나 서버사이드 애플리케이션에서 사용할 수 있도록 만들고자 합니다.

 

CommonJS는 자발적인 워킹그룹으로 특정한 라이브러리를 제공하는 것은 아닙니다. ECMA나 W3C와 같은 일종의 표준화 조직에 가깝습니다. 이들은 자바스크립트를 조금 더 범용적으로 사용하기 위해 필요한 명세(Specification)를 만듭니다.

 

CommonJS의 창시자인 Kevin Dangoor는 자신의 블로그에서 자바스크립트가 범용적으로 쓰이기위해 몇 가지 문제점이 있다고 주장했습니다. 그 내용은 다음과 같습니다.

 

  1. 모듈 시스템의 부재
  2. 표준 라이브러리의 부재
  3. 표준 인터페이스의 부재
  4. 패키지관리 시스템의 부재

살펴 보면 사실상 네가지 문제 모두 모듈화와 연관이 깊다는 것을 알 수 있습니다. 때문에 CommonJS는 모듈 API를 정의하고 있습니다. 애초에 html 페이지가 존재하지 않는 서버사이드에서 자바스크립트를 사용하기 위해서는 명백히 모듈 API가 필요합니다.

 

모듈을 정의할 때 필요한 것은 크게 세 가지 입니다. 모듈은 독립적인 실행 영역(scope)가 있어야 합니다. 따라서 전역변수와 지역변수를 분리하는 것이 매우 중요합니다. 그리고 모듈을 외부에서 사용할 수 있게 공개해야 합니다. CommonJS에서는 exports라는 전역 객체를 이용합니다. 반대로 모듈을 이용하는 영역이 있어야 할 것입니다. 이 때 자바에서 import 키워드의 역할을 하는 것이 바로 require 함수 입니다.

 

위 코드는 node.js와 형태가 비슷한데 그 이유는 node.js가 CommonJS 스타일의 모듈을 구현했기 때문입니다.

 

그러나 서버사이드에서는 자바스크립트파일마다 독립적인 파일스코프를 만들기 때문에 파일 하나에 하나의 모듈을 작성하면 전역과 자연스럽게 분리가 되지만 브라우저에서 동작할 때는 파일마다 단일한 스코프가 존재하지 않기 때문에 단순히 <script> 태그를 통해 자바스크립트 파일을 로드하면 여전히 전역변수가 오염되는 문제가 발생합니다.

 

또 브라우저에서 네트워크를 통해 필요한 모듈을 모두 내려받기 전까지는 브라우저가 아무 일도 하지 않는다는 문제점이 있습니다. 다시 말해 위 코드에서 var add = require('add');를 호출했을 때 시스템이 모듈이 다 호출될 때 까지 멈춰 있다는 것입니다.

 

CommonJS는 이런 문제를 해결하기 위해 추가로 다른 정의를 내 놓습니다. 그러나 그룹 내에 의견이 다른 사람들이 조재했고 논쟁끝에 합의점에 이르지 못하고 독립한 그룹이 존재합니다. 이 그룹의 이름이 바로 AMD(Asynchronous Module Definition)입니다. CommonJS가 자바스크립트를 브라우저 밖에서 쓸 수 있도록 하기위해 노력했다면 AMD는 보다 브라우저에 중점을 두고 있습니다.

 

CommonJS와 AMD 모듈 명세에서 가장 큰 차이는 모듈 로드에 있습니다. CommonJS는 로컬 디스크에서 모듈을 로드할 때 더 빠르고 간결한 코드를 사용할 수 있습니다. 반면 AMD는 Asynchronous Module Definition라는 이름에서 알 수 있듯이 비동기 모듈에 대한 표준안을 다루고 있고 브라우저에서 네트워크를 통해 모듈을 내려 받는데 더 간결하고 빠른 코드를 제공하게 됩니다.

 

<script> 태그를 통해 코드를 로드하는 시간동안 브라우저는 실행을 멈추고 페이지 렌더링을 하지 않게 됩니다. 브라우저 입장에서는 안정성을 위한 선택이지만 느린 속도는 사용자의 사용경험을 나쁘게 만들 수 밖에 없습니다. 이를 보안하기 위해 <script> 태그를 <body> 태그의 가장 아래에 넣는 최적화 기법이 존재하지만 사용자의 첫 인터랙션이 가능할 때 까지 걸리는 시간을 줄일 수는 없습니다.

 

특히 현대의 웹 애플리케이션은 복잡한 화면과 AJAX로 떡칠된 경우가 많기 때문에 첫 페이지 렌덜이과, 인터랙션에 필요한 부분만 먼저 로드하고 이후 사용자의 반응에 따라 점진적으로 로드하는 방법이 필요하게 됩니다. 이렇게 페이지의 렌더링을 방해하지 않으면서 필요한 파일만 로드하는 방법을 동적로딩(Dynamic Liading, Lazy Loading)이라고 합니다.

 

동적로딩의 대표적인 방법은 이처럼 script 태그를 동적으로 삽입하도록 하는 것입니다. AMD는 이렇게 <script> 태그를 동적으로 삽입해 로드하는 방식을 사용합니다.

 

AMD에서는 전역함수인 define 함수를 사용하여 스코프를 분리하게 됩니다. 즉, 이 define 함수가 일종의 네임스페이스 역할을 하게 되는 것입니다. 이 define 함수는 의존선을 나타내는 모듈 배열을 인자로 가지고 로드된 모듈을 콜백함수에 전달하게 됩니다. 이 함수의 return 값이 exports 속성이 됩니다. 이제 모듈 객체마저 사라지고 글로벌 네임스페이스가 완전히 깨끗해 진 것을 알 수 있습니다.

 

이렇게 정의된 모듈을 가져와서 사용하는 것은 require 함수입니다. 위 코드를 보면 require 함수는 sum.js 만 로드하는 것을 볼 수 있습니다. require 함수는 종속성(의존관계)를 먼저 판단해서 종속성이 있는 것을 먼저 로드하기 때문에 add.js 를 페이지에 먼저 로드할 필요가 없습니다. 덕분에 일일이 의존성을 확인해야 할 필요가 사라졌습니다.

 

이렇게 기존에 자바스크립트 코드가 가지고 있었던 의존성 확인 문제나 글로벌 네임스페이스의 오염 문제를 갈끔하게 정리할 수 있게 되었습니다. 

 

물론 그렇다고 해서 문제가 완전히 제거된 것은 아니고 이후의 자바스크립트 모듈화 방향에 대해서는 다음 포스트(기약은 없습니다만...)에서 다뤄 보도록 하겠습니다.

반응형

'language > javascript' 카테고리의 다른 글

XMLHttpRequest API  (0) 2019.03.29
문서 객체 모델(Document Object Model)  (0) 2019.03.29
자바스크립트 웹 프로그래밍  (0) 2019.03.29
자바스크립트 모듈  (0) 2019.03.29
자바스크립트의 객체지향프로그래밍  (0) 2019.03.29
donaricano-btn
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함