슬쩍 떠보는 npm 과 package.json

GruntJS 와 같이 Node.js 로 만들어진 유틸리티들은 npm 을 통해 설치하고 사용하는 것이 쉽고 편리하다. 하지만 Node.js 를 깊이 공부해보려는 목적이 아니라면 굳이 npm 에 대해 깊이 알 필요는 없다. 그런 사람들과 입문자들을 위해 npm 을 통한 패키지의 설치/제거방법과 package.json 에 대해 간단히 알아보려고 한다.

npm 는 Node Package Manager 의 약자이다. 보통 npm 은 두가지 의미로 사용된다. 첫번째는 오픈소스로 작성된 Node.js 모듈들이 등록된 저장소인 http://npmjs.com 를 의미한다. 두번째는 패키지를 인스톨하고 의존성을 관리하는 자바스크립트로 작성된 커맨드라인 유틸리티이다. 커맨드라인 유틸리티는 npmjs.com 의 저장소로 부터 패키지를 찾고 설치하는 등의 기능을 사용할 수 있다. 이 글에서 npm 은 주로 커맨드라인 유틸리티의 의미로 사용하고, 첫번째 의미의 npm 은 npm 저장소라고 부를 것이다.

패키지 관리가 필요한 이유

일반적으로 Node.js 의 프로젝트는 의존하는 다른 패키지의 소스코드를 포함하지 않는다. 대신 의존하는 패키지들을 package.json 에 명시하고 개발자들은 npm 을 사용해 각자 설치해 사용한다. 특히 패키지들 중에는 C 코드를 컴파일해야 하는 것들도 있다. 이 때 컴파일된 결과물은 OS 나 시스템에 의존적이기 때문에 패키지에 포함되지 않는다. 따라서 다른 패키지의 소스코드를 포함하지 않는 것이 원칙이고 패키지 설치와 제거를 위해 npm 기본사용법을 알아야 한다.

패키지 설치와 제거

패키지 설치

npm install <패키지이름|패키지외부URL>

패키지 설치를 위해서는 install 명령을 사용한다. npm 저장소에 위치한 패키지들은 패키지이름을 적으면 설치된다. npm 패키지 외에 git 저장소나 외부 URL 에 위치한 패키지들도 설치도 가능하다. 외부 패키지 설치와 관련한 내용은 공식문서의 Install Package공식문서의 Specifics of npm’s package.json handling에 정리되어 있다.

지역패키지, 전역패키지 지정 옵션

npm 패키지는 설치되는 위치에 따라 지역패키지와 전역패키지로 나눌 수 있다.

전역(global)패키지는 시스템 전체에서 사용할 수 있도록 설치되는 패키지이다. 특히 명령어를 사용해야하는 경우에 많이 사용한다. 예를들어 grunt-cli 패키지는 grunt 명령을 포함하는데, 이 명령은 시스템 어디에서든 실행될 수 있어야 하므로 전역 패키지로 분류할 수 있다. 전역패키지로 설치하기 위해서는 전역을 의미하는 --global(또는 -g) 옵션을 사용한다.

npm install <패키지이름|패키지외부URL> --global

지역(local)패키지는 현재 프로젝트에만 한정해 사용하는 패키지를 말한다. 이 패키지들은 프로젝트 루트 디렉토리(package.json 이 있는 디렉토리)의 바로 아래에 node_modules 디렉토리에 설치된다. package.json 을 찾을 수 없으면 현재 디렉토리에 바로 아래에 node_modules 디렉토리를 만들고 여기에 패키지를 설치한다. --global 옵션을 명시하지 않은 경우 지역패키지로 설치된다.

의존성 명시 옵션

package.json 에는 프로젝트가 의존하고 있는 다른 프로젝트를 명시할 수 있다. 특히 유닛테스트용 패키지나 grunt 태스크 플러그인처럼 프로젝트를 개발하거나 테스트할 때만 필요한 패키지들만 따로 명시해 설치할 수도 있다.

--save : 패키지를 설치하고 package.jsondependencies 항목에 설치한 패키지의 이름과 버전을 명시한다.

--save-dev : 패키지를 설치하고 package.jsondevDependencies 항목에 설치한 패키지의 이름과 버전을 명시한다.

npm install <패키지이름|패키지외부URL> [--save-dev|--save]

