λ³Έ 글은 μ œκ°€ NestJS ν”„λ ˆμž„ μ›Œν¬λ₯Ό 톡해 κ°œλ°œν•˜λ©΄μ„œ 깨달은 λ…Έν•˜μš°λ₯Ό κΈ°λ‘ν•œ κ²ƒμž…λ‹ˆλ‹€. μ œκ°€ μ œμ‹œν•œ 방법보닀 더 쒋은 방법이 μžˆμ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 지적은 μ–Έμ œλ‚˜ ν™˜μ˜μž…λ‹ˆλ‹€ :)

7 minute read

λ³Έ 글은 μ œκ°€ NestJS ν”„λ ˆμž„ μ›Œν¬λ₯Ό 톡해 κ°œλ°œν•˜λ©΄μ„œ 깨달은 λ…Έν•˜μš°λ₯Ό κΈ°λ‘ν•œ κ²ƒμž…λ‹ˆλ‹€. μ œκ°€ μ œμ‹œν•œ 방법보닀 더 쒋은 방법이 μžˆμ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. 지적은 μ–Έμ œλ‚˜ ν™˜μ˜μž…λ‹ˆλ‹€ :)


Dependency Injection은 NestJS ν”„λ ˆμž„μ›Œν¬μ—μ„œ λ‹¨κ³¨λ‘œ λ“±μž₯ν•˜λŠ” μš©μ–΄λ‹€.

Dependency Injection(DI)λŠ” μ†Œν”„μ›¨μ–΄ μ„€κ³„μ˜ β€œDesign Pattern” 쀑 ν•˜λ‚˜λ‹€.

DIλŠ” β€˜μ˜μ‘΄μ„±(Dependency)’과 β€˜μ£Όμž…(Injection)’을 ν•¨κ»˜ μ‚¬μš©ν•˜λŠ” 섀계 방법이닀. κ·Έλž˜μ„œ 두 κ°œλ…μ— λŒ€ν•œ 이해가 μ„ ν–‰λ˜μ–΄μ•Ό ν•œλ‹€!

λ³ΈνŽΈμ— λ“€μ–΄κ°€κΈ° 전에 DI에 λŒ€ν•œ κ°„λ‹¨ν•œ 지을 보고 κ°€μž πŸ™‚

Material from here



μ˜μ‘΄μ„±; Dependency

Β  β€œDependency is a relationship between components or classes that can be thought of as a β€˜uses’ relationship.”

Class $A$ uses Class $B$
$\equiv$ Class $A$ is dependent on Class $B$
$\equiv$ Class $B$ is a dependency of Class $A$

μ§κ΄€μ μœΌλ‘œ λ§ν•˜λ©΄ Class $A$κ°€ Class $B$λ₯Ό λ‚΄λΆ€ λ³€μˆ˜λ‘œ 가진닀고 말할 수 μžˆμ„ 것 κ°™λ‹€.

μ΄λ²ˆμ—” μ½”λ“œ λ ˆλ²¨μ—μ„œ μ‚΄νŽ΄λ³΄μž!

public class PetOwner{
  private AnimalType animal;

  public PetOwner() {
    this.animal = new Dog();
  }
}

// code fragment from here

이 μ½”λ“œμ—μ„œ PetOwner κ°μ²΄λŠ” AnimalType의 객체λ₯Ό λ§Œλ“€κΈ° μœ„ν•΄ Dog 객체에 β€œμ˜μ‘΄β€ν•œλ‹€.

μ†Œν”„νŠΈμ›¨μ–΄λ₯Ό λ§Œλ“œλŠ” κ³Όμ •μ—μ„œ β€˜μ˜μ‘΄μ„±β€™μ€ ν”Όν•  수 μ—†λ‹€! (μ˜μ‘΄μ„± μ—†λŠ” μ†Œν”„νŠΈμ›¨μ–΄κ°€ μ–΄λ”” μžˆκ² λŠ”κ°€)

