개발팀장이 되면서 겪게된 점들 1

이미지
                                                         <팀원을 모집하기 위해 고군분투하는 모습이다. > 첫 한달  개발팀장을 맡다 2021년 5월 , 기존에 있던 CTO분이 휴직(개인사)을 하게 되면서    개발에 대한 모든 권한을 내게 일임하였다.   개발에 대한 모든 의사결정을 전부 내게 맡긴 것으로 ,   어느 정도 규모가 있는 회사의 의사결정권한을 갖게 된 것은 그만큼 내게 큰 신뢰가 있었음을   알수 있게해주는 대목이었다. 그러나 전혀 예측하지 않았던 상황이기에 준비가 되어있지 않았던만큼 처음에는 삐걱거렸다. 가장 첫번째로 어려움을 겪었던 것은 업무의 배분이었다.   관리자가 되니까 해야할일은 업무를 만들고 또 그것을 팀원들에게 분배하고 잘 되고있는지 취합하고 관리감독을 하는것이었다.   군 시절 장교로 복무하면서 겪어봤던 일이긴 했지만, 군복무 당시에도 그닥 잘 하지는 않았던 것 같다.   그럼에도 어쨌든 전반적인 시스템을 이해하고 있었고, 어떻게 구현해야할지에 대해서는 어느정도 경험이 쌓여있었기때문에 큰 문제가 없을 줄 알았다.   실무자로 일을 할 때에도 항상 업무를 받아서 하지는 않았다. 스스로 돌이켜보건대, 나는 주어진 업무가 없으면 스스로 만들어서 제안하고 기획하여 업무를 진행했다.  조그마한 스타트업이었던 첫 회사에서부터  내가 할일은 내가 만들어서 곧 잘했다. 어떤 큰 방향만 정해져있다면 그건 큰 어려움은 아니었다. 나에게 일은 항상 있었다.   매니저가되면서 달라진게있다면 내가 할일만 만드는 것은 아니라는 점이다 . 남이 할 일도 만들어줘야했다.  다행히 팀원들에 대한 면담을 실시한 결과,(팀원을 맡게되자마자 했던 부분)   마이크로 매니징을 원하지는 않았기때문에 큰 그림을 그리는 정도만 준비하면 됐었다.   문제는 내 실무를 동시에 진행하면서 팀원들의 업무 방향도 설정해야했기때문에 시간이 배로 들게 되었다는 점이다. 물론 두배로 일하지는 않았다. 대신에 내 실무시간을 줄였고

Typescript를 이용한 Express. Inversify js 를 이용한 IOC를 구현해보기 -




블로그 이전했습니다~

링크(
https://steemit.com/@cicada0014



요즘 한창 타입스크립트를 이용해서 express 서버를 구축하고 있다.

(막간을 이용해서 홍보 / 천기new설 포스텔러)

코드리뷰를 받으면서 많이 부족함을 느꼈다.

나는 용어를 명확하 이해하지 않고 개발을 하고 있었는데, 용어 설정에 신중함을 기해야 겠다.

코드를 살펴보니 전체적으로 의존성 주입이 애매했다. 코드를 짜면서도 매번 매핑시켜주는 것이

귀찮아 지기 시작했는데, 시간없음을 핑계로 해당 라이브러리를 제대로 파악하지 않았다.

검색을 해보니 inversify.js 라는 훌륭한 라이브러리가 있었다. (타입스크립트도 지원되니 딱 알맞았다)

하지만 한국어로 된 포스팅은 없었다. 우리나라에서는 JAVA/Spring이 강세라서 그런건가

node express를 사용하시는 다른분들은 IOC를 어떻게 구현하실까

Vue js를 사용하시는 분이 inversify에 대한 포스팅을 해준 것이 구글 한글검색에서는 전부였다. 

한글로된 2번째 inversify 관련 포스팅이라 생각하면서 작성해본다.

Spring을 써봤던 기억을 더듬고, Angular에서 의존주입하는 방식을 접목해서 구축해보았다. express

typescript가 널리 번창하기를 바라는 사용자로써 일조를 하고자한다.


해당 깃 리포지토리는 이 url로 클론하실 수 있습니다.
https://github.com/cicada0014/jwt-practice.git


inversify 홈페이지 가이드를 살펴본다.
npm install inversify reflect-metadata --save
inversify 말고 reflect-metadata 라는 것도 설치해야 함을 알 수 있다

이 포스트에서 다루고자 하는 내용을 벗어나므로 간단하게 설명하고 넘어간다.
컨테이너에 컴포넌트들을 등록하고 자동으로 주입을 하기 위해서는 컴포넌트의 내부를 들여다 보아야한
다.

Reflect라는 말의 의미는 한국어로는 비춰본다와 상통한다. 즉, 컴포넌트를 살펴보며 자동주입을 하기 위한 라이브러리이다

inversify는 typescript 2.0 이상을 지원한다. (@XXX 와 같은) decorator를 쓰기 위해서는

tsconfig.json을 손봐야한다.

{
    "compilerOptions": {
        "target": "es5",
        "lib": ["es6", "dom"],
        "types": ["reflect-metadata"],
        "module": "commonjs",
        "moduleResolution": "node",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
    }
}

위처럼 설정해주지 않으면 inversify를 사용할 수가 없다.
이제부터 express와 연동하는 간단한 예제를 만들어본다.
물론 express와 typescript가 설치되어 있어야 한다. 모르는 분은 이 부분을 참조

필자는 적당한 디렉토리로 가서 다음과 같이 명령어를 실행했다.

mkdir inversify-prac && cd inversify-prac && npm init - y && npm i inversify inversify-express-utils express reflect-metadata @types/node @types/express  --save && tsc -init


이제 디렉토리에 node_modules와 package.json, tsconfig.json이 생성되어 있을 것이다.
tsconfig.json은 위에서 소개한대로 설정을 바꾸면 된다.

app.ts 파일을 만들고 다음과 같이 입력한다

주의할점이 하나 있다. reflect-metadata는 다른 것들보다 우선해서 import 되어야 한다 이 polyfill은 싱글턴으로 생성되는데 , 이 처럼 최상위 파일에 한번만 넣어주면 된다.
최종적으로 만들어지는 것은 express.Application 타입이다.

생성자 메소드를 보자

먼저 IOC 컨테이너를 생성한다. 그 컨테이너를 INversifyExpressServer에 파라미터로 넘겨주어 서버를 생성하고, 서버를 빌드시켜주면 express 서버가 만들어진다.

예시 컴포넌트를 2개 생성해본다.
웹어플리케이션이므로 컨트롤러아 모델을 하나씩 생성한다.



model.ts

@injectable 데코레이터를 클래스위에 명시한다. 이 데코레이터를 통해 컨테이너로 자동으로 등록이 된다. model은 hello 스트링값을 가진 value 프로퍼티를 지니고 있다.



container.ts

컨트롤러 역시 @injectable을 통해 컨테이거가 인식할수 있도록 해야한다.
@Controller 데코레이터는 이 ㅋ클래스가 컨트롤러이며, 경로값을 매핑할 수 있도록 해준다.
생성자 부분을 보면 @inject 데코레이터가 쓰이고있다. ㅇ이는 컨테이너에게 다음에 해당하는 식별자를 가진 컴포넌트를 주입해달라고 명령하는 부분이다. 모델이 자동주입되기때문에 model에 따로 값을 선언하지 않아도 사용이된다. @inject(Model.name) 부분에서 name에 대한 값은 Model 클래스의 이름값이다. 클래스이름 값이 유일무이 하기때문에 name값을 사용햇는데 name이 중첩된다면 다른 변수를 사용할 수도 있다.

inversify 가이드에서는 Symbol을 통해 유일값을 넣어주고 잇는데, 필자는 이 부분이 매우 귀찮은 부분이라 판단했다.

Model의 타입은 다음과 같다 new(...args)=>{} 생성자 리터럴이 그 타입이다.
이 생성자 함수에 자동으로 들어가 있는 name 값을 사용한 것인데 클래스이름과 동일하다.

생각을해보면 클래스의 이름은 유일한 값으로 등록하기 마련이다. 이미 유일한 식별자 값으로서 작동하고 있는 클래스의 이름을 사용하는 것이 유리하지 않을까? 물론 클래스에 name이라는 프로퍼티가 오버라이딩 될경우 의도했던 바가 나오지 않을 가능성이 있다. 이점은 개발자가 명확히 인지를 하고 있다면 문제될것이 없다고 판단하는데 초짜의 생각이므로.... 뭔가 단점이 있을 것 같다.

데코레이터를 달아 놓기만 해서는 컨테이너가 인식할수가 없다.
(스프링에서는 자동으로 주입되었던 것으로 기억한다)

this.container.bind(TYPE.Controller).to(ExempleController).whenTargetNamed(ExempleController.name)


this.container.bind<Model>(Model.name).to(Model).whenInjectedInto(ExampleController)

app.ts의 일부이다. 이렇게 bind 메소드를 써서 명시를 해줘야 한다.

bind 메소드에 들어가는 식별자 값은 @inject에서 사용되는 식별자 값과 일치해야한다.
컨트롤러의 경우 inversify-express-utils의 타입에서 식별자 값을 가져온다.

식별자값은 중복이 가능하다. 대신이 중복되더라도 원하는 값을 가져오기 위해서 to 메소드 다음에 when XXX 메소드를 덧붙여야 한다.

tsc && node ./app.js

위 명령어를 실행하면 서버가 작동된다. 
이제 http://localhost:3000/hello/world에 들어가면 hello world! 가 나타나는 것을 볼 수 있다. 
우리의 예측대로 자동주입이 잘 되었음을 의미한다.

Angular 처럼 사용하고자 하는 것들을 최상위 컨테이너에 등록을 해두고 해당 클래스에서 주입받고자하는 컴포넌트들만 기록을 하는 방법을 구현해보고자 했다.


예를들어 컨트롤러가 model1 뿐만 아니라 model2, model3 도 필요하다고 해보자.

개발자가 해주는 것은 model2, 3에 @injectable() 데코레이터를 붙여주고 컨테이너에 등록시켜준다.

컨트롤러에 model2 model3 를 inject 하고 싶다고 명시하기만 하면 된다.

어떤식으로 어떻게 들어오는지 컨트롤러는 알지 못한다. 컨테이너에서 설정해주는 것이다.
이 패턴을 이용하지 않았다면 개발자는 하나하나 매핑을 직접해주어야 했을 것이다.
컨트롤러 내부에 컨테이너를 생성해서 그 값을 직접 매핑시켜주거나 컨테이너에서 컨트롤러를 불러다가 생성시기에 매개변수로 넘겨주거나 하는 방식으로 말이다.

inversify 문서를 읽어보면 다양한 상황에서 매핑방식을 설정해줄수가 있다. 어떤 이름일때, 어떤 태그를 지니고 있을때, 어디에 주입되었을때만 바인딩이 되도록 설정할 수가 있다.




댓글

  1. inversify의 문제는 버그가 너무많다는점.. 그리고 그문제가 해결이 안되고있다는점이네요.
    현재로선 view엔진이 사용이 불가능하며,
    next로 error 객체가 안넘아가는 버그가 버젓히 존재하는데 2년째 안고치고있네요..

    답글삭제

댓글 쓰기

이 블로그의 인기 게시물

iframe 보안 문제 우회 및 해결법 1

iframe 보안 문제 우회 및 해결법 2

개발팀장이 되면서 겪게된 점들 1