DI, DIP 그리고 IOC
프로그래밍 2022. 6. 15. 22:51DI, DIP, IOC에 대하여 인터넷 상에 너무나도 많은 글들이 넘쳐나고 있습니다.
그 글들 중에는 제가 알고 있는 내용과 다른 글들도 아주 많더군요.
제가 틀렸을 수도 있지만 제가 아는것을 써보겠습니다.
혹시 제가 쓴 글이 틀린 부분이 있으면 과감히 지적해 주시면 감사하겠습니다.
전통적인 프로그래밍
간단한 예를 들어 들어 보겠습니다.
"흐름제어", "통신","Database" 모듈이라는 것이 있다고 가정하고...
전통적인 방법으로는 Software를 아래처럼 만들었겠죠.
즉, 이 그림에서 흐름제어 모듈이 통신 모듈과 Database 모듈에 참조를 걸고(include, import 등등의 방법으로)
아래와 같이 모듈 내부에서 직접 참조해서 구현하는 것이었습니다.
그리고 보통 "통신 모듈" 과 "Database 모듈" 을 먼저 만들고 이것들을 가지고 흐름제어 모듈이
나중에 Integration을 하게 되는 구조이지요.
그런데 이걸 가만히 생각해보면 처음부터 윗쪽 layer에 위치한 모듈과 아랫쪽 모듈간에는 세밀하게 협의하는 과정이 없었다는 것입니다.
그래서 작업도 아랫쪽 모듈이 만들어지기 전에는 윗쪽 모듈 작업을 못하고 기다리고 있게 되는 것이었죠.
이와 같은 방법은 윗쪽 Layer와 아랫쪽 Layer를 담당하는 부서가 나뉘어져 있으면 더욱 더 심해지고 이것은 Integration 단계에서 매우 큰 어려움을 유발하기 쉽습니다.
추상화
그런데 여기서 가만히 생각해 보면 윗쪽 아랫쪽이 서로 어떻게 동작할 것인지를 미리 정의(추상화)해 놓는다면
즉, 서로간이 규칙만 미리 정해져 있다면 윗쪽 layer에 위치한 모듈도 동시에 작업을 진행할 수 있을 것입니다.
실제 동작하지 않는 Interface는 Mock을 만들어 Interface에 붙여 놓으면 되니까요.
서로 규칙만 맞게 구현하면 되니까 나중에 싸울일도 없습니다.
DIP ( Dependeny Inversion Principle )
Dependency Inversion 이라는 말은 참조가 역전 되었다는 의미인거죠.
위에서 얘기했던 전통적인 방식의 참조는 위에서 아래방향으로 해야 했었는데..
그런데 바로 위에서 얘기한 추상화 단계를 끼워 넣어 보면 어떻게 될까요?
이 그림을 보면 전통적으로 우리가 알고 있던 모습과 달라져 버립니다.
왜냐면 위쪽 모듈은 아래쪽 모듈을 직접 참조하지 않고 추상화 된 Interface를 참조하고 아래쪽 통신 모듈과 Database 모듈 역시 위쪽에 위치한 "추상화된 Interface" 를 참조해야 하기 때문입니다.
심지어 아래쪽 모듈에서는 화살표가 위쪽으로 그려지는 것이죠.
이것은 전통적인 참조방법이 아니라 참조 방법이 역전된 것입니다. 그래서 "Dependency Inversion"이라는 말이 나오게 되었습니다.
DIP의 정의를 한 번 볼까요.
high level modules should not depend on low level modules; both should depend on abstractions. Abstractions should not depend on details. Details should depend upon abstractions.
"하이 레벨 모듈이 직접 로우 레벨을 참조하지 않고 추상화된 것들을 참조하라. 하이/로우 둘다 마찬가지다."
이렇게 구현하게 되면 "통신","Database"모듈은 수정하지 않고 "흐름제어" 모듈을 새로 구현하거나 바꿔치기 하는 것이 아주 쉬워집니다. 반대로 흐름제어 모듈을 건드리지 않고 "통신" 모듈이나 "Database"모듈만 교체 하는 것도 아주 쉬워집니다.
DI ( Dependency Injection )
위 그림처럼 추상화된 Interface를 사용하게 되면 어떤 모양이 될까요?
모든 모듈이 Interface만 가지고있게 됩니다.
그리고 이 모듈들은 추상화된 껍데기 Interface 만 가지고 있기 때문에 모듈의 생성 시점에는 어딘가에 만들어 놓은 Interface에 대한 구현체를 주입시켜 주어야 합니다.
이렇게 주입시키는 것을 Dependecy Injection이라 하며 이것은 할 수 있는 방법은 여러가지가 있습니다.
프로그래밍 언어와 Framework에 따라서도 방법이 많이 달라지고요.
IOC ( Inversion Of Control )
의미상 "제어의 역전"입니다. 도대체 뭐가 역전 되었다는 의미일까요?
제일 위의 첫 그림에서 보면 전통적인 방법의 제어 순서는 다음과 같습니다.
1. 흐름제어 모듈을 생성
2. 흐름제어 모듈이 내부에서 통신 모듈과 Database 모듈을 참조 후 생성
즉, 전통적인 모듈 생성의 관점에서 보면 윗쪽에서 아랫쪽으로 생성됩니다.
달리 말하면 아랫쪽 모듈은 생성부터 위쪽 모듈의 제어를 받게 되는 것입니다.
그러면 DIP가 적용된 모듈들은 어떻게 될까요?
1. 통신 Interface에 대한 구현체 생성
2. Databse Interface에 대한 구현체 생성
3. 흐름제어 모듈을 생성하면서 Interface에 주입
보시다시피 모듈 생성 순서가 완전히 역전 되었습니다.
흐름제어 모듈에 Interface 를 주입해 주기 위해서는 "통신","Database" 구현체를 먼저 만들어야 합니다.
전통적인 방법과 완전히 반대가 된 것이죠.
이것 때문에 Inversion Of Control 이라는 말이 생기게 되었습니다.
IOC Container
추가로 IOC Container는 어디에 사용 될까요?
위의 예에서 보면 DIP 가 적용된 모듈들의 전체적인 관리는 흐름제어 모듈이 하는 것도 아니고 통신, Databse 모듈이 하는 것도 아닙니다. 물론 어딘 가에서 할수 있을 테지만...
Interface에 대한 Instance를 만들어주는 역할을 통합해서 관리는 것이 IOC Container이고 이 IOC Container를 잘 활용하면 Interface들을 모듈들에 쉽게 주입시킬 수 있는 것입니다.
'프로그래밍' 카테고리의 다른 글
소켓 프로그래밍 3 - Accept (0) | 2022.06.22 |
---|---|
소켓 프로그래밍 2 - Client와 Port Range (0) | 2022.06.21 |
소켓 프로그래밍 1 - binding (0) | 2022.06.19 |
조제프 푸리에(Joseph Fourier) (1) | 2022.06.15 |
트랜지스터 (0) | 2022.06.15 |