Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

Paypal의 KrakenJS

Paypal이 지난 5월 Java에서 Node.js로 갈아탄다고 발표한 이후 지난달 Node.js를 갈아탄 이후의 내용을 공유하면서 Kraken.js를 공개했다.

Kraken.js

Kraken.js를 한마디로 표현하기가 어려운데 express 웹프레임워크의 확장 정도로 보면 적당할 것 같다. 몇 주간 만져보고 나니 내부에 크게 대단한 부분은 없다고 느껴지는데 좀 더 자세히 얘기하면 express 웹 프레임워크를 사용하는데 몇몇 모듈들을 사용해서 사용하기 쉽게 프로젝트 폴더를 구조화하고 인증 모듈 Lusca, i18n 모듈 Makara를 추가한 정도에 불과하다. (물론 Dust.js 렌더러인 Adaro와 개인 NPM 저장소를 사용하기 위한 npm 프록시 Kappa도 있다.)

추가된 모듈들이 있기는 하지만 팀 내에서 express로 프로젝트를 한다고 할 때 누가 프로젝트를 구조화하고 미리 모듈들을 넣어서 세팅해 놓은 다음에 다른 팀원들한테 배포하면서 Oustier.js라고 이름 붙인 것 같은 기분이다. (Node.js가 아니라 어떤 프로젝트를 하더라도 이런 작업은 다들 하지 않나?) 물론 express로 개발하면 프로젝트 구조를 어떻게 가져갈지 고민되므로 참고할 부분이 전혀 없는 것은 아니다.

Kraken은 index.js가 실행파일이고 다음과 같은 폴더구조로 되어 있다. (Kraken이 yo로 스캐폴딩을 제공하지만 이건 그냥 실행하면 되므로 Kraken에 대해서만 살펴보자.)

  • /config : 애플리케이션과 미들웨어에 대한 설정
  • /controllers : 라우팅과 컨트롤러
  • /lib : 개발자가 작성한 라이브러리나 코드
  • /locales : i18n 리소스 번들
  • /models : 모델 객체
  • /public : 정적 리소스
  • /public/templates : 서버/브라우저용 템플릿(Kraken은 Dust.js를 템플릿으로 사용한다.)
  • /tests : 테스트 코드

index.js

실행파일인 index.js파일은 다음과 같이 생겼다.

'use strict';

var kraken = require('kraken-js'),
    app = {};

app.configure = function configure(nconf, next) {
    // Fired when an app configures itself
    next(null);
};

app.requestStart = function requestStart(server) {
    // Fired at the beginning of an incoming request
};

app.requestBeforeRoute = function requestBeforeRoute(server) {
    // Fired before routing occurs
};

app.requestAfterRoute = function requestAfterRoute(server) {
    // Fired after routing occurs
};

kraken.create(app).listen(function (err) {
    if (err) {
        console.error(err);
    }
});

보통의 express 애플리케이션의 실행파일이 많은 설정코드가 들어가는 데 비해서 깔끔한 파일이다. 실제 애플리케이션은 kraken.create(app).listen()부분에서 생성하고 위에서 보듯이 4가지의 훅(hook)을 제공한다.

  • configure는 처음 앱을 실행할 때 설정을 하기 위해서 호출되고 /conf/app.json에 있는 설정 값들이 nconf 파라미터로 넘어오게 되므로 애플리케이션을 시작하기 전에 각 모듈 등의 설정을 여기서 하면 된다.
  • requestStart는 요청이 시작될 때 호출된다.
  • requestBeforeRoute는 라우팅이 일어나기 전에 호출된다.
  • requestAfterRoute는 라우팅이 일어난 후에 호출된다.

테스트를 해보면 최초 애플리케이션 실행 시 configure - requestStart - requestBeforeRoute - requestAfterRoute 순으로 호출되고 여기서 미들웨어를 설정했을 때 요청이 들어올 때마다 requestStartrequestBeforeRoute에서 등록했던 미들웨어가 실행된다. (저 위의 함수 자체가 실행되는 것은 아니다.)

config

/config폴더 안에는 app.jsonmiddleware.json이 있다. app.json에 애플리케이션과 관련된 호스트, 포트, 컨트롤러 폴더, i18n 모듈 등의 설정을 한다. yo로 스캐폴딩을 생성하면 기본 옵션들이 표시되고 주석처리가 되어 있는데 기본값으로 설정되어 있으므로 바꿀 경우에만 주석을 풀어서 수정하면 된다. 여기에 설정하면 Kraken이 자동으로 값을 가져와서 애플리케이션을 설정하고 따로 필요한 설정 값들도 이 파일에 넣으면 위에 configure 훅에서 nconf에 담겨서 넘어오게 된다. middleware.json에는 express가 설정하는 미들웨어들에 대한 설정을 JSON으로 한다. 이 설정에서 app-development.json, middleware-development.json처럼 JSON 설정을 추가하면 개발환경에서는 이 설정을 기반으로 로드된다. 자세한 설정 옵션은 Kraken 문서에 나와 있다.

controllers

controllers 폴더에는 라우팅 설정과 컨트롤러를 작성한다. 일반적인 express에서 app.get('/', function(req, res));와 같이 작성하던 라우팅을 여기다 넣게 되는데 다음과 같이 생겼다.

'use strict';

module.exports = function (server) {

    server.get('/', function (req, res) {
        var model = { name: 'test' };

        res.render('index', model);
    });
};

이 폴더 아래에 원하는 대로 컨트롤러 파일들을 위처럼 작성해서 추가하면 자동으로 모두 추가된다. 일반적인 express 애플리케이션에서는 실행파일에서 라우팅하므로 라우팅 설정과 핸들러가 다른 파일로 떨어지거나 컨트롤러 파일을 따로 둘 경우 매번 require()를 추가해야 해서 귀찮은데 그에 비해서는 훨씬 깔끔하다. 라우팅과 핸들러를 함께 둘 수 있으므로 이해하기나 수정하기 좋고 필요할 때마다 파일만 새로 만들어서 추가하면 자동으로 로딩되므로 편하다. 이 기능은 Paypal이 만든 express-enrouten이 처리해 준다.

lib

여기에 개발자가 작성하는 코드를 넣는데 보통 서비스 로직이 들어갈 것으로 생각된다. 여기에 대한 특별한 가이드는 없지만 필요한 로직을 작성하고 설정이 필요한 경우는 앞의 configure 훅에서 설정을 전달해서 연결하는 식으로 작성하면 될 것 같다.

locales

locales 폴더에는 언어별로 리소스 파일(locales/US/en/index.properties처럼)을 추가하고 뷰 템플릿에서 {@pre type="content" key="index.greeting"/}와 같이 사용하면(Dust.js일 경우에) 해당 언어의 리소스파일에서 index.greeting을 가져와서 보여준다.

models

데이터를 다루는 모델 관련 로직을 여기에 작성한다. 이 부분은 데이터베이스나 라이브러리를 어떤 걸 사용하느냐에 따라 형태가 달라질 것이므로 정해진 가이드는 없어 보인다.

맺음말

앞에서도 말했지만 구조가 잘 잡혀있는 거 외에 특별한 것은 없다. 특히 i18n과 보안이 중요하지 않다면(이 두 모듈을 자세히 살펴보지 않았지만) kraken의 매력은 크게 떨어진다. 몇 주 써보니 불편한 점이 있었는데...(Dust.js가 익숙지 않은 부분은 제외로 하더라도...)

  1. 문서화가 아직 별로다. 이게 불편함의 대부분인데 제공된 가이드나 예제 외의 무언가를 하려면 한참을 테스트해보아야 하고 자료를 찾을 수 있는 곳도 없다. 직접 테스트해보거나 소스 열어서 찾아봐야 한다.
  2. 4개의 훅을 제공하기는 하지만 사실 이게 잘 쓰일지는 모르겠다. 매번 요청이 들어올 때마다 뭔가 동작하는 로직을 그렇게 자주 작성할 일이 있는지 모르겠다. 인증모듈 같은 경우가 대표적인데 보통 그런 처리는 인증모듈이 자체적으로 처리해주니까 마찬가지로 딱히 필요한지 모르겠다. 애플리케이션을 작성하면 항상 시작 전에 세팅해야 하는 부분들이 있으므로 그나마 configure 훅이 유용하다 할 수 있는데 어차피 Node.js는 비동기로 동작하므로 설정단계에서 설정을 다 하려면 설정되기 전에 진행되지 않도록 일일이 작업을 해주어야 하기 때문에 그냥 실행파일에서 설정함수를 호출해주는 거에 비해서 장점이 있는지 모르겠다.
  3. 기본 제공되는 설정 외에 커스터마이징하는 방법을 알 수 없다. 미들웨어나 설정을 일일이 설정하지 않고 JSON으로 설정할 수 있는 점이 매력적으로 보이지만 막상 사용하려면 기본 옵션 외에 많은 것들이 필요한데 어떻게 하는지 나와 있는 곳이 아무 데도 없다. (가능한지도 모르겠다.) 예를 들어 난 Dust.js가 익숙지 않아서 Jade로 바꾸고 싶다면 어디서 변경을 해야 하는지 아니면 Passport를 사용하는 경우 app.use(passport.initialize());처럼 미들웨어 설정을 해야 하는데 이를 JSON으로 가능한지도 모르겠다. 힘들게 찾아본 결과로는 requestBeforeRoute훅에서 이 설정을 하지만 이런 경우 JSON으로 설정한다는 장점은 크게 높지 않다.

이렇다 보니 몇 주간 써보면서 꽤 힘들어서 결국 Kraken을 제거하고 express만 사용하기로 했다. 물론 참고할 부분은 있었으므로 들어내면서 설정 관리하는 nconf와 컨트롤러를 로딩하는 express-enrouten만 가져와서 프로젝트를 다시 설정했다. (i18n과 보안 모듈은 딱히 필요없는 상태였으므로...)

덧) 참고로 express-enrouten은 얼마 전에 0.1.0이 나왔는데 기본 Kraken과는 호환이 안 된다고 한다. (응?)

2013/12/18 23:28 2013/12/18 23:28