ν•˜μ§€λ§Œ, PetOwner와 Dog μ‚¬μ΄μ—μ„œλŠ” PetOwnerκ°€ μ‚¬μš©ν•  animalμ΄λΌλŠ” 객체 생성과 κΈ°λŠ₯이 λͺ¨λ‘ Dog에 μ˜μ‘΄ν•œλ‹€. 즉, μ•„μ£Ό κΈ΄λ°€ν•˜κ²Œ μ—°κ²°(tight coupling) λ˜μ–΄ μžˆλ‹€κ³  λ³Ό 수 μžˆλ‹€.

이런 상황은 λ””μžμΈ νŒ¨λŸ¬λ‹€μž„ 쀑 ν•˜λ‚˜μΈ β€œLow Coupling”에 λΆ€ν•©ν•˜μ§€ μ•ŠλŠ”λ‹€.

μ™œλƒν•˜λ©΄, Coupling이 μ‘΄μž¬ν•œλ‹€λ©΄ μ–΄λ–€ λͺ¨λ“ˆμ˜ APIλ‚˜ 행동이 λ°”λ€Œλ‹€λ©΄, κ·Έ λͺ¨λ“ˆμ— μ˜μ‘΄ν•œ λ‹€λ₯Έ λͺ¨λ“ˆκΉŒμ§€ μ½”λ“œλ₯Ό λ³€κ²½ν•΄μ€˜μ•Ό ν•  κ°€λŠ₯성이 생기기 λ•Œλ¬Έμ΄λ‹€.

즉, Dog 객체λ₯Ό μˆ˜μ •ν•˜λ©΄, PetOwnerκΉŒμ§€ 덩달아 μˆ˜μ •ν•΄μ•Ό 할지도 λͺ¨λ₯Έλ‹€.

μ£Όμž…; Injection

β€œμ£Όμž…β€μ€ 객체 생성이 λ‚΄λΆ€κ°€ μ•„λ‹ˆλΌ β€œμ™ΈλΆ€β€μ—μ„œ μ§„ν–‰ν•˜μ—¬ 그것을 μ‚¬μš©ν•  객체에 μ£Όμž…ν•˜λŠ” 것을 λ§ν•œλ‹€.

μœ„μ˜ μ˜ˆμ‹œ μ½”λ“œμ—μ„œλŠ” this.animal 객체의 생성을 PetOwner 객체의 β€œλ‚΄λΆ€β€μ—μ„œ μ§„ν–‰ν–ˆλ‹€.

κ·Έλž˜μ„œ μ΄λ²ˆμ—” β€œμ£Όμž…β€μœΌλ‘œ μ½”λ“œλ₯Ό μˆ˜μ •ν•΄λ³΄μž.

public class PetOwner{
  private AnimalType animal;

  public PetOwner(AnimalType animal) {
    this.animal = animal;
  }
}

μˆ˜μ • μ΄ν›„μ—λŠ” PetOwner의 μƒμ„±μžμ—μ„œ animal에 λŒ€ν•œ 인자λ₯Ό λ°›λŠ” λ°©μ‹μœΌλ‘œ λ°”λ€Œμ—ˆλ‹€.

μ΄λŠ” 객체 λ‚΄λΆ€κ°€ μ•„λ‹Œ β€œμ™ΈλΆ€β€μ—μ„œ AnimalType의 객체을 λ§Œλ“€μ–΄ PetOwner 객체에 μ£Όμž…ν•˜λŠ” 꼴이닀!

μ΄λ ‡κ²Œ λ§Œλ“€ 경우, PetOwner와 Dog μ‚¬μ΄μ˜ couping은 μ˜…μ–΄μ§€κ²Œ λœλ‹€!!

였히렀 Dog λŒ€μ‹ μ— Catμ΄λ‚˜ Rabbit 같은 μƒˆλ‘œμš΄ ν˜•νƒœμ˜ AniamlType 클래슀λ₯Ό μ •μ˜ 해쀄 수 μžˆλ‹€!! (짱인데?)