의존성 전체 설치

npm install [--production]

package.jsondependenciesdevDependencies 에 명시된 의존성 패키지들은 다른 옵션없이 npm install 명령으로 설치할 수 있다.

프로젝트를 개발/테스트하려는 것이 아니라 활용만 하려는 목적이라면 개발의존성을 설치하는 것이 불필요하므로 devDependencies 의 패키지를 제외하고 설치할 수도 있다. 이 때는 --production 옵션을 사용한다.

패키지 제거

npm uninstall <패키지이름> [--save-dev|--save|--global]

패키지를 제거하는 명령은 npm uninstall 이다. npm install 과 마찬가지로 --global --save-dev --save 옵션을 사용할 수 있다.

주의할 점은 --save--save-dev 옵션을 사용해 의존성을 명시한 패키지들은 제거할 때도 --save--save-dev 를 사용해야 package.json 의 의존성 항목을 제거한다.

마찬가지로 전역패키지에서 찾아 제거하려면 --global 를 명시해야한다.

짧은 이름 사용하기

npm 은 명령어 중엔 별명을 사용할 수 있는 명령들이 있다. 예를 들어 npm installnpm i 로 줄여 쓸 수 있다. 그리고 npm uninstallnpm unpm rm, npm r 으로 줄여 사용할 수 있다.

package.json 생성

npm init [--yes]

package.json 은 정해진 규칙이 있는 JSON 형식의 파일이다. 하지만 세부 내용들을 모두 외워 생성하는 것은 어렵다. 이 때 npm init 명령을 통해 package.json 을 쉽게 생성할 수 있다.

npm init 은 대화형 인터페이스로 package.json 을 생성하도록 도와준다. 이 때 모든 값을 기본값으로 채우고 싶다면 -yes(또는 -y) 옵션을 사용할 수 있다. pacakge.json 의 일반적인 항목을 자동으로 채워 생성한다.

package.json 의 주요항목

package.json 은 npm 이 사용하는 설정 파일이다. 패키지의 이름 및 의존성 등이 이 파일에 명시된다. 이 파일의 주요항목을 살펴보자.

name 프로젝트의 이름이다. 기본값은 프로젝트의 디렉토리 이름이다.

version 프로젝트의 버전이다. Node.js 패키지의 버전은 유의적 버전(Semver: Semantic Versioning) 의 체계를 사용한다. 이 체계는 버전번호를 주버전(主, Major), 부버전(部, Minor), 수버전(修, Patch) 로 구분해 3개의 점(dot) 으로 표현한다. 즉, 2.1.3 버전이 있다고 한다면, 주버전은 2, 부버전은 1, 수버전은 3이다. nameversion 항목은 package.json 에서 가장 중요한 정보이다. 이 두가지 정보를 결합해 패키지의 식별자로 사용한다. 따라서 패키지의 내용이 변경되면 꼭 version 항목을 변경해야한다. 참고로 npm version [major|minor|patch] 명령을 사용하면 자동으로 package.json 의 version 항목을 변경하고 Git 저장소에 버전이름(v2.1.3 형식)으로 태그를 달 수 있다.

(참고: 유의적 버전에 대해서는 http://semver.org/lang/ko/ 를 참고하자.)

description 프로젝트의 구체적인 설명이다.

main 이 패키지의 엔트리포인트가 되는 자바스크립트 파일경로를 명시한다. 만약 패키지의 이름이 foo 라면 다른 패키지에서는 require('foo') 문으로 이 패키지를 로드한다. 이 때 main 에 지정된 파일을 로드하게 된다.

scripts 패키지에서 반복적으로 사용할 주요명령들을 지정해 사용할 수 있다. 기본값으로 생성된 test 를 실행하기 위해서는 npm test 으로 실행할 수 있다.

keywords 이 패키지를 설명하는 키워드들이다. 이렇게 지정된 키워드들은 npm search 명령으로 패키지를 검색할 때 검색어로 사용된다.

license 패키지의 라이선스 정책을 명시한다. 기본값은 ISC 이다. 참고로 ISC 는 INTERNET SYSTEMS CONSORTIUM 의 약자로 이 단체에서 제정한 공개 소프트웨어 라이선스이다.

author, contributors 객체형식 또는 문자열 형식으로 개발자의 이름과 이메일을 명시한다. author 는 원 저작자이기 때문에 문자열형식이나 객체형식으로 한명만 지정하고, contributors 는 여러 사람이 될 수 있으므로 배열 형식으로 지정한다. 사람을 표현할 때는 아래와 같이 이름, 이메일, URL을 명시할 수 있고, 이메일과 URL은 선택사항이다.

객체 형식으로 지정한 예

{ "name" : "Constantine Kim"
, "email" : "[email protected]"
, "url" : "http://elegantcoder.com/"
}

문자열로 표현한 예

"Constantine Kim <[email protected]> (http://elegantcoder.com/)"

dependencies, devDependencies 이 패키지가 다른 패키지에 의존할 경우 의존성에 대한 항목이다. foo 라는 프로젝트의 2.x 버전에 의존적이라면 아래와 같이 명시한다.

{
  "dependencies" :
    "foo" : "2.x"
  }
}

