[TIL] Today, I learned : DI(Dependency Injection) 의존성 주입

Uno·2022년 1월 24일
0

개념보관소

목록 보기
2/3

작성 동기

  • MVVM을 공부하다보니까, 의존성 주입에 대해서 신경쓰게 되었습니다. 다양한 자료들을 살펴보니 ViewModel의 인스턴스를 주입하는 시기가 상당히 다양하더라구요. 그래서 해당 개념에 대해서 정리해볼까 했습니다.

의존성 주입 (Dependency Injection)이란?

Dependency injection is a 25-dollar term for 5-cent concept - James Shore

  • 의존성 주입이라는 표현을 너무 어렵게 이야기하는 것에 대한 비유입니다. 개인적으로도 정리를 하고나니 이런 느낌이 없지않아 있네요. 어려운 개념이라고 생각하고 바라보면, 정말 고민할게 많을 수 있지만, 간단하게 바라보면 한없이 간단한 것 같습니다.
  • 의존성 주입이라는 단어를 뜯어보면, 의존성 이라는 명사를 주입한다(=넣는다.) 입니다. 그러면 의존성이 무엇인지 알면 좋겠네요.

의존성?

  • "의존" 이라는 뜻은 다음과 같습니다.

"의존(依存)'은 '다른 것에 의지하여 존재함."

  • 하나의 객체가 다른 객체에 의지하고 있다는 뜻이죠. 의지한다는 것은 그것이 없으면 불편하다 혹은 안된다라는 의미로도 해석이 되겠네요.
  • 즉, A라는 객체가 있고 B라는 객체가 있는데, A가 정상적으로 동작하기 위해서는 B가 필요하다면, A는 B에 의존하고 있다는 뜻이죠.

의존성주입은 언제 필요한 것을 전달해주느냐이다.

  • 의존의 뜻에서 유추하면, 결국 A는 B가 필요합니다. 그러면 그것을 언제 전달해주면 좋을까요? 이것을 고민하는 것이 의존성 주입니다.
  • 단순하게 말하면, 언제 인스턴스를 생성해서 A에게 전달해주면 가장 적절할까요? 라고 생각할 수도 있겠네요.

2 가지 의존성 주입 방법

  1. 내부에서 직접 생성해서 생성한 객체에 의존한다.
class A {
  var b = B()
}
  1. 외부에서 전달받는다.
class A {
  var b 
  
  init(b: B) {
    self.b = b
  }
}

// 혹은

// 밖에서
var a = A()
a.b = b()

class A {
  var b: B?
}

이점이 뭔데?

두 가지 방법이 있는 것은 알겠습니다. 이걸 하면 도대체 무엇이 장점일까요?

사실 위 예시코드로는 이점을 얻었다고 하긴 힘듭니다. 왜냐하면, protocol이 있을 때, 저는 의존성 주입에 대해서 장점이 생긴다고 생각합니다. 아래처럼요.

protocol 노트북기능 {
  func 디스플레이송출()
  func 사운드출력()
  func 와이파이연결()
}
  • 노트븍의 기능을 일반적인 속성을 추상화했습니다. 이후에는 각각의 노트북들이 해당 동작을 하겠죠?
  • 아래 기능은 디스플레이송출만 하겠습니다.
class 비보북: 노트북기능 {
  func 디스플레이송출() {
    120Hz송출()
  }
  ...
}

class 맥북: 노트북기능 {
  func 디스플레이송출() {
    	레티나디스플레이()
  }
  ...
}
  • 이렇게 노트북 기능의 규약을 따르면, 노트북이라고 쳐도 되겠죠? 그러면 특정 사람이 노트북이 필요할 때, 노트북 기능을 따르는 노트북 어느것을 전달해줘도 될겁니다. 아래코드처럼요.
class 우노 {
  var 노트북: 노트북기능
  ...
  init(노트북: 노트북기능) {
    self.노트북 = 노트북
  }
}
  • 이렇게 우노의 객체가 선언되어있다고 가정해봅시다.(우노는 참고로 저입니다.)
let macbook = 맥북()
let normalLaptop = 비보북()

// #1
let uno = 우노(노트북: 맥북)
// #2
let uno = 우노(노트북: 비보북)
  • 여기가 핵심입니다. uno는 노트북으로 맥북과 비보북을 모두 받을 수 있습니다. 왜냐하면 "노트북기능" 프로토콜을 모두 준수하고 있기 때문이죠.
  • 이런식으로 프로토콜을 활용하여 의존성을 주입하면, 노트북에 특정 객체에만 의존하지 않게 되고 "노트북기능"을 채택한 노트북 객체가 모두 가능하기에 의존성을 상대적으로 낮출 수 있게됩니다.

정리

의존성 주입이라는 말은, 원하는 객체를 언제 전달해줄지에 관한 질문이라고 정리할 수 있겠습니다. 그 과정에서 "Protocol"이 유용한 개념이 되겠구요.

장점이라고하면

  1. 유지보수에 유리해진 구조를 가진다.

    -> 프로토콜만 채택하면 새로운 객체 어느것이든 구성해서 넣을 수 있으니까요.

  2. 테스트터블한 구조

    -> 의존성 주입 == input 이니 그것에 대한 output을 테스트하면 되는 비교적 단순한 테스터블한 구조(물론 이것 하나로 되는 것은 아니라고 봅니다만, 시작점이라고 생각합니다.)

  3. 확장성

    -> 확장성은 이미 느끼셨겠죠? 노트북에 들어갈 객체를 생성할 때, 그냥 프로토콜만 채택해서 구현하고 넣으면됩니다.

단점이라고하면

  1. 의존성 주입 시점에 대한 동료들간의 합치가 있어야함.

    -> 동료들간 의존성 주입을 다르게한다면, 코드가 상당히 복잡해질 우려가 있겠죠? (저같은 경우 required init을 활용해서 강제하려고 노력합니다. 옵셔널 선언 후 서브스크립트로 전달하는 경우는 시간이 지난다음 코드를 보거나 다른 사람이 보면 빼먹고 의존성 주입을 안해줄 우려가 조금이나마 남아있으니까요.)

참고자료

https://wlgusdn700.tistory.com/m/124
https://sihyungyou.github.io/iOS-dependency-injection/
https://silver-g-0114.tistory.com/143

profile
iOS & Flutter

0개의 댓글