3. 모듈
1. NPM은 무엇인가?
NPM(Node Pakage Manager)입니다. 즉 Node에서 사용할 수 있는 아주 기초가 되는 부품이라고 할 수 있습니다. 우리의 선배님들이 후배들을 위해 구현에 복잡할 수도 있는 기능들을 미리 모듈화 해서 저장해 놓을 수도 있을 것입니다. 이것을 우리는 NPM이라는 마치 앱스토어 같은 플랫폼을 활용해서 손쉽게 사용 할 수 있는 것이지요. 주요한 기능으로는
- 모듈의 설치
- 모듈의 삭제
- 모듈의 업데이트
- 모듈의 의존성 관리
입니다. 여기서 모듈의 의존성 관리는 만약 우리의 프로젝트가 NPM을 통해 몇가지의 모듈을 사용한다면 어떠한 모듈을 사용하는지에 대한 JSON 형태의 문서를 NPM이 쉽게 관리 해주게 되는 것이죠. NPM을 통해 우리가 설치할 수 있는 것은 크게 2가지 종류가 있습니다.
- 독립적으로 동작하는 앱 (예를 들어, npm install uglify-js-g)
- 모듈 (예를 들어, npm install uglify-js)
두 가지 모두를 포괄하는 개념은 Package입니다.
2. NPM 독립적으로 동작하는 앱
- 먼저 uglify-js를 독립적인 앱으로 한번 설치해 봅시다.
- 터미널을 열고 'npm install uglify-js-g'를 입력하고 설치합니다.
- 앞서 살펴 봤던 것처럼 -g의 유무는 -g가 있는 경우에는 독립적인 앱으로 설치해서 특정 폴더 밖에서도 설치한 앱에 접근하여 실행할 수 있게 됩니다.
여러분이 설치한 IDE에 pretty.js라는 파일을 하나 만든위 아래와 같은 코드를 입력하고 저장합니다.
function hello(name){ console.log('hi' + name); } hello('TS');
터미널에서 여러분이 파일을 저장한 폴더로 이동합니다.
- 이동 후 uglifyjs pretty.js를 입력하면 띄워쓰기와 줄바꿈이 사라진 한 줄짜리 결과를 얻게 될 것입니다.
- 관습적으로 최소화한 파일의 이름은 'uglifyjs pretty.js -o pretty.min.js -m'와 같은 코드로 이름을 저장하게 됩니다.
3. NPM을 이용해서 나의 앱의 모듈로 사용하기
- underscore를 설치해 봅시다.
- 다른 사람이 만든 모듈(상대방의 패키지)을 사용할 때에는 자신의 프로젝트도 하나의 패키지임으로 패키지화할 필요가 있습니다. 이는 npm init을 이용해 달성 할 수 있습니다.
- 기본적인 정보들을 입력하게 되면 그동안은 존재 하지 않았던, package.json이라는 파일을 확인할 수 있습니다. 해당 파일을 클릭하면 우리가 터미널에서 입력했던 값들이 JSON 형태로 변환되어 저장된 것을 확인 할 수 있습니다.
- 지금부터는 터미널을 열고 underscore를 설치해 보도록 합시다.
- 'npm install underscore --save'를 입력하면 설치가 자동으로 실행됩니다. 여기서 '--save'를 입력하는 이유는 json에 명시적으로 저장하는 것입니다. 이는 협업과 긴밀한 관계를 가지고 있습니다. 만약 2명의 사람이 github를 이용해 프로젝트를 수행하는 중에 A라는 컴퓨터에는 underscore라는 모듈을 사용하고 있지만 B라는 컴퓨터에는 사용하고 있지 않아 다른 환경에서 프로젝트를 진행하게 되면, 자칫 잘못하면 재앙을 가져올 수도 있습니다. 동일한 작업 환경을 구성하기 위해 우리는 package.json파일을 dependencies를 참고하면 쉽게 동일한 개발 환경을 구성할 수 있겠지요.
- 그리고 다시 package.json을 열어보면 defendencies라는 항목이 생긴것을 확인 할 수 있습니다. 이것을 통해 모듈성 관리를 쉽게 하도록 도와주는 역할을 수행하게 됩니다.
- 만약 --save를 해서 문제가 발생하는 경우 'npm cache clean'으로 cache정리를 해보세요.
4. 모듈 사용하기
- underscore를 사용해 봅시다.
아래의 코드를 여러분의 IDE에 입력해 보세요.
var _ = require('underscore'); var arr = [1,2,3,4,5] // 가장 처음의 값에 접근하기 console.log(arr[0]); console.log(_.first(arr)); // 마지막 값에 접근하기 console.log(arr[arr.length - 1]); console.log(_.last(arr));
underscore라는 모듈을 설치함으로해서 우리는 배열의 값들에 접근할 수 있는 방법을 얻게 되었습니다. 우리에 앞선 선배들이 만들어 놓은 다양한 모듈들을 단순히 가져오는 것만으로도 우리는 간편하게 다양한 기능들을 쓸 수 있게 된 것이죠.
여기서 중요한 시사점이 있습니다. 하나의 완성된 앱을 건담 프라모델이라고 생각해 봅시다. 극단적인 상황을 가정하여 여러분이 하나의 프라모델을 완성하기 위해 원하는 플라스틱을 가공하고 이것들을 조립한다고 생각한다면, 너무도 큰 일이고 힘든 일이 될 것입니다. 즉, 생산성이 매우 떨어 지게 되는 것이죠. 만약 여러분들이 만들게 되는 부품을 표준화된 형태로 만들어서 다른 사람도 함께 쓸 수 있게 된다면, 여러분의 부품을 사용하게 되는 다른 사람은 좀 더 빠르고 쉽게 다음 단계로 나아갈 수 있을 것입니다. 인간이 다른 동물과의 가장 큰 차이점이 지식을 전달할 수 있는 언어와 인쇄기술을 발달시킨 것입니다. 우리는 새로운 부품을 만들어 내는 선구자가 될 수도 있지만, 다른 선구자들이 만들어 놓은 부품들을 사용해 혜택을 보는 후손이 될 수도 있습니다. 이것은 지식의 발전적 관점에서 보면 매우 중요한 인식의 전환입니다. 사설이 길었지만 제가 하고 싶은 말은 모든 것을 혼자 다 하려고 하지마세요. 누가 미리 만들어 놓은 부품을 사용한다고 해서 여러분이 정직하지 못하거나, 실력이 모자란 것이 아닙니다. 부품을 잘 사용하고 여러분도 나중에 많은 사람들의 사랑을 받는 부품을 만듦으로써 보답하면 됩니다. (사실 이건 저의 얘기 입니다.ㅎㅎ 위와 같은 이유로 다른 사람이 만들어 놓은 모듈을 사용하는 것을 꺼렸거든요.)
4. Callback
Callback함수는 무엇인까요?
- 먼저 Callback함수에 대한 정의부터 하고 진행해 보겠습니다. 통상 함수를 정의하고 함수를 호출하기 위해 우리는 정의된 이름의 함수를 호출해 줍니다. 여기서 함수를 호출하는 것을 Call이라고 하고 이때 함수내에 정의된 실행코드들이 개발자의 의도에 따라 실행되게 됩니다. 즉, 함수를 Call(호출) 할때 실행되는 함수를 일반적인 함수라고 합니다. 그렇다면 Callback함수는 Call(호출)시에 실행되는 것이 아니라, Callback(응답)할때 호출되는 함수입니다. 여기서 유의해야 하는 것은 사람은 프로그램이 실행되는 와중에 여러분이 의도한 실행코드를 순차적으로 실행하기 위해 개입하거나 할 수 없다는 것입니다. 여기서 이해가 필요한 중요한 것은 비동기 입니다. 프로그램이 실행된 뒤 특정 함수를 호출하고 함수내에서 그 결과를 이용해서 또다른 작업을 수행하고자 할때 우리는 callback함수를 사용하게 됩니다.
비동기를 이해하기 위해서는 하나의 소설을 이해할 필요가 있습니다. TS는 보디빌딩 대회 참여를 위해 극단적인 식단관리에 들어갑니다. 대회가 끝나고 그동안 먹지 못했던 음식들을 먹기 위해 평소 먹지 못했던 피자, 햄버거, 라면, 족발, 김밥을 먹기로 합니다. 하지만 점심시간이었고, 한집 한집 들러 TS가 원하는 모든 음식을 받아오기에는 너무나 시간이 걸립니다.(하나의 작업이 완료되고 다음 작업이 수행되는 것: 동기처리) 좋은 아이디어를 생각하던 중 순X이라는 어플을 떠올리고 본인이 원하는 음식점을 들러 번호를 받습니다. 각각의 음식점의 음식이 준비되면 먼저 완료되는 지점부터 방문해서 음식을 받게되는 것이죠.(한번에 모두 실행하고 먼저 완료되는것 부터 처리하는 방법: 비동기처리)
터미널에서 node라고 타이핑 합니다. 이렇게 되면 우리는 한줄 한줄 입력하는 형태로 프로그래밍 할 수 있게 됩니다. 즉각적인 결과값을 확인할 수 있지만, 앞선 코딩에서 수정 사항이 발생 하면 수정에 어려움이 있다는 점에서 저희는 지금까지 IDE에서 파일형태로 코드를 입력하고 한꺼번에 컴파일하는 과정을 거쳤습니다. 어쨌든 지금은 node를 타이핑하고 한줄 한줄 바로 결과를 확인해 보도록 하겠습니다.
node
지금부터 한줄한줄 실행할 수 있게 됩니다. 함수와 Obejct를 하나 정의해 보도록 하겠습니다.
a = [3,1,2]; function b(v1, v2){return v2-v1;}; a.sort(b); console.log(a);
다음을 실행하게 되면 3,1,2로 선언되어 있던 Object 값이 3,2,1로 출력되는 것을 확인할 수 있습니다. sort라는 메소드에 대한 documentation을 확인해 보면 함수를 인자로 받을 수 있다는 것을 확인할 수 있습니다. 또한 인자로 받게 되는 함수를 적절히 선언하면 여러분들이 원하는 의도대로 함수를 수행할 수 있게 됩니다.
5. 동기와 비동기
1. 의미
- 동기: 여러가지 일을 순차적으로 수행, 앞선 일의 완료시점은 다음 일의 시작시점.
- 비동기: 여러가지 일을 한꺼번에 수행, 완료시점 알수 없음.
2. 활용
- 지금부터는 활용을 통해 동기와 비동기를 이해해 보도록 하겠습니다.
먼저 filesystem에 관련된 documentation을 node 웹사이트에서 확인해 보시면, 파일을 읽어 오는 방식에 있어서 명시적으로 sync가 붙어 있는 method를 확인할 수 있을 겁니다. 되도록 동기 방식의 사용을 지양해라고 말하고 있지만 일단 어떤 식으로 활용하는지 확인해 보도록 하죠.
var fs = require('fs');
console.log(1); var data = fs.readFileSync('hello.txt', {encoding: 'utf8'}); console.log(data)
console.log(2);
fs.readFile('hello.txt', {encoding: 'utf8'}, function(err, data) {
console.log(3); console.log(data);
})
console.log(4) 1 hello sync & async 2 4 3 hello sync & async
결과를 확인해 보면 아래 나와 있는 형태를 확인할 수 있습니다. 여기서 주목해야 할 점은 비동기적으로 처리 되고 있는 함수의 경우 콜백함수가 호출되기 이전에 readFile함수 뒤에 있는 내용이 먼저 호출되고 있다는 점입니다. 즉, reaFile 함수의 처리가 완료 되었을 때 해당 내용을 출력하고 그 이전에 먼저 실행할 수 있는 내용을 실행하는 것이죠.