이렇게 이름과 버전을 명시한 패키지들은 npm 저장소로부터 설치된다. 앞서 패키지 설치 장에서 봤듯 npm 저장소 외에도 git 저장소나 외부 URL 의 패키지도 명시할 수 있다.

dependencies 는 이 패키지에 의존하는 다른 프로젝트에서 구동시키기 위한 의존성이다. 즉, 이 패키지를 활용할 때 필요한 의존성을 명시한다. npm install --save 명령을 통해 패키지를 설치하면 이 항목에 프로젝트 정보가 저장된다.

devDependencies 에는 이 패키지를 테스트하거나 개발할 때 필요한 패키지들을 명시한다. npm install --save-dev 명령을 통해 패키지를 설치하면 이 항목에 프로젝트 정보가 저장된다.

Google Spreadsheet 로 쉽고 빠른 Backoffice 구축

Google IO Extended Seoul 에 다녀왔다. 나는 C 홀에 있었는데 라이트닝 토크 세션이 있고 그 자리에서 발표신청을 해도 된다길래 즉석해서 “스타트업 개발자의 수고를 줄여주는 GoogleSpreadsheet” 라는 주제로 자료를 만들어 발표했다.

5분은 짧은 시간이었지만 개괄적으로 이야기하기에는 충분한 시간이었다. 세션 후에 적극적으로 질문 해주시는 분들을 보고 나에게만 고민스러웠던 주제가 아니구나 하는 생각을 하게 됐다. 발표자료를 공유하고 더 자세한 내용을 블로그 포스트로 적어봤다.

덧) 오프라인 세미나를 준비하고 있다. 구글 설문지 를 통해 의향을 알려주셨으면 한다.

앱이나 웹을 개발할 때 서비스를 구성하는 컨텐츠를 제작해야 한다. 컨텐츠는 맛집서비스라면 맛집데이터 일 수 있고, “이메일 형식으로 입력해 주세요” 같은 문구일 수도 있다. 프로젝트에서 컨텐츠 제작에는 대부분 기획자나 큐레이터 등 별도의 롤을 둔다. 그리고 개발자는 그 컨텐츠를 소프트웨어에 맞게 옮긴다. 그런데 이렇게 옮기는 작업에도 시간이 든다. 한글로 된 컨텐츠라면 맞춤법이 틀린 부분을 발견하고 피드백하는데도 시간이 든다.

그래서 스타트업 개발자는 언제나 시간이 부족하다. 그렇다고 컨텐츠 담당자에게 “데이터를 JSON으로 만들어주세요.” 라고 요청할 수는 없는 것 아닌가. 그래서 지금도 수많은 개발자들이 텍스트데이터를 복사와 붙여넣기 기능으로 JSON 으로, 하드코딩으로 소프트웨어를 만들고 있다.

누구나 이 쯤에서 백오피스로 만들어 처리하면 좋겠다고 생각할 것이다. 하지만 스타트업 개발자에게 그럴만한 여유가 없다. 한시가 바쁜데 서비스와 서비스의 컨텐츠를 구성하는 도구까지 만들어야하는 것이다. 그리고 백오피스를 구축하려면 사내에서만 접속하도록 보안관련 사항을 구축하고 사내에 활용교육도 해야한다. 그리고 구축 후 뭔가 변경되면 그 때마다 교육이 필요하다. 쉽지 않은 일이다.

