작년에 한창 텔레그램 봇이 주목받을때  같이 스터디 하는 분들과
개인 토이 프로젝트를 만든다음 공유하는 자리를 가졌었다.

나는 그때 당시에 클리앙 알뜰구매 봇 을 하나 공유했는데. http://telegram.me/hotdeal_bot

대략 Node.js 랑 MongoDB 를 이용해서 만들었었다.

사실 간단하게 웹페이지 크롤링 한다음 저장해놓고 있고 저장할때 ( 새로운놈이라고 판단되면)
봇 사용자한테 알려주는 로직인데 당시에 webhook 형태로 만드려고 ( https만 지원) 이것저것 설정을 바꾸어서 재밌게 만들었다.

이 봇이 대략적으로 지금 10개월 정도 운영중인데..
( 사용자는 500명 좀 안됨 당시에 한번 글 쓰고 나서 공유 안하는데도 계속 사용자는 조금씩 증가한다. )
채널 형태로 만들 수도 있었지만 나중에 확장성(?) 을 생각해서 봇 형태로 유지했었다.

그리고 사용자들이 내 봇한테 /noti 를 날리면 해당 유저를 등록해놓고 그 유저한테 개인 메시지 보내듯이 할 수 있어서 뭔가 더 뿌듯하기도 했고..

아무튼 히스토리는 이렇고 위 봇이 돌고있는 서버는 DigtialOcean의 가장 낮은 사양 ( 한달에 5불) 이다.

이 가상서버는 512메가의 메모리를 가지고 있는데.
최근에 클리앙도 업데이트했고 간혹가다가 Node 가 뻗는 이슈가 있어서 마음의 짐처럼  가지고 있다가 로그를 좀 살펴봤는데

뻗는 이유가 2개 였다.

1. DB 에 url을 업데이트 하고 user 정보를 업데이트 하는데 mongoDB 서비스가 갑자기 죽어 버릴때 노드가 재시작
2. 텔레그램  API를 통해 메시지를 전달할때 정의되지 않은 오류 또는 가상버서 메모리 leak이 발생해서 노드가 재시작

위 2가지 이유였는데. 일단 1번이 시급했기 때문에
digitalOcean이 아닌 fun25 란 곳의 가상서버로 mongoDB 서비스를  옮기는 작업이 필요했다. ( 여기는 메모리가 4기가. 다만 포트가 제한적이다. 1년치가 66000원 인데 이것저것 개인 프로젝트 하고 놀기 딱 좋다.
이 블로그도 fun25에서 돌고 있다. 사실 봇도 fun25에서 돌리고 싶은데.. 포트가 digitialOcean은 다 열려있어서 더 해보고싶은게 있다. )

그래서 mongoDB 의 데이터를 이전하는 찾아 봤는데 생각보다 간단해서 놀라웠다.

우선 해당 서버에서 아래와 같이 치고   이전하고 싶은  db와 collection을 찾아둔다.

$ mongose
> show dbs;
> show collections; 

여기서 만약 mongoDB 가 port가 다르게 되어있다면 --port 12000 와 같이 mongose 명령어 뒤에 붙혀 주면 된다. 

그다음 다시 mongose를 나가서 아래와 같이 명령어를 입력하면 된다.
$ mongoexport -h 127.0.0.1:27000 -d dbName -c collectionName -o filename.json

위에서 127.0.0.1:27000은 mongoDB가 돌고있는 서비스 호스트와 포트고 dbName은 해당 데이터가 저장되어있는 db이름 그리고 collectionName은 저장되어있는 collection이름으로
변경해주면 된다. 물론 filename은 원하는데로 변경해주면 된다.

  • mongoexport 의 옵션
-h[--host] 호스트
-u[--username] 아이디 인증이 없다면 없어도 된다. 
-p[--password] 비밀번호
-d[--db] 디비이름
-c[--collection] 사용할 컬렉션명
-q[--query] query필터
-o[--out] output 파일

