Contents

Dependency Injection (feat:Nest)

๊ฐœ์š”

Nest.js Framework(Spring, Angular ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ž‘์—…์„ ํ•˜๋‹ค๋ณด๋ฉด, Dependency Injection, Inversion of Controll ๊ฐ™์€ ๋‹จ์–ด๋“ค์ด ์ž์ฃผ๋ณด์ธ๋‹ค. ํ•„์ž๋Š” ์ด ๋‹จ์–ด๋“ค์ด ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š”์ง€ ๋ชจ๋ฅด๊ณ  ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋‹ˆ ๊ณ„์† ๊ตฌ๋ ํ……์ด์— ๋น ์ง€๋Š” ๊ธฐ๋ถ„์ด๋ผ ์ด์— ๋Œ€ํ•ด ๋งŽ์€ ํฌ์ŠคํŠธ/ ๋น„๋””์˜ค๋ฅผ ๋ณด๊ณ  ์ •๋ฆฌํ•˜์˜€๋‹ค.

ํฌ์ŠคํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. Nest.js์—์„œ DI๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€๋ฅผ Nest.js ๋ฉ”์ธํ…Œ์ด๋„ˆ์˜ ์„ค๋ช…์„ ํ† ๋Œ€๋กœ ์ž‘์„ฑํ•˜์˜€๋‹ค. ๊ทธ๋ฆฌ๊ณ  DI๊ฐ€ ๊ฐœ๋…์ ์œผ๋กœ ๋ฌด์—‡์ธ์ง€, ์™œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š”์ง€์— ๋Œ€ํ•ด ํฌ์ŠคํŠธํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

Nest.js ์—์„œ DI๋ž€?

Nest๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž์ฃผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

1
2
3
4
5
6
7
@Injectable()
class CatService{
    constructor(
        private readonly httpService : HttpService,
        private readonly logger : Logger,
    ){}
}

์—ฌ๊ธฐ์„œ @Injectable() ์ด๋ž€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์ฃผ๋ชฉํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” typescript compiler์— ์˜ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ metadata๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

1
2
3
4
5
CatsService = __decorate(
    [__metadata("design:paramtypes",[HttpService, Logger])],
    CatsService
)
// metadata  = [HttpService, Logger]

์—ฌ๊ธฐ์„œ "design:paramtypes" ๋Š” typescript metadata key์ด๊ณ , ์ด๋ฅผ ์ด์šฉํ•ด CatsService๊ฐ€ ์ฐธ์กฐํ•˜๋Š” class ๋ฐฐ์—ด์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ metadata๋Š” Metadata Reflection API๋ฅผ ์ด์šฉํ•ด ๋‹ค์Œ์˜ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜์—ฌ

1
Reflect.getMetadata("design:paramtypes",CatsService)

ํ˜„์žฌ CatsService๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ์˜์กด์„ฑ์ด ์–ด๋–ค ํƒ€์ž…์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๋‹ค์Œ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด `INJECTOR` ๋Š” ํ•ด๋‹น ํƒ€์ž…์— ํ•ด๋‹นํ•˜๋Š” Instance๋ฅผ `DI Controller`์—๊ฒŒ ์š”์ฒญํ•˜๊ณ  `DI Controller`๋Š” ํ•ด๋‹น ํƒ€์ž…์— ๋งž๋Š” ์ ์ ˆํ•œ intance๋ฅผ `INJECTOR`์—๊ฒŒ ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค. `INJECTOR`๋Š” ํ•ด๋‹น ๊ฐ’์„ ์‚ฌ์šฉํ•ด์„œ ์ƒˆ๋กœ์šด provider๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•จ์œผ๋กœ์จ DI๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
Tip
์‹ค์ œ๋กœ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” Circular Dependency, Synchronous Process ๋“ฑ๊ณผ ๊ฐ™์€ ๋ณต์žกํ•œ ๊ฒƒ๋“ค๋„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ์ด ๊ธ€์˜ ๋‚ด์šฉ์—์„œ ๋ฒ—์–ด๋‚˜๋Š” ๋‚ด์šฉ์ด๋ฏ€๋กœ ๋‹ค๋ฅธ ํฌ์ŠคํŠธ์— ์˜ฌ๋ฆฌ๋„๋ก ํ•˜๊ฒ ๋‹ค.


Injector in Nestjs

Nest.js์—์„œ๋Š” module ๋ ˆ๋ฒจ์˜ Injector๋งŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ , Nest.js์—์„œ๋Š” ๋ชจ๋“ˆ์˜ ๊ตฌ์กฐ๋ฅผ ๋ชจ๋“ˆ์„ ์ •์ ์œผ๋กœ ํ•˜๋Š” ๊ทธ๋ž˜ํ”„๋กœ ํ‘œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ๋ชจ๋“ˆ์€ Injector๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
Nest.js์—์„œ ๊ฐ ๋ชจ๋“ˆ์ด singleton ์ฒ˜๋Ÿผ ๋ณด์ด๊ธฐ๋Š” ํ•˜์ง€๋งŒ, ์‚ฌ์‹ค์€ Dynamic module ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ผญ ๊ทธ๋ ‡์ง€๋Š” ์•Š๋Š”๋‹ค. ๋ชจ๋“ˆ์ด ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ณ  ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” exports/ imports / declarations ์„ ํ†ตํ•ด ๋™์ ์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์ด์œ ๋Š” ๋ชจ๋“ˆ์˜ isolation์„ ์œ„ํ•จ์ด๋‹ค.

A module์—์„œ B module์˜ B service๋ฅผ ์ด์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, A module์— B moudle์„ importํ•˜๊ณ , B Service๋ฅผ B module์—์„œ exports ์‹œ์ผœ์•ผ ํ•œ๋‹ค. ๋งŒ์•ฝ B service๋ฅผ exports ํ•˜์ง€ ์•Š์œผ๋ฉด, ์บก์Šํ™”๋˜์–ด ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ์ด ์ ์ด Nest.js ์˜ DI์—์„œ ์ค‘์š”ํ•œ ์ ์ด๋‹ค.

Nest๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

  1. ํ˜„์žฌ module ๋‚ด์—์„œ provider๋ฅผ ์ฐพ๋Š”๋‹ค.
  2. import๋œ module์„ ํ™•์ธํ•œ๋‹ค.
  3. ๋งŒ์•ฝ ๋ชจ๋“ˆ์ด exports ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ•ด๋‹น provider๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

์ด๋ ‡๊ฒŒ Nest.JS๋Š” ๊ฒฉ๋ฆฌ์ˆ˜์ค€์— ์žˆ์–ด์„œ ์—„๊ฒฉํ•˜๊ฒŒ ์ž‘์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น provider๋ฅผ ์ฐพ์„ ๋•Œ ๊ทธ๋ž˜ํ”„ ์ƒ์—์„œ ํ˜„์žฌ ENQUIRER์— ๊ฐ€๊นŒ์šด provider๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

Global Scope

๋งŒ์•ฝ core module์„ @Global() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ „์—ญ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด, ๋‹ค๋ฅธ module์—์„œ ๊ฐ€์ƒ์˜ ๊ฐ„์„ ์„ ํ•ด๋‹น ๋ชจ๋“ˆ์— ์—ฐ๊ฒฐํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด, core module์„ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•  ๋•Œ, ๋ช…์‹œ์ ์œผ๋กœ imports ํ•˜์ง€ ์•Š๊ณ  ํ•ด๋‹น ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

DI๋ž€?

์ƒ์œ„ ๋ชจ๋“ˆ์€ ํ•˜์œ„ ๋ชจ๋“ˆ์— ์˜์กดํ•ด์„  ์•ˆ๋œ๋‹ค.
์ถ”์ƒํ™”๋œ ๊ฒƒ์€ ๊ตฌ์ฒดํ™”๋œ ๊ฒƒ์„ ์˜์กดํ•˜๋ฉด ์•ˆ๋œ๋‹ค, ๊ตฌ์ฒดํ™”๋œ ๊ฒƒ์€ ์ถ”์ƒํ™”๋œ ๊ฒƒ์„ ์˜์กดํ•œ๋‹ค.

์™œ DI๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜๊ณ  ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€?

button class๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. button class๋Š” ๋ˆ„๋ฅธ๋‹ค ๋ผ๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋ˆ„๋ฅด๋Š” ํ–‰์œ„๋กœ on/off ๋˜๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž. Lamp / Carkey ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ์ด ๋•Œ button์„ ๋ˆŒ๋ €์„ ๋•Œ lamp๋Š” ๋ถˆ์ด ์ผœ์ง€๋‹ค / ๋ถˆ์ด ๊บผ์ง€๋‹ค์˜ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๊ณ , Carkey๋Š” ๋ฌธ์„ ์—ด๋‹ค/ ๋ฌธ์„ ๋‹ซ๋Š”๋‹ค์˜ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.
๊ทผ๋ฐ button class๊ฐ€ lamp์—๋„ ์˜์กดํ•˜๊ณ , Carkey์—๋„ ์˜์กดํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด, lamp, carkey ๊ฐ์ฒด๋ฅผ button์— ์ƒ์„ฑํ•ด์•ผํ•˜๊ณ , ๊ฐ๊ฐ์˜ ๊ธฐ๋Šฅ๋„ ๋”ฐ๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด button class๋Š” ์žฌ์‚ฌ์šฉํ•จ์˜ ๊ฐ€์น˜๋ฅผ ์ƒ์‹คํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด, button์„ ์ถ”์ƒํ™” ์‹œ์ผœ์•ผ ํ•œ๋‹ค. ButtonInterface๋ผ๊ณ  ํ•œ๋‹ค๋ฉด, button์€ buttonInterface๋ฅผ ์˜์กดํ•˜๊ณ , lamp, carkey ๋„ buttonInterface๋ฅผ ์˜์กดํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  lamp, carkey ํด๋ž˜์Šค์—์„œ, ButtonInterface์˜ ๋ฉ”์„œ๋“œ์ธ ๋ˆ„๋ฅธ๋‹ค์˜ ๊ธฐ๋Šฅ์„ ๊ฐ๊ฐ ์ •์˜ํ•˜๊ฒŒ ๋˜๋ฉด, Button class๋Š” ์ด์ œ lamp, carkey๋ฅผ ์˜์กดํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋‹ค๋ฅธ ๋ชฉ์ ์œผ๋กœ๋Š”, ํ…Œ์ŠคํŠธ์— ์šฉ์ดํ•˜๋‹จ ์žฅ์ ๋„ ์žˆ๋‹ค. mock ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜, 3rd ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋งˆ๋ฌด๋ฆฌ

๋‚ด ํฌ์ŠคํŠธ์— ํ‹€๋ฆฐ์ ์ด ์žˆ๋‹ค๋ฉด, ํ•„์ž์˜ ๋ถ€์กฑํ•จ ๋•Œ๋ฌธ์ด๋‹ค. ์˜์–ด๋กœ ๋œ ์œ ํŠœ๋ธŒ๋ฅผ ๋ณด๊ณ  30๋ถ„์งœ๋ฆฌ ์˜์ƒ์„ ๋ชจ๋‘ ํ•ด์„ํ•ด์„œ ์ฝ๊ณ , ๋ช‡๋ช‡ ํ•œ๊ตญ์–ด ๋ธ”๋กœ๊ทธ ์ค‘ ๋ฏฟ์„ ๋งŒํ•œ๊ณณ์„ ์ฐธ๊ณ ํ•ด์„œ ์ ์œผ๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ๋‹ค.