따라서 개발자는 백오피스를 만드는 데에 보수적이어야 한다. 도구를 갖는 것에 반대해야 한다는 것이 아니다. 빠르게 변하는 스타트업의 비즈니스를 담을 수 있는 은탄환같은 백오피스를 만들기에는 시간이 많이 들기 때문에 쉽게 접근해서는 안된다는 것이다.

그렇다고 도구를 갖지 않을 수는 없으니 백오피스는 스스로 구축하기 보단 있는 것을 조합해 사용하자. 그래서 나는 구글 스프레드시트로 백오피스를 대신하는 것을 추천한다.

왜 구글 스프레드시트인가?

구글스프레드시트는 모두의 도구다. 특히 IT 에 밝지 않은 사람이 새로운 도구를 익히는데 방어적인 경우가 많은데 그렇다하더라도 엑셀을 다루지 못하는 사람은 드물다. 여기에는 컨텐츠 담당자들에게 손에 익숙한 도구를 쥐어주고 협업을 강화하는데 의미가 있다. 컨텐츠 작성을 컨텐츠 담당자에게 온전히 돌려주고, 개발자가 소프트웨어로 옮기는 작업을 최소화할 수 있다.

구글 스프레드 시트는 강력하다. 기본적으로 엑셀과 비슷한 함수셋을 가지고 있기 때문에 컨텐츠 개발자에게는 반복되는 일을 줄여줄 것이다. 또 필요한 함수가 있다면 개발자가 직접 자바스크립트로 직접 작성해 기능을 추가할 수도 있다. 또 공개된 API 를 사용해 스프레드시트의 내용을 JSON/XML 포맷으로 쉽게 변환해 다운로드 받을 수 있다.

다시말해 구글 스프레드시트는 비 개발자들에게는 손쉬운 도구이면서 개발자에게는 강력한 도구가 된다.

구글 스프레드시트로 백오피스를 대체하는 방법

먼저 백오피스에서 입력할만한 데이터의 특성은 읽기에는 열려있고 쓰기에는 닫겨있다. 즉, 입력을 하는 사람은 한정적이다. 하지만 데이터 자체는 어떤 방법으로든 모든 사람에게 공개될 것이다. 예를들면 웹사이트의 “언론보도” 에 들어가는 데이터 정도를 들 수 있다.

데이터 입력은 구글 설문지에서

데이터 입력은 어느정도 정규화되어야 한다. 따라서 구글 설문지를 활용하자. 입력값 검증(validation) 도 어느정도 가능하다. 데이터를 입력하는 사람이 한정적이라는 것은 상대적으로 검증에 여유롭다는 말도 되므로 적은 검증으로도 활용할 수 있다.

데이터 수정/삭제는 스프레드시트에서 직접수행

설문양식으로 입력받은 데이터는 스프레드시트에 곧바로 들어간다. 따라서 이 시트에서 직접 수정하고 삭제할 수 있다.

개발자의 스프레드시트 활용

필요한 함수가 있다면 직접 작성

Google Apps Script 를 통해 스프레드시트에 들어갈 함수를 직접작성할 수 있다.

예를들어 아래 코드는 내가 만든 전각-반각 변환 자바스크립트 함수다. 회사가 중국어를 다루다보니 필요해서 만들게 되었다.

아스키 문자를 입력하더라도 중국어나 일본어 키보드로 입력하면 I'm full width 처럼 입력된다. 이 때 이 글자들이 바로 전각문자다. 자바스크립트를 사용해 구글 스프레드시트의 함수를 작성하고, 스프레드시트 내에서 이 함수를 호출해 반각문자로 손쉽게 변경할 수 있다.

참고로 전각문자들은 아스키코드와 동일한 순서로 코드가 배열되어 있어 그대로 변환만 하면된다. 다만 영어/한국어로 타이핑 할 때 마침표(.)를 타이핑하면 중국어/일본어에서는 。 로 표시가 되는데, 이것은 아스키코드 순서로 변환할 수 없어 이에 대해서만 별도의 처리를 해주었다. 전각 코드표는 여기에서 볼 수 있다. https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms

function ch_fw2hw(string) {
  var re = /([\uFF01-\uFF5E])/g;
  var unicodeStarting = "\uFF01".charCodeAt();
  var asciiStarting = "!".charCodeAt();
  string = string.replace(re, function (match, p1, offset, string) {
      var asciiCharCode = asciiStarting + (p1.charCodeAt() - unicodeStarting);
      return String.fromCharCode(asciiCharCode);
  }); 
  string = string.replace(/。/g, '.');
  return string;
}   

이렇게 작성한 코드는 스프레드 시트에서 곧바로 사용할 수 있다.

Screen Shot 2015-07-13 at 2.37.55 AM

외부서비스로부터 데이터가져오기, 데이터 내보내기 가능

그리고 URL 로부터 데이터를 받아온다던지 네트워크를 지원하므로 외부 서비스와의 연동도 가능하다. 예를들면 Facebook API 와 연동해 좋아요 횟수를 카운트 할 수도 있다.

Screen Shot 2015-07-13 at 2.38.58 AM

여러가지 방법으로 스프레드시트 API 에 접근해 내용을 JSON 으로 받아올 수 있다. API 에 접근하는 라이브러리를 사용해 직접 만들 수도 있고, 외부에서 Apps Script 를 실행해 읽어올 수도 있다.

아래 그림은 내부 프로젝트로 진행했던 translator 의 실행화면이다. 시트의 내용을 그대로 JSON 으로 받아오고 있다.

Screen Shot 2015-07-13 at 2.43.13 AM

보안문제는 어떤가?

발표 후에 가장 많이 들은 질문이다. 보안이라면 시트자체의 보안과 스크립트 실행권한의 2가지 측면에서 살펴볼 수 있을 것이다.

기본적으로 시트의 공유설정을 통해 받은 사람 외에는 다른 사람은 쓰거나 볼 수 없게 설정이 가능하다. 그리고 그림과 같이 Apps Script 실행권한을 제한할 수 있다. Apps Script 실행권한은 App 이 시트에 접근할 때 어떤 사용자를 대신해 접근하는지와 어떤 권한으로 Apps Script 을 실행할지로 나눠 생각할 수 있다.

Screen Shot 2015-07-13 at 1.53.00 AM

다만 Apps Script 에서 접근을 제한하는 경우에는 로그인이 필요하기 때문에 커맨드라인 인터페이스를 통해 Google OAuth 로그인하는 프로그램을 짜야하고 이것은 난이도가 다소 높다.

다시 말하지만 스타트업의 쉴새없이 변하는 비즈니스를 담을 수 있는 백오피스는 없다. 대신 도구를 조합해 최고의 퍼포먼스를 발휘하는데에 집중하자. 사실 나는 이 전에 그런 백오피스를 만들고자 했고, 관리에 실패한 후 이것을 깨달았음을 고백한다.

글을 쓰고보니 코드 한 줄 없이 개발자에게 공부할거리만 지운것은 아닌가 싶다. Apps Script 사용법을 알려드리고 직접 작성해보는 오프라인 세미나를 갖는 것이 좋겠다는 생각이 들었는데 혹시 참석 의향이 있다면 아래 구글 설문지로 의견을 주시기 바란다. 대략 2~3시간 정도면 Apps Script 의 기본 사용법을 라이브코딩으로 배울 수 있을 것이라 생각한다.

구형 맥북프로, 연속성 기능 활성화 성공

OSX Yosemite(v10.10) 이 되면서 혁신적이었다고 평가받는 것은 바로 연속성 기능 이다. 이 기능은 맥과 iOS 를 오가며 실행하던 애플리케이션을 끊김없이 실행할 수 있는 기능이다.

현재 가지고 있는 맥북은 Macbook Pro 15” 2011 Early CTO 버전이다. 물론 이미 노쇠했지만 개인적인 사정으로 은퇴하지 못하고 꾸준히 부품을 교체하며 버티고 있다.

하지만 현재 가지고 있는 모델이 연속성 기능이 제대로 지원되지 않아 아쉬웠다. 연속성기능에 포함된 모든 기능을 사용하기 위해서는 iOS 와 맥 모두 블루투스LE(BLE, Bluetooth Low Energy) 가 반드시 지원되어야 한다.