그 다음 이전하게 될 서버에 mongoDB가 떠있는지 확인하고 아래와 같이 명령어를 입력해주면 된다.

$ mongoimport -h 127.0.0.1:27017 -d dbName -c collectionName --file filename.json

  • mongoimport 의 옵션은
-h[--host] 호스트
-u[--username] 아이디 인증 없다면 없어도 된다.
-p[--password] 비밀번호 
-d[--db] 디비이름
-c[--collection]  컬렉션명
-f[--fields] 필드명
--file 파일명
--drop 컬렉션을 처음 드랍할때
--upsert 이미 존재할때는 update 아닐경우 insert

위 명령어만 끝나면 생각보다 이전이 쉽게 된다.

예전부터 정리해보고 싶었던 주제인데. 드디어 정리하게된다. ( 사실 많이 늦은 내용이지만.. 내 생각을 정리하는 용도로..)

javaScript 로 개발을 하다가 다양한 데이터를 다루다 보면은 ( 주로 서버에서 내려오는 . 또는 로그나.. ) lodash나 underscore 라는 라이브러리를 많이 사용하게 된다.

내가 프로젝트의 메인 역할을 할때는 개인적으로 lodash나 underscore를 선호하지 않았는데 이유는 다음과 같다.
( 누군가 include를 했었어도 나는 native로 ..)

  1. 일반적으로 크기가 큰 데이터는 배열 형태이다. ( 주로 내가 다뤘던 )
  2. 배열은 데이터를 처리하기 유용한 메소드를 기본적으로 제공한다.
  3. 물론 이 메소드들은 ES5이상에서 주로 많이 쓰이며 ES6에서는 더 많이 제공한다.
  4. SUGAR 라이브러리들이 아무리 좋아도 성능으로 native를 따라올수가 없다.
  5. 사실 웬만한 데이터 처리는 직접 짜서 쓰는게 낫다고 생각한다.

간단하게 forEach를 가지고 이 이야기를 해보자.

Array가 보유 하고 있는 forEach 메소드는 배열을 순회하면서 데이터를 처리할때 아주 유용하다.
ES5 일 때 코드 는 아래와 같다.

var array = [1,2,3,4,5,6]
array.forEach(function(v){ 
    console.log( v+1); 
});

물론 ES6 일경우에는 더욱더 코드가 줄어든다.

const array = [1,2,3,4,5,6]
array.forEach(v => console.log(v+1)); 

보기에도 깔끔하고 ES6(ES2015)로 가면 저런 Native 메소드를 안쓸 이유가 없다. 추가적으로 forEach와 비슷한 역할을 하는 메소드로는 jQuery의 $.each 가 있는데 이 메소드는주로 ES5 문법을 지원하지 않는 브라우저에서 (IE 계열.. 7,8 ) Array.forEach대신 $.each를 많이 사용해서 오래된 코드들을 보면 대부분 사용하고있다.

*물론 $().each() 와는 조금 다르다. $() 는 chainIng을 지원하기 때문에 $().each() 의 경우에는 $.each()와 다르게 장점이 존재한다.
*추가로 Angular에서 Angular.forEach로도 사용가능하다. (angular는 jqlite 가 포함되어있기 때문에 .)

이렇듯이 같은 역할(?) 을 하는 메소드들이 여러가지가 있지만. 나는 Array.forEach()를 선호했다.
이유는 라이브러리의 의존성을 줄이는것도 목적이지만. 속도 이슈에서 native 메소드가 더 좋기때문이기도 했다.

그렇다면 이 글에서 다루고자 하는  lodash와 underscroe 와 같은 라이브러리를 보자

lodash도 그렇고 unserscore도 그렇고 forEach 역할을 하는 메소드들은 당연히 존재한다.

lodash

_.forEach( array, v => console.log( v +1 ) );

underscore 는