사싀 μœ„μ™€ 같이 β€œμ˜μ‘΄μ„±β€μ΄ λ°œκ²¬λ˜λŠ” 뢀뢄을 β€œμ£Όμž…β€μœΌλ‘œ ν•΄κ²°ν•΄μ£Όλ©΄ β€œμ˜μ‘΄μ„±-μ£Όμž…β€œμ΄ λœλ‹€!! πŸ™‚

μœ„μ˜ μ½”λ“œμ—μ„œλŠ” κ°„λ‹¨ν•˜κ²Œ ν•¨μˆ˜ 인자둜 μ„€μ •ν–ˆμ§€λ§Œ, 객체λ₯Ό μƒμ„±μ˜ Factoryλ₯Ό μ‚¬μš©ν•  μˆ˜λ„ μžˆμ„ 것 κ°™λ‹€!!



μ—¬κΈ°κΉŒμ§€λ§Œ μ•Œλ©΄, DI에 λŒ€ν•΄ μΆ©λΆ„νžˆ μ΄ν•΄ν•œ 것이닀.

이제 쑰금 μ†Œν”„νŠΈμ›¨μ–΄ 섀계λ₯Ό 곁듀인 κ°œλ…λ“€μ„ μ‚΄νŽ΄λ³΄μž. Design Principle에 λŒ€ν•΄ μ΅μˆ™ν•˜λ‹€λ©΄, λ‹Ήμ—°ν•œ 것듀을 κΈ°μˆ ν•˜λŠ” 것과 λΆˆκ³Όν•˜λ‹€κ³  λŠλ‚„ 것이닀.

μ œμ–΄μ˜ μ—­μ „κ³Ό μ˜μ‘΄κ΄€κ³„ μ—­μ „

μ œμ–΄μ˜ μ—­μ „

Β  Principle that promotes components that relinquish control of aspects of the code execution to external modules to obtain β€œweek coupling”. * relinquish: give up

</div>

예λ₯Ό λ“€μ–΄, Sorting ν•¨μˆ˜μ˜ Comparatorκ°€ λŒ€ν‘œμ μΈ β€œμ œμ–΄μ˜ μ—­μ „(Inversion of Control; IoC)”이닀!

List<T>.Sort(IComparator<T>);

List의 Sort ν•¨μˆ˜λŠ” μ‹€μ œ Sorting을 μˆ˜ν–‰ν•  ꡬ체적인 방법/기쀀을 Sort APIλ₯Ό μ‚¬μš©ν•˜λŠ” Client λ‹¨μ—μ„œ λ§‘κΉ€μœΌλ‘œμ¨ Control의 일뢀λ₯Ό ν¬κΈ°ν•˜μ˜€λ‹€!

ClientλŠ” IComparator dependency에 λŒ€ν•œ implementation, creation, lifetime을 λͺ¨λ‘ 직접 κ΄€λ¦¬ν•œλ‹€!

이 β€œμ œμ–΄μ˜ 역전”과 DI에 λŒ€ν•œ κ΄€κ³„λŠ” μ•„λž˜ λ¬Έμž₯μ—μ„œ μ†Œκ°œλœλ‹€.

Β  β€œDependency injection is a software design pattern that implements inversion of control for resolving dependencies. A β€˜dependency’ is an object that can be used. An β€˜injection’ is the passing of a dependency to a dependent object that would use it. - Wikipedia

</div>


μ˜μ‘΄κ΄€κ³„ μ—­μ „μ˜ 원칙

β€œμ˜μ‘΄κ΄€κ³„ μ—­μ „μ˜ 원칙(Dependency Inversion Principle; DIP)β€œλŠ” 객체 사이에 μ˜μ‘΄κ΄€κ³„λ₯Ό 맺을 λ•Œμ˜ κ°€μ΄λ“œ 라인이닀.

DIPλŠ” μ˜μ‘΄κ΄€κ³„λ₯Ό 맺을 λ•Œ λ³€ν™”ν•˜κΈ° μ‰¬μš΄ 것 λ˜λŠ” 자주 λ³€ν•˜λŠ” 것 λ³΄λ‹€λŠ” λ³€ν™”ν•˜κΈ° μ–΄λ €μš΄ 것, 거의 λ³€ν•˜μ§€ μ•ŠλŠ” 것에 μ˜μ‘΄ν•˜λΌλŠ” 원칙이닀!

