Software Engineering

의존성 역전 원칙(Dependency Inversion Principle, DIP)

habana4 2024. 10. 26. 09:56
728x90
반응형

의존성 역전 원칙(DIP, Dependency Inversion Principle)은 모듈 간의 결합도를 낮추어 유지보수성과 확장성을 높이는 객체지향 설계 원칙입니다. 특히, 상위 모듈이 하위 모듈에 의존하는 대신, 추상화된 인터페이스에 의존하게 함으로써 시스템의 유연성을 극대화할 수 있습니다. DIP는 SOLID 원칙 중 마지막 원칙으로, DIP를 통해 변경에 강한 구조를 갖추고 코드 재사용성을 극대화할 수 있습니다.

 

1. 의존성 역전 원칙이란 무엇인가?

먼저 다음 그림을 보겠습니다. 소프트웨어를 개발함에 있어 요구사항부터 구현까지의 과정에서 다양한 행위들이 존재할 수 있습니다. 과연 어떤 형태의 방법이 합리적일까요? 물론 여기에 정답은 없다고 생각합니다. 개발하는 개발자의 역량과 조직구성, 상황, 그리고 프로세스 등 다양한 변수가 존재하고 이에 따라 합리성 결과는 달라질 수 있을 것입니다.

소프트웨어 개발 절차

 

그러나 아키텍처가 존재하는 이유는 분명 따로 있는 것처럼 같은 맥락에서 의존성 역전 원칙을 살펴 보겠습니다.

 

의존성 역전 원칙은 다음 두 가지 기본 규칙을 제안합니다:

  1. 상위 모듈이 하위 모듈에 의존하지 말고, 추상화(인터페이스)에 의존해야 한다: 상위 모듈과 하위 모듈이 모두 인터페이스나 추상 클래스와 같은 추상화된 요소에 의존하게 함으로써, 하위 모듈이 변경될 때 상위 모듈의 변경을 최소화할 수 있습니다.
  2. 추상화는 세부 사항에 의존하지 않게 하며, 세부 사항이 추상화에 의존해야 한다: 구현 세부 사항이 추상화된 인터페이스에 의존하게 함으로써 변경이 필요할 때 인터페이스만 유지된다면 다른 요소에 미치는 영향을 최소화할 수 있습니다.

이 원칙을 통해 소프트웨어는 보다 유연하고 확장 가능하게 설계되며, 상위 모듈과 하위 모듈 간의 결합도가 낮아져 수정 시 영향 범위가 줄어들게 됩니다.

 

2. 의존성 역전 원칙의 필요성

일반적으로 상위 모듈이 하위 모듈에 직접적으로 의존하면, 하위 모듈이 변경될 때 상위 모듈이 수정될 가능성이 높습니다. DIP를 적용하지 않으면 결합도가 높아지고, 특정 기능 변경이나 확장 시 코드 수정 범위가 넓어지며, 유지보수 비용이 증가합니다.

 

예를 들어, 전자 상거래 시스템에서 상품 추천 기능을 변경하려고 할 때, 추천 기능의 구현을 직접 상위 모듈에 연결해 두었다면, 이를 교체하기 위해 많은 부분을 수정해야 합니다. DIP를 적용하여 상위 모듈이 추상화된 인터페이스에만 의존하도록 한다면, 추천 기능의 세부 구현은 쉽게 교체할 수 있어 유지보수성이 높아집니다.

 

3. 의존성 역전 원칙 적용 방법

의존성 역전 원칙 적용은 객체지향 특성이 강한 C++에서는 클래스와 인터페이스를 사용하여 더 직관적으로 적용할 수 있습니다. 반면, C 언어에서는 함수 포인터와 구조체를 활용하여 DIP를 구현할 수 있습니다.

3.1 예제: C 언어 가상 알림 시스템

C 언어에서 DIP를 적용하여 가상 알림 시스템을 설계해보겠습니다. EmailNotificationSMSNotification 두 가지 구현체가 있으며, Notification 인터페이스에 의존하여 알림 유형을 변경해도 상위 모듈에 영향을 주지 않도록 합니다.

C언어 기반 가상 알림 시스템 개요
C언어 기반 가상 알림 시스템 구현

 

설명

  • Notification 구조체에 send 함수 포인터를 두어, 상위 모듈이 특정 구현체가 아닌 추상화된 Notification 인터페이스에 의존하게 합니다.
  • initEmailNotificationinitSMSNotification을 통해 Notification에 원하는 구현체를 주입할 수 있습니다.
  • 상위 모듈인 notify 함수는 Notification 인터페이스를 통해 알림을 전송하며, 특정 구현체에 의존하지 않기 때문에 구현체 교체 시에도 변경이 필요하지 않습니다.

3.2 예제 C++에서 의존성 역전 원칙 적용 예시

C++에서는 인터페이스로 추상 클래스를 활용하여 DIP를 구현할 수 있습니다.

 

예제: 가상 알림 시스템

C++언어 기반 가상 알림 시스템 구현

 

설명

  • Notification 추상 클래스는 알림을 보내는 send 메서드를 정의하며, EmailNotification과 SMSNotification 클래스는 이를 상속받아 각각의 알림 방식을 구현합니다.
  • Notifier 클래스는 Notification 인터페이스에 의존하며, shared_ptr을 통해 원하는 구현체를 주입받아 알림을 전송합니다.
  • Notifier 클래스는 특정 알림 구현체가 아닌 추상화된 Notification에 의존하므로, 알림 방식을 교체할 때도 상위 모듈의 코드 수정이 필요하지 않습니다.

 

6. 의존성 역전 원칙의 장점

의존성 역전 원칙을 적용하면 다음과 같은 장점이 있습니다:

  • 유연성과 확장성: DIP를 적용하여 상위 모듈이 하위 모듈에 의존하지 않기 때문에, 다양한 하위 모듈을 쉽게 교체하거나 확장할 수 있습니다.
  • 결합도 감소: 상위 모듈과 하위 모듈 간 결합도가 낮아져 모듈 교체 시 영향이 줄어들고, 특정 기능을 다양한 모듈에서 재사용할 수 있습니다.
  • 유지보수성: DIP는 시스템의 유지보수성을 높이며, 특정 모듈을 교체할 때 상위 모듈을 수정할 필요가 없어 코드 안정성이 강화됩니다.

마치며...

의존성 역전 원칙(DIP)은 상위 모듈이 하위 모듈의 구체적인 구현에 의존하지 않고 추상화된 인터페이스에 의존하게 함으로써, 시스템의 유연성과 확장성을 높이는 중요한 설계 원칙입니다. DIP를 통해 코드 간 결합도를 낮추고, 기능 교체나 확장 시 상위 모듈의 코드 변경을 최소화할 수 있습니다. 이를 통해 재사용성과 유지보수성을 크게 향상시키며, 소프트웨어 개발의 복잡성을 효과적으로 관리할 수 있습니다.

 

C와 C++ 모두 DIP를 적용할 수 있으며, C에서는 함수 포인터구조체를 사용하여 추상화를 구현하고, C++에서는 추상 클래스스마트 포인터를 활용하여 보다 직관적이고 객체지향적인 방식으로 DIP를 적용할 수 있습니다. DIP는 유연한 시스템을 만들기 위한 필수 원칙으로, 다양한 프로그래밍 환경에서 매우 유용하게 사용됩니다

728x90
반응형