핸드스튜디오 사내강의 “Git+, Git 조금 더 배워보기”

2013년 핸드스튜디오와 연이 닿아 프로젝트를 함께 진행한 적이 있었다. 개인적으로 매우 잘 아는 유명한 회사이다 :)

당시 핸드스튜디오는 Git 을 사내 버전 관리시스템으로 도입한 초기였고, 그 과정에서 도움이 되고싶어 사내강의를 자처했다.

당시 “svn 능력자를 위한 git 개념 가이드” 라는 아주 좋은 슬라이드가 있어 도입초기에는 이 슬라이드를 교안으로 강의를 진행했고, 이후 조금 더 잘 사용해보자는 의미에서 아래 슬라이드를 제작했다.

강의 이후 까맣게 잊고 지내다 며칠 전 함께 일했던 동료로부터 git flow 도입과 관련한 문의를 받고 생각난 김에 슬라이드쉐어에 업로드 했다.

아래 슬라이드는 git-blame, git-log, git-rebase, git-flow 에 대해 간단히 알아보는 정도로 내용이 구성되어 있어 능력자들께는 부족할 수도 있겠다 :)

혹시라도 사내 강의가 필요하시면 연락주세요(소곤소곤)

Undefine:D 에서 발표한 “GruntJS로 개발프로세스 구축하기”

페이스북의 Undefine:D 정기세미나에서 “GruntJS로 개발프로세스 구축하기” 를 발표하게 되었다.

GruntJS 는 어떤 플러그인을 어떻게 사용하는지에 성패가 달려있다고 생각하기 때문에 기초보다는 사용하고 있는 플러그인 위주로 발표했다. 기초에 대해서는 이전에 많은 분들이 소개를 하셨기 때문에 발표로서의 차별화도 고려했다.

조직에서 사용하기 위해서는 구성원을 납득시킬 수 있어야 하기 때문에 도입에 대해 확신을 가질 수 있도록 장점을 보여줄 수 있는 데모를 골랐다.

첫 데모는 grunt-contrib-watch 를 골랐는데 그다지 반응이 없었다. 아마도 한번쯤은 봤던 데모여서 그럴지도 모르겠다. 오히려 grunt-injector 가 데모 중에 실수가 있었음에도 더 많은 관심을 받았다. 이외에도 grunt-imagesprite 에 대해 관심을 보여주셨다.

발표 이후에 반응을 종합해보면 현재 GruntJS 도입 초기에 있는 경우가 많다. 그리고 플러그인 하나씩을 이해하고 적용해가는 과정에 어려움을 가지고 있다. 그래서 그런 과정을 공유하면 어떨까 하는 마음에 페이스북에 GruntJS 관심그룹 을 만들었다. 이런 그룹을 만드는 것이 처음이라 어찌 잘 될지는 모르겠지만..

발표자로 서는 것이 오랫만이라 긴장했지만 발표 후에는 보람을 느꼈다. 앞으로도 공유할 것이 많아야 할텐데.. ^^

구글애널리틱스 IQ 시험 후기

스타트업에 있다보니 지표 측정이 중요하다. 아무래도 경력이 있다보니 어깨너머로 들은 지식들은 있지만 지표측정에 대해 정확히 안다고 이야기할 수는 없었다. 그렇다고 요즘 유행하는 강의를 듣기에는 비용부담이 만만하지 않았다.

GA 강사들의 프로필을 보다보니 Google 애널리틱스 공인 전문가(GAIQ)가 빠지지 않는다는 것을 알게 되었다. 아직은 회사규모가 지표만 분석하는 사람을 뽑기에는 어려움이 있어서 내가 공부하고 적용해보기로 마음먹었다.

그렇지 않아도 GA 와는 인연이 있다. 예전 KTH 에 입사해 처음 작업한 일이 바로 이벤트 측정 코드를 곳곳에 심는 일이었다. 그렇게 대략 200개 정도의 이벤트 코드를 꽂았다. 그런 이유로 GA SDK 레퍼런스도 꽤 여러번 봤었다.

시험 준비는 구글의 가이드 대로 Google Analytics Academy 의 Digital Analytics Fundamentals 강의를 보았다. (개편 후에 Google Analytics Platform Principles 까지 포함되었다고 알고 있다. )그리고 “구글 애널리틱스” 책을 한 번 다 읽었다. 강의는 영어로 되어 있지만 PDF 파일이 지원되고, 자막을 켜고 보아서 많은 도움이 되었다.

처음부터 끝까지 3번 정도 영상을 봤는데 주로 웹분석의 프로세스와 구글 애널리틱스의 기초적인 사용법에 대해 강의한다. 더 자세한 특색에 대해서는 구글 애널리틱스 도움말을 한 번 살펴본 것이 더 좋았다.

마침 사이트 런칭 직전이라 야근이 꽤 많았기 때문에 주말에만 시간이 조금 나서 대략 2개월정도 소요되었다. 동영상을 두번 보고 나서 구글의 테스트 센터에 가서 50달러를 결제하고 영어로 시험을 쳤다.

첫 시험은 사실 간만 본다는 마음으로 쳤다. 오픈북이 가능하지만 시험범위 등을 알아보는게 목적이어서 열어보지 않고 테스트를 봤고 예상대로 떨어졌다. 구글 애널리틱스의 도움말을 자세히 살펴봐야 한다는 것을 알게 됐다.

점수는 예상보다는 나쁘지 않았다. 70문제 80% 통과인데 74%로 아쉽게 탈락했다. 재시험은 2주 후에 가능했기 때문에 그 때까지 공부를 더 해야겠다고 생각했다. GAIQ첫시험 결과 74%로 불합격

어찌어찌 시간이 지나고 2주가 지났는데 짬이 안돼 1달만에 시험을 봤다.

그런데 구글 애널리틱스 시험이 기존 테스트센터에서 사라져서 당황했다. 아직 재시험을 볼 수 없게 된 것인지 싶었다. 그래서 다른 개인 계정으로 시험센터에 재접속해보니 그냥 시험이 테스트 센터에서 사라진 것이었다.

이제 GAIQ 시험 방식이 변경되어서 이제 시험을 무료로 볼 수 있다. 시험은 http://partners.google.com 에서 볼 수 있으며 이제는 한글 시험도 제공된다.

재시험을 준비하면서 이전에 공부했던 내용에 비해 조금씩 추가된 내용이 있는 것 같다는 느낌을 받았는데 아마도 이번 개편과 관련된 것으로 보인다. 물론 문제도 처음 시험볼 때 봤던 문제들이 많이 출제되었지만 못 풀어서 기억에 남았던 문제중 하나는 사라졌고, 처음보는 문제들도 추가되는 등 조금 달라졌다. 무엇보다 무료로 풀린게 속이 쓰렸다.

그리고 결과는 92% 합격이었다. GAIQ 인증서 시험을 보다보니 영어로 공부한 내용을 한글로 시험을 보려니 용어 등에서 어려움이 있었다. 강의자료들이 영어로 되어 있으니 되도록 그냥 영어로 시험을 보는 것을 추천한다.

이제 기본준비는 다 되었다. 하지만 이제야 대략 틀을 잡은 것 뿐이고 공부할 것이 무척 많다는 것도 알게 되었다. 웹분석은 전문분야는 아니어서 한계는 있겠지만 조금 더 관심을 가지고 알아보려고 한다.

Dockerfile – ADD 를 통해 build 캐시막기

Dockerfile 을 수정하고 다시 빌드할 때 cache 덕분에 빠르게 재실행이 가능하다.

Dockerfile 의 명령라인이 변경되지 않으면 자동으로 캐시가 작동하게 되는데 가끔 이 기능이 불편할 때가 있다.

Node 개발용 서버를 구축하는 중에 이런 경우를 만났다.

git pull 을 하고, 의존성 해결을 위해 npm install 을 하는 플로우인데, RUN git pull 행이 변경되지 않으니 계속 캐시가 작동했다.

캐시를 작동하지 않게 하는 명령을 추가하는 것에 대해 이 곳에서 계속 논의가 진행중인데, 이 이슈를 살펴보다 랜덤스트링을 추가하는 괜찮은 방법을 알게되었다.

ADD http://www.random.org/strings/?num=10&len=8&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new /var/tmp/uuid

이 명령을 더이상 캐시가 필요하지 않는 곳에 추가해주면 된다. 이렇게 추가해주면 build 할 때마다 랜덤스트링을 다운받고 컨테이너의 파일이 변경되기 때문에 이후의 명령들은 캐시가 동작하지 않게된다.

어느 스타트업의 백오피스 인증 구현기

스타트업에는 놓치지 않아야 할 여러 가지가 있다. 난 그 중 백오피스를 꽤 높은 순위에 둔다.

백오피스를 가졌을 때의 장점은

  1. 서비스를 만들고 지표의 변화를 감지해 서비스를 개선하는 데 큰 도움이 된다.
  2. 개발자전용 인터페이스(REST API 도구라든지 <form> 만 있는 HTML 페이지 등)를 사용하는 것보다 모두의 도구를 만드는 것이 가장 시간이 부족할 때 큰 도움이 된다.

지표에 대해 조금 더 이야기하면 IT 기업에서 지표를 측정하려면 개발자의 도움이 꼭 필요하다. Google Analytics와 같은 도구의 코드를 삽입하거나 데이터베이스 내의 수치 등의 많은 지표가 개발자의 손을 통해 측정되고 알 수 있게 되기 때문이다. 백오피스가 없는 경우 데이터에 접근성이 떨어지고 알고 싶은 리포트를 수동으로 작성할 수밖에 없다. 가뜩이나 인원도 시간도 모자란 스타트업에게 보고서 작성하는 시간을 할애하는 것과 같다고 생각한다.

현재 근무하고 있는 회사는 KStyleTrip.com이고 첫 서비스로 Luck2share 를 만들었다. 새로 입주한 사무실을 꾸미면서 위시리스트를 작성하려고 했는데 공수도 많이 들지 않을 테니 서비스로 만들어보자. 그리고 dogfooding 해보자는 개념으로 시작한 서비스다. KStyleTrip 의 위시리스트 바로 가기

아직 kstyletrip.com 은 제작 중이기 때문에 백오피스의 플랫폼을 만드는 작업은 주로 이 Luck2share 를 대상으로 했다. 그리고 회사의 서비스와 관리자에게 필요한 기능은 앞으로 계속 늘어날 것이기 때문에 서비스마다 각기 다른 백오피스를 갖는 것이 아니라 모든 서비스가 통합된 백오피스를 제작하는 것으로 방향을 잡았다. 이 방법이 각 서비스가 방치되지 않고 잘 관리되는 방법이라는 것에는 이견의 여지가 없으리라고 생각한다.

DB 쿼리 vs. REST API

여기까지 생각이 미치고 구현에 앞서 고민했던 점은 Luck2share 의 데이터를 가져오는 방법이었다. 검토했던 방법은 DB 포트를 열고 백오피스 서버에서 접근해 관리자 전용 API를 구현하는 것과 Luck2share 서버에 관리자용 API를 만들어 사용하는 것이었다.

Luck2share 의 DB 포트는 외부에 공개되지 않고 서버 안쪽에서만 사용하고 있다. 따라서 상대적으로 안전하게 보관되고 있는데 이 포트를 열어 보안이슈를 만들고 싶지 않았다. 그리고 이미 Luck2share 내에 DB쿼리하는 코드베이스가 충분한데 비슷한 코드를 다시 만들어야 하는 것에도 거부감이 있었다.

따라서 API는 Luck2share 서버에 두고 데이터를 가져오는 것으로 방향을 잡았다.

Private API 구축 – 비밀번호 공유 vs. 비대칭 키암호화

두 번째 고민은 Private API를 구축하는 부분이었다. 관리자를 위한 API라면 서버 간, 또는 서버와 클라이언트 간 HTTP 통신을 구축하는데 인증수단이 반드시 있어야 한다. 따라서 HTTP의 Authorization헤더를 통해 인증하는 방법을 사용했다.

우리는 구글 앱스를 사용하고 있기 때문에 회원을 관리할 필요는 없다. OAuth 로그인을 정상적으로 마친 후 OAuth 로부터 얻어온 회원정보에서 몇 가지를 추려 다시 토큰을 만들었다.