μ΄λ•Œ, 변함에 λŒ€ν•œ ꡬ뢄 기쀀은

  • 섀계도 interface이면 λ³€ν•˜μ§€ μ•ŠλŠ” 것, 아직 λ³€ν•˜μ§€ μ•Šμ€ 것
  • κ΅¬ν˜„μ²΄ implementation은 이미 λ³€ν•œ 것

μ •λ„λ‘œ μ΄ν•΄ν•˜λ©΄ 될 것 κ°™λ‹€.

μ•žμ—μ„œμ˜ 예제λ₯Ό 빌렀였자면, κ΅¬ν˜„μ²΄μΈ Dog에 μ˜μ‘΄ν•˜λŠ” 것이 μ•„λ‹ˆλΌ AnimalType μžμ²΄μ™€ 같은 좔상적인 interface에 μ˜μ‘΄ν•˜λΌλŠ” 것이닀!!

interface에 μ˜μ‘΄ν•¨μœΌλ‘œμ¨ μ†Œν”„νŠΈμ›¨μ–΄λŠ” 쒀더 μœ μ—°ν•œ μ‹œμŠ€ν…œμ΄ λœλ‹€.

쒀더 μ—„λ°€νžˆ κΈ°μˆ ν•΄λ³΄μžλ©΄,

A. ν•˜μ΄-레벨 λͺ¨λ“ˆμ€ 둜우-레벨 λͺ¨λ“ˆμ— μ˜μ‘΄ν•΄μ„œλŠ” μ•ˆ λœλ‹€. λ‘˜λ‹€ 좔상에 μ˜μ‘΄ν•΄μ•Ό ν•œλ‹€.
A. High-level module should not depend upon low-level module. Both should depend upon abstractions.

B. 좔상은 상세λ₯Ό μ˜μ‘΄ν•΄μ„œλŠ” μ•ˆ λœλ‹€. μƒμ„ΈλŠ” 좔상을 μ˜μ‘΄ν•΄μ•Ό ν•œλ‹€.
B. Abstractions should not depend upon details. Details should depend upon abstraction.

β€œμ˜μ‘΄ 관계 μ—­μ „β€μ—μ„œ β€˜μ—­μ „inversionβ€˜μ˜ μ˜λ―ΈλŠ” λͺ¨λ“  것을 둜우-레벨 λͺ¨λ“ˆμ— μ˜μ‘΄ν•˜λŠ” 전톡적인 μ„€κ³„μ—μ„œ ν•˜μ΄-레벨 λͺ¨λ“ˆμ— μ˜μ‘΄ν•˜λŠ” λ°©μ‹μœΌλ‘œ β€˜μ—­μ „β€™λ˜μ—ˆλ‹€λŠ” 의미λ₯Ό λ‹΄κ³  μžˆλ‹€.


λͺ¨λΈ λ””μžμΈμ΄ DIPλ₯Ό λ§Œμ‘±ν•˜λŠ” 섀계라면, β€˜μ˜μ‘΄μ„± μ£Όμž…β€™μ„ μ‰½κ²Œ μˆ˜μš©ν•˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.

μ˜μ‘΄μ„±μ΄ ν•„μš”ν•œ 뢀뢄이 implementation이 μ•„λ‹ˆλΌ interface에 μ˜μ‘΄λ˜μ–΄ 있기 λ•Œλ¬Έμ— κ·Έ interfaceλ₯Ό 기반으둜 ν•œλ‹€λ©΄ μ˜μ‘΄μ„±μ„ μ†μ‰½κ²Œ μ£Όμž…ν•  수 μžˆλ‹€.



자! 이제 μ²˜μŒμ— 봀던 지을 λ‹€μ‹œ ν•œλ²ˆ 보자.

Material from here



참고자료

Categories:

Updated: