Architect 기반 Node 앱 개발하기

클라우드 IDE 서비스인 c9.io 의 오픈소스 버전인 cloud9 IDE. Architect를 이용하여 Node앱의 구조를 Plugin 방식으로 개발하는 방법에 대하여 알아보자.

Kim, min tae
ibare story
8 min readMay 12, 2014

--

어플리케이션의 규모가 커지고 단일 프로젝트에 참여하는 협업 개발자의 수가 많아 질 수록 코드의 구조에 따른 생산성은 큰 차이를 보일 수 있다. 규모가 커질수록 단위 모듈들은 많아질 수 밖에 없다. 협업자가 많아지면 모듈과 모듈간의 분리가 잘 되어있고 모듈간의 종속 관계 정리가 잘 되어있을 수록 생산성이 올라가는 것은 당연한 일이다. 그러나 쓸만한 아키텍처를 설계하고 발전시켜나간다는 것은 결코 쉬운일이 아니다. 잘못 설계된 아키텍처인 경우 너무 복잡하여 오히려 생산성을 떨어뜨릴 수 있고, 유연성이 부족하여 미래에 문제를 발생시킬 수 있는 위험을 내재할 수 있는 것이다.

Node.js로 만들어진 어플리케이션의 경우 유연성이 매우 뛰어난 Javascript라는 언어적 특성에 기인하여 다양한 아키텍처를 만들어 낼 수 있다. 그 중 대표적인 클라우드 IDE인 c9.io의 plugin 아키텍처를 셈플과 함께 살펴보고, 간단하지만 확장성 높은 구조의 어플리케이션 개발 방법에 대하여 알아보자.

Architect

architect 는 오픈소스인 cloud9 ide 의 플러그인 아키텍처를 구현하기 위한 기반 모듈이다. 여느 node 모듈과 같이 npm 을 통하여 배포되며 만들고자 하는 앱을 plugin 구조로 구성하기 위하여 다음과 같이 간단한 규약을 가지고 있다.

단위 plugin

각각의 plugin 은 플러그인 정보와 함께 플러그인 소스 파일이 포함된 디렉토리에 존재해야한다. 플러그인의 이름, 버전정보, 종속성 등의 정보는 해당 플로그인 디렉토리내 package.json 으로 존재해야하며 주된 내용은 다음과 같다.

*(주의) npm 의 package.json 과 다른 버전이다. 이름이 같지만 다른 것이라는 것에 주의하자.

plugin package.json

name은 플러그인의 이름이다. main 은 플러그인 본체 소스 파일명이며, plugin은 플러그인 실행시 전달될 옵션과 종속성 (Consumes, Providers) 정보를 포함하고 있다.

main에 지정된 플러그인 본체는 반드시 setup 함수를 구현하고 exports 로 노출해야한다. setup 함수는 세개의 파라메터가 전달되며 각각 options, imports, register 이다.

options 은 package.json 의 plugin 에 기술한 필드가 전달된다. 아래 코드에서와 같이 package.json 의 plugin 에 path 를 기술했다면 해당 플러그인에선 options.path 와 같이 접근할 수 있다.

plugin 코드 본체 예시

두번째 파라메터인 imports 에는 package.json 의 plugin 기술 내용 중 consumes 로 정의한 모듈을 imports로 접근할 수 있다. consumes 는 이름에서도 알 수 있듯 arthitect 규약으로 생성한 플러그인 이어야 하며 A 플러그인에서 B 플러그인을 사용할 수 있도록 해주는 방법을 제공한다. A 플러그인이 B 플러그인에서 사용되게 하려면 A는 스스로를 제공(provides) 해야하며, B 플러그인에선 A를 소비(consumes) 한다고 등록해야 한다.

다른 플러그인에게 기능을 제공하기 위해서 package.json 의 plugin 에 provides 로 해당 플러그인을 명시한다고 다 되는건 아니다. 실제 제공될 모듈 명과 기능(함수)를 구현해야하는데 이는 setup 의 마지막 파라메터인 register 를 통해서 할 수 있다. register의 두번째 파라메터로 제공될 모듈과 함수를 구현하여 반환하면 cunsumes 한 플러그인 모듈에서 제공된 기능을 사용할 수 있게된다.