_.each( array, v => console.log( v +1 ) );

코드로만 봤을때는 별 차이가 없고 차이는 배열을 인자로 전달한다는 것이다. 사실 이 부분이 차이가 있는데
array.forEach() 방식으로 인해 array 가 Array type이 아닌 경우에는 “undefined” 오류가 난다.

이런 문제는  $.each()도, lodash나 underscore 모두 발생하지 않는다. ( 스크립트가 뻗지 않는다는 것이다. )
이건 실제로 프로젝트를 할때  array 의 값이 서버에서 제대로 오지 않거나. 중간에 다른 모듈에서 제대로 값이 전달되지 않았을때
JS의 특성상 중간에 멈춰 버리기때문에 사실 치명적이다.

예를들어 native 의 document.getElementsByClassName() 같은 선택자로 리턴된값을  forEach를 적용하게 되면
해당 값은 array 같이 보이지만 실제로는 Array Type이 아닌 array-like object 이기 때문에 forEach메소드가 없고 오류가 발생하게 된다.

http://stackoverflow.com/questions/24266313/using-foreach-on-an-array-from-getelementsbyclassname-results-in-typeerror-und

위 링크와 비슷한 일이 실제로 많이 발생한다.

이러한 실수를 줄여주려면 개발자가 예외처리를 잘하고 타입에 대해 항상 생각하고 개발을 해야 한다.
다만 lodash, underscroe 와 같은 라이브러리를 사용하면 이러한 처리를 따로 해줄 필요가 없는것이다.

그리고 위에서 언급 하지 않은 lodash나 underscore가 native 에 비해 장점이 하나 더있다.
그건 바로 다양한 메소드 제공인데. 현재 2017.05.25 기준으로 .underscore는 100개 이상의 메소드가 제공되며 lodash 또한 정말 많은 메소드들이
제공된다. 이건 native가 따라올 수 없는 부분이며 분명히 이점이 된다. ( 참고 : https://colintoh.com/blog/lodash-10-javascript-utility-functions-stop-rewriting)

또한 lodash나 underscore 는 Array 타입의 객체만 사용할 수 있는게 아니라. 다양한 Object 데이터 타입에서도 사용 가능하다.
이건 데이터 처리를 하는데 있어서 엄청난 장점이다.

결론적으로 다음과 같이 정리할 수 있다.

Native

  • 장점 : 빠르다, 코드 유지/보수가 편하다, 브라우저 호환성 (ES5는 대부분 지원하니.)
  • 단점:  예외처리를 잘해야한다, Array 타입밖에 지원안함, 복잡한 데이터 처리에는 직접 메소드를 만들어서 써야한다.

lodash/underscroe

  • 장점: 다양한 메소드 제공으로 생산성이 향상된다, 스크립트가 뻗는 경우가 없다, 객체도 지원하므로 데이터 처리에 용이하다.
  • 단점: 무겁다, native에 비해서는 느리다,  협업할때 상대방이 익숙하지 않은 메소드는 doc을 한번 살펴봐야 한다. 최신 v8엔진 에서만 지원한다.(lodash경우)

결론을 내리자면( 개인적인 견해 )프론트엔드의 경우에는 초기 로딩 속도로 리소스의 양을 많이 줄여야되는데 ( 특히 모바일 ) 프론트엔드에서의 데이터 처리는 대부분 한정적이며, 다른 사람과의 협업할때는 Native 가 더 좋기 때문에 프론트엔드 프로젝트 ( 특히 모바일) 의 경우에는 굳이 이런 라이브러리를 쓰는걸  나는 앞으로도 최대한 지양할 것 같다. 다만 Node.js 를 활용한 백단 작업에서는 스크립트가 뻗는 오류가 프론트보다는 위험하고 , 데이터 처리가 많으며 라이브러리가 많은게 부담이 덜 되므로 잘 사용하면 생산성을 많이 올려줄 것이라고 본다