페이스타임을 통한 셀룰러 통화나 SMS 문자 전달은 동일한 아이클라우드 계정에 접속하기만 하면 자동으로 활성화되지만, iOS와 OS X간의 핸드오프와 인스턴트 핫스팟, 에어드롭 기능은 블루투스LE를 반드시 지원해야 합니다 .
OS X 요세미티와 iOS 연속성 기능을 구형 맥에서 사용하는 방법… ‘2011 맥북 에어 및 맥 미니는 더 간단합니다.’ – Back To The Mac

근래에 여유가 있던 차에 맥북에서도 연속성기능을 사용할 수 있도록 부품을 교체했다.

랩탑에 탑재된 랜카드는 BCM94331PCIEBT4AX (Bluethooth 2.1+EDR) 모델인데 BLE 를 사용하기 위해서는 BCM94331PCIEBT4CAX(Bluetooth 4.0) 로 랜카드를 교체해야 한다. (모델명 끝에서 3번째에 C 에 유의.)

Back To the mac 에 따르면 이 기능을 위해 USB 블루투스 동글을 사용해도 된다고 한다http://macnews.tistory.com/2895. 하지만 USB 포트에 꽂아놓는 것은 거추장스러워 내장된 랜카드를 교체하는 방법을 선택했다. BLE 를 사용하는데 랜카드를 교체하는 이유는 랜카드에 블루투스 모듈이 탑재되어 있기 때문이다.

최근 패치에서 블루투스 동글 사용이 막혔다고 하니 참고 바란다.

구매

우선 알리익스프레스에서 랜카드를 구매했다. http://www.aliexpress.com/snapshot/6751075037.html?orderId=68001485756049 거의 가장 저렴하게 구할 수 있어서 아낀 비용을 EMS배송료에 사용했다. EMS 배송은 물론 로켓 배송이었다. 일요일에 구매한 제품이 수요일에 왔다 :)

하드웨어 교체

Untitled_2

교체 순서는 ifixit 의 내용을 따라했다.MacBook Pro 15″ Unibody Early 2011 AirPort/Bluetooth Board Replacement 안테나 4군데와 메인보드와의 연결을 떼어내면 쉽게 분리할 수 있다.

분리와 재조립은 크게 어렵지 않은데 이슈가 되는 부분은 절연테이프와 안테나 연결이다. 혼선 방지를 위해 붙여진 절연테이프가 너무 얇아 한번 떼어내면 다시 붙이기 어렵다. 그래서 지금 한 면은 절연테이프가 붙어있지 않은 상태다. 절연테이프를 구하면 다시 한번 열어 붙일 예정이다. 그리고 안테나를 떼었다 붙일 때 각이 정확하게 맞아야만 다시 연결할 수 있다.

패치 적용

정식지원되지 않는 기기에서 연속성 기능을 사용하려면 별도의 패치가 필요하다.패치는 Continuity Activation Tool 에서 다운받아 Back To The Mac 을 참고해 손쉽게 처리할 수 있었다. OS X 요세미티의 연속성 기능을 구형 맥에서 쓰는 가장 간단한 방법… 블루투스 4.0 동글!

아래 스크린샷은 하드웨어 설치 직후 호환성 검사를 실행하고 있는 모습이다. 모든 것이 순조롭게 진행되었다.

Screen_Shot_2015-07-07_at_11_59_55_PM

활용

모든 것이 매우 잘 동작한다. 그리고 연속성 기능을 사용하기 시작하면서 맥라이프가 굉장히 윤택해졌다.

iphone-main

lte

  • Airdrop 을 통하면 iPhone 과 iPad, 그리고 맥북에서 서로 사진과 링크도 주고 받을 수도 있다.
  • 사파리 뿐 아니라 페이스북에서 외부 링크를 열어보던 페이지도 Dock 에 올라온다. (확실하진 않지만) UIWebview 를 사용하는 앱들도 연속성 기능을 사용할 수 있도록 API 가 열려있는 것으로 보인다.
  • Pocket 등 연속성 지원 앱들을 사용했을 때 자동으로 이어진다.
  • OSX 의 Wifi 메뉴에서 곧바로 개인용핫스팟(Personal Hotspot) 을 사용할 수 있다.
  • 그 중에서도 링크들을 주고 받게 되면서 잠시 짬날 때 살펴보던 링크를 그대로 맥으로 이전해 볼 수 있게 된 점이 특히 마음에 든다.

참고:

중첩된.오브젝트.프로퍼티.가져오기.성공적 = getobject 

TypeError: Cannot read property ‘..’ of undefined 는 매우 흔히 발생하고 오랫동안 개발자를 괴롭혀온 에러다.

이 에러는 오브젝트의 프로퍼티에 접근하려 하는데 그 오브젝트가 undefined 인 경우 발생한다. 즉, 아래 같은 상황이다.

> var opt = {};
undefined
> opt.a.b.c.d
TypeError: Cannot read property 'b' of undefined
...
> 

특히 API 연동처럼 외부에서 생성된 오브젝트를 가져와 사용할 때 프로퍼티가 누락되면 자주 만나게 된다. 특히 스키마가 없는 NoSQL 데이터베이스를 사용하는 경우에 자주 만나는 오류이기도 하다.

그래서 여러가지 방법으로 돌파를 시도하는데, 변하지 않는건 단계가 깊어질 수록 조건문이 길어진다는 것이다. 커피스크립트 등에서는 ?. 이라는 존재연산자(existential operator)를 지원하고, JavaScript 완벽가이드에도 비슷한 코드가 수록되어 있다.

이렇게 중첩된 프로퍼티들을 조건문을 사용하지 않고 가져올 수 있다면 꽤 편리할텐데 이런 기능을 가진 패키지를 찾았다. 바로 Ben Alman 이 만든 getobject 이다. 이 패키지는 Gruntjs 에도 포함되어 있다. (사실은 이 패키지를 Gruntjs 코드를 살펴보다 알게되었다.)

패키지는 NodeJS 에서 사용할 수 있는 node-getobject 와 jquery 및 클라이언트쪽 자바스크립트에서 사용할 수 있는 jquery-getobject 패키지 두가지 이다. jquery-getobject 라는 프로젝트 명을 가지고 있긴 하지만 jquery 를 사용하지 않는 경우도 이 패키지를 사용할 수 있다.

node-getobject

먼저 node 쪽의 node-getobject 를 살펴보자. 프로젝트 홈은 http://github.com/cowboy/node-getobject 이다.

설치

npm install getobject

사용법

getobject.get(object, parts, create);

중첩된 프로퍼티에서 값을 편리하게 가져온다. 값이 없는 경우에는 undefined 를 리턴한다.

  • obj 는 대상이 되는 오브젝트이다.
  • parts 는 오브젝트 내에 접근하는 중첩된 키들을 문자열로 적는다. 예를들어 opts.a.b.c 를 가져오고 싶다면 ‘a.b.c’ 로 적는 식이다.
  • create 은 parts 에 접근하는과정에 undefined 를 만나는 경우 이들을 생성할지 설정하는 옵션이다.

 getobject.set(obj, parts, value);

중첩된 프로퍼티에 값을 적는다.

  • obj 는 대상이 되는 오브젝트이다.
  • parts 는 오브젝트 내에 접근하는 중첩된 키들을 문자열로 적는다. .get 에서의 parts 와 같다.
  • value 는 적을 값이다.

getobject.exists(obj, parts);

중첩된 프로퍼티에 값이 존재하는지 검사한다.

예제