config.js

config.js 예시

위 예제 config.js 는 architect의 데모 셈플 코드 중 하나인 Calculator의 config.js 내용이다. node 의 표준 모듈 이며 실행될 플러그인의 목록과 플러그인 실행시 전달될 options 이 기술된다. 프로젝트에 포함된 플러그인이라면 해당 경로를 문자열로 지정한다. 다운로드되어 node_modules 에 존재하는 플러그인이라면 패키지 경로와 전달할 옵션등을 기술하면 된다. 플러그인인 config.js 에 기술된 순서와 동일하게 실행되므로 실행 순서의 의존성이 있는 플러그인이라면 순서에 주의를 기울여야한다.

plugin 로딩

architect.loadConfig 에 config.js 파일을 지정하여 플러그인 카탈로그를 생성하고 architect.createApp에 생성된 카탈로그를 전달하여 플러그인을 실행한다. 예제 코드에서와 같이 architect는 플러그인의 묶음을 App 이라 정의하고 있는 것을 알 수 있다.

Architect Express Sample App

architect 기반의 플러그인 구조로 작동되는 간단한 셈플앱을 한번 살펴보자. 이 셈플 앱의 코드는 github 저장소에서 다운로드할 수 있다.

https://github.com/ibare/architect-express-sample

셈플앱의 동작은 지극히 단순하다. express 4.0 으로 작성된 server 플러그인은 실행 즉시 3000번 TCP 포트를 오픈하고 클라이언트 요청을 대기한다. /users 요청을 처리할 users 플러그인과 /users/:id/photos 의 업로드 요청을 처리할 photos 플러그인으로 구성되어있다. 마지막으로 플러그인 실행을 처리할 index.js 가 존재한다. 코드를 보며 하나씩 살펴보자.

최초 실행될 index.js 이다. 위에서 설명한 셈플 코드와 다른 내용 없이 단순하게 구성되어있다.

config.js 이다. 이 셈플 앱은 외부에서 개발된 architect 플러그인을 사용하지 않기 때문에 모두 로컬 플러그인만 기술되어 있다. 4개의 플러그인으로 구성되어있다는 것을 알 수 있다.

server.js 와 server.js의 package.json 파일을 보자. 플러그인 코드는 전형적인 express 어플리케이션인걸 알 수 있다. 한가지 다른점이 있다면 생성된 express 앱의 app.route가 register를 통하여 server.route로 외부에 노출하고 있을 뿐이다. server 는 package.json 에서 명명한 provides 의 이름이며 다른 플러그인에서 consumes하여 사용될 수 있게된다

주된 로직이 포함되어있는 users 플러그인을 보자. plugin 에 path 와 consumes 를 확인할 수 있고, user.js 를 보면 각각 options 과 imports 를 통하여 접근하는 것을 알 수 있다. expressjs 로 앱을 개발해본 개발자라면 이 코드가 express 의 라우팅 처리를 코드와 config로(package.json) 자연스럽게 분리하여 처리하는 구조라는 것을 알 수 있을 것이다. 당영히 어떤 방식으로 plugin 구조를 만들어가느냐는 각각의 스타일이고 수 많은 방식이 존재할 것이며 여기서 중요한 것은 그 각각의 방식을 architect를 이용하면 보다 쉽고 명확하게 만들수 있다는 것이다.

왼쪽의 디렉토리 목록을 보면 users 플로그인 디렉토리 하위에 photos 디렉토리가 있는 것을 알 수 있다. photos 는 독립된 plugin 이며 이 셈플앱의 클라이언트 요청 구조인 /users/:id/photos 와 동일하게 구성하고 있다.

마지막으로 photos 플러그인이다. 실제로 users 플로그인과 거의 동일한 구주임을 알 수 있다. 셈플 앱이라 실제론 별로 하는일이 없다.

실행

셈플 앱을 실제로 실행해보자. 다음과 같은 화면을 볼 수 있다.

로그를 살표보면 플러그인이 config.js 에 나열된 순서대로 실행된다는 것을 확인할 수 있다. curl 로 요청을 보내 보면 당연하게도 잘 동작한다는 것도 알 수 있다.

--

--