개요

기존 의존 관계 설정

Main이라는 객체가 Dep이라는 객체에 의존하고 있다고 가정해 보자. 전통적으로 작성하다 보면 아마 다음 흐름이 나올 것이다.

class Dep:
	def run(self) -> int:
		return 1

class Main:
	def run(self) -> int:
		return Dep().run()

이 경우 Main은 Dep에 직접적으로 의존 관계를 가지게 된다. 서로 강하게 결합 된다고 표현할 수도 있다. 무슨 의미냐면,

  1. Main이 Dep에 의존하고 있다는 사실이 Main의 공개 API(public method)를 통해 노출되어 있지 않아 밖에서 알기 어렵다.
  2. Dep의 자리는 진짜 Dep이 아닌 다른 객체가 대채할 수 없다. 때문에 다형성 동작이 어렵다.
  3. 2에 이어서, Main과 Dep은 겉보기에는 2개의 객체지만, Main 입장에서는 사실상 하나의 객체나 다름이 없다. Main을 실행하려면 반드시 Dep을 실행해야 한다. 이는 단위 테스트를 작성할 때 문제가 될 수도 있다.

이런 문제가 있는데 어떻게 해결하지?!

<aside> 💡 즉, 위 3가지가 현재 작성하는 코드와 관계 없는 문제라면, DIP는 생각할 필요가 없다는 말이 된다.

</aside>

추상화에 의존하기

그럼 객체 사이의 결합을 낮추려면 어떻게 해야 할까? 구체적 객체가 아니라 추상화된 인터페이스에 의존하게 만들면 된다. 인터페이스는 크게, 자바의 Interface처럼 서브타입으로 선언할 수도 있고, Golang의 interface처럼 프로토콜(흔히 정적 duck-typing 이라고도 부름)로 선언할 수도 있다.

파이썬은 동적 언어이기 때문에, 기본적으로는 서브타입도 정적 duck-typing도 필요 없지만, abc패키지를 사용해서 서브타입 인터페이스를, typing 패키지의 Protocol을 사용해서 정적 duck-typing을 사용할 수 있다.