이 토큰을 Luck2share 서버에서 검사하도록 해야 했는데 secret을 공유해 암호화/복호화하는 방식은 깔끔하지 않을 뿐 아니라 유출되었을 때 다른 서비스도 동시에 유출되기 때문에 안전하지 않다. 따라서 비밀 키/공개 키를 통한 암호화 방식을 선택했다.

아래와 같은 절차로 Private API에 접근할 수 있다.

  1. 우선 비밀 키와 공개 키를 생성한다. 이 키 쌍의 비밀 키는 백오피스 서버에, 공개 키는 Luck2share(다른 서비스들의 서버)에 둔다
  2. 사용자가 로그인할 때 사용자의 필수정보와 토큰 생성시간과 관련한 데이터를 묶는다. 시간을 묶으면 생성할 때마다 토큰이 확연히 달라지기 때문에 유출의 위험이 적다.
  3. 2에서 만들어진 데이터를 백오피스 서버의 비밀 키로 암호화해 토큰으로 만든다.
  4. 통신이 필요할 때 토큰을 Luck2share 에 전달한다.
  5. Luck2share 에서는 미리 받아놓은 공개 키로 토큰을 복호화한다.
  6. 복호화가 정상적으로 이루어지고 조건에 맞으면 API 호출결과를 돌려주고 그렇지 않으면 401 Unauthorized를 내보낸다.

백오피스 API 서버에서 사용한 프레임워크는 Restify 로, Node 의 jwt 모듈과 express-jwt 미들웨어를 사용해 큰 어려움 없이 Private API를 구축할 수 있었다.

(사실 키 암호화에 대해 깊은 조예가 있어서 떠올린 것이 아니라, jwt 모듈의 기능을 살펴보다 알게 되었다. :-P)

OAuth Login 과 만료시간

앞서 밝혔듯 KStyletrip.com은 Google Apps for Business를 사용하고 있다. 따라서 구글에서 제공하는 OAuth 인증을 사용하면 되므로 회원가입, 회원정보 수정과 같은 것을 구현할 필요가 없었다. 단지 OAuth Consumer로서 회원정보를 활용하는 방법을 구현하면 되었다. 다만 Google에 로그인할 때 제공하는 Access Token의 만료시간은 1시간으로 굉장히 짧아서 API 호출 때마다 이 정보에 의존할 수는 없었다.

따라서 별도의 토큰을 만들어 유지하기로 했다. 이 토큰은 위에 설명한 Private API에 접근하는 토큰과 같은 것이다. 이 토큰을 만들고 사용하는데 만료기간이 너무 짧으면 불편할 것이고 너무 길면 퇴사하거나 변동이 생긴 직원에 대해 대처하기 어려워질 것으로 판단했다.

그래서 아래와 같은 방법으로 구현했다.

OAuth 인증 시에 오프라인 접근권한을 받을 수 있도록 했다. 오프라인 접근권한을 받으면 Refresh Token을 얻어올 수 있다. 이렇게 받아온 Refresh Token으로 백오피스 API 서버가 주기적으로 Google의 OAuth 서버에서 Access Token을 받아오도록 했다. 이렇게 하면 자동으로 사용자의 유효성을 측정할 수 있게 되어 퇴사한 직원에 대해 걱정하지 않아도 된다.

그리고 유효성이 확인된 토큰들을 메모리에 (사실은 API 서버의 변수에) 넣어두고 최초 로그인시 발급된 토큰을 갱신할 수 있는 API 를 만들었다. 변수에 저장된 토큰들은 서버를 새로 시작하면 날아가 버리기 때문에 다른 방법으로 보완할 예정이다. 2014. 8. 3 추가: nedb (Node Embeded DataBase) 를 사용했다.

프론트엔드에서는 주기적으로 갱신 API를 호출해 토큰을 갱신하는 동시에 자체토큰을 가진 사람이 Google에서도 유효하게 판단하는지를 확인했다.

후기

일주일 남짓한 시간에 우리는 꽤 안정적인 백오피스 플랫폼을 갖게 되었다. 그리고 이제 실제로 비즈니스에 필요한 API를 필요할 때마다 개발하기만 하면 된다.

참고