var getobject = require(‘getobject’);
var opt = {};
getobject.get(opt, ‘a.b.c.d.e’, true);
typeof getoject.get(opt, ‘a.b.c.d’);  // object
getobject.set(opt, ‘a.b.c.d.e’, ‘hello');
getobject.get(opt, ‘a.b.c.d.e’); // hello

jquery-getobject

프로젝트 홈은 http://github.com/cowboy/jquery-getobject 이다.

클라이언트측 자바스크립트에서의 사용법은 Node 에서의 사용과는 조금 다르다.

jQuery 를 사용중이라면 jQuery 내의 메서드처럼 동작하고 없는 경우에는 window.Cowboy 라는 객체 아래에 메서드들이 위치한다.

즉, window.jQuery.getObject(),window.jQuery.setObject() (물론, window.jQuery 는 $ 로 줄여쓰는 경우가 많다.) 이거나 window.Cowboy.getObject(), window.Cowboy.setObject() 가 된다.

사용법

$.getObject(parts, create, obj);

중첩된 프로퍼티에서 값을 편리하게 가져온다. 값이 없는 경우에는 undefined 를 리턴한다.

  • parts 는 오브젝트 내에 접근하는 중첩된 키들을 문자열로 적는다. 예를들어 opts.a.b.c 를 가져오고 싶다면 ‘a.b.c’ 로 적는 식이다.
  • create 은 parts 에 접근하는과정에 undefined 를 만나는 경우 이들을 생성할지 설정하는 옵션이다.
  • obj 는 대상이 되는 오브젝트이다.

$.setObject(name, value, context);

중첩된 프로퍼티에 값을 적는 메서드이다.

  • parts 는 오브젝트 내에 접근하는 중첩된 키들을 문자열로 적는다. .getObject 에서의 parts 와 같다.
  • value 는 적을 값이다.
  • context 는 대상이 되는 오브젝트이다. context 는 생략가능하고, 생략한 경우 window 객체에서 찾아내려간다.

$.exists(parts, obj)

중첩된 프로퍼티에 값이 존재하는지 검사한다.

예제

jQuery 를 사용 중인경우

window.$ === window.jQuery; //true
var opt = {};
$.getObject('a.b.c.d.e', true, opt); //undefined 
$.setObject('a.b.c.d.e', 'hello', opt);

jQuery 를 사용하지 않는경우

window.Cowboy.getObject('a.b.c.d.e', true, opt); //undefined        
window.Cowboy.setObject('a.b.c.d.e', 'hello', opt);

스타트업, 제품 시장 궁합과 고객찾기 – 사내 그로스 해킹 세미나

재직하고 있는 KStyleTrip 에서 그로스 해킹(Growth Hacking) 관련 세미나를 했다.

그로스 해킹에 대해 위키피디아에서는 이렇게 정의한다.

그로스해킹이란 기술기반 스타트업에서 개발된 마케팅 기법으로 (기존의 것과 다른) 창의적인 방법, 분석적인 사고, 소셜 지표 등을 통해 제품을 노출하고 판매하는 것이다. (Growth hacking is a marketing technique developed by technology startups which uses creativity, analytical thinking, and social metrics to sell products and gain exposure.)

최근 번역서가 출간되어 사내에서 함께읽고 그 내용을 전파하는 자리를 마련했다.

지금까지는 막연히 페이스북 뉴스피드에서 단편적인 지식만 얻어왔다. 예를들면 링크드인은 “이메일의 3~4번째 안에 위치해야 개봉률이 높다” 같은 인사이트를 얻었다는 것 들이었다. 하지만 이런 노하우 보다는 어떻게 그런 생각을 할 수 있었는지 궁금했었다. 이 책은 그 부분에 대해 명쾌하게 이야기 한다. 지금까지의 사고 방식을 바꾸라는 것이다.

책을 자세히 읽다보니 나는 지금 그로스 해킹을 적용하기 매우 좋은 상황과 위치에 있다는 것을 알게됐다. 지금 회사가 스타트업이고 이런 세미나를 개최할 정도로 사내에 새로운 마케팅 기법에 우호적이다(그로스 해킹은 특히 대표님께서 항상 강조하는 것이기도 하다). 그로스 해킹에는 기술적인 도움이 많이 필요한데 내가 바로 개발자이고, 지표에 대한 이해가 있으며 분석을 직접 할 수 있다.

세미나를 위해 제작한 슬라이드를 공유하고자 한다. 내가 맡은 부분은 Step 1, 2 이다. 책 내용 중 일부를 공유하지만 지금까지의 생각을 어떻게 바꿔야 하는지 인사이트를 얻기에는 충분하다고 생각한다.

책의 내용에 대해 너무 많이 공개하지 않는 선에서 이야기 해보자면, 이 책에서는 전통적인 마케팅 방식을 영화 산업과 같다고 이야기 한다. 9개 영화가 망해도 블록 버스터 1개가 많은 매출을 내면 상쇄할 수 있다는 것이다. 그리고 많은 비용을 들여 산탄총을 쏘는듯이 마케팅한다. 하지만 스타트업은 그럴 수 없고 우리 인생도 그렇지 않다.

그리고 마케팅이란 에스키모인에게 냉장고를 파는게 아니라 시장에 먹히는 제품을 만들고 개선해 파는 것이라 이야기한다.

특히 스타트업 종사자라면 이 책을 꼭 한번 읽어보시기를 추천한다.