본문 바로가기
IT 서적/Clean Architecture

11장. DIP: 의존성 역전 원칙(Dependency Inversion Principle)

by Crystal.k 2022. 3. 21.

11장. DIP: 의존성 역전 원칙(Dependency Inversion Principle)

고수준 정책을 구현하는 코드는 저수준 세부사항을 구현하는 코드에 절대로 의존해서는 안된다. 대신 세부사항이 정책에 의존해야 한다.

 

의존성 역전 원칙에서 말하는 ‘유연성이 극대화된 시스템’이란 소스 코드 의존성이 추상(abstraction)에 의존하며 구체(concretion)에는 의존하지 않는 시스템이다.

 

DIP를 논할 때 운영체제나 플랫폼 같이 안정성이 보장된 환경에 대해서는 무시하는 편이다.

환경에 대한 의존성은 용납한다. 변경되지 않는다면 의존할 수 있다는 사실을 이미 알고 있기 때문이다.

의존하지 않고 피하고자 하는 것은 바로 변동성이 큰 구체적인 요소이다.

이 요소는 우리가 열심히 개발하는 중이라 자주 변경될 수밖에 없는 모듈들이다.

 

안정된 추상화

인터페이스는 구현체보다 변동성이 낮다.

인터페이스를 변경하지 않고도 구현체에 기능을 추가할 수 있는 방법을 찾기 위해 노력한다. (소프트웨어의 설계의 기본이다.)

안정된 소프트웨어 아키텍처 : 변동성이 큰 구현체에 의존하는 일은 지양하고, 안정된 취상 인터페이스를 선호하는 아키텍처.

  • 변동성이 큰 구체 클래스를 참조하지 말라.
    • 대신 추상 인터페이스를 참조하라.
    • 언어가 정적 타입(java)이든 동적 타입( 파이선)이든 관계없이 적용된다
    • 이 규칙은 객체 생성 방식을 강하게 제약하며, 일반적으로 추상 팩토리(abstract Factory)를 사용하도록 강제한다.
  • 변동성이 큰 구체 클래스로부터 파생하지 말라.
    • 상속은 아주 신중하게 사용해야 한다.
    • 정적 타입 언어에서 상속은 소스코드에 존재하는 모든 관계 중에서 가장 강력한 동시에 뻣뻣해서 변경하기 어렵다.
    • 동적 타입 언어는 문제가 덜 되지만 의존성을 가진다는 사실은 변함없다. 결국 신중해야 한다.
  • 구체 함수를 오버라이드 하지 말라.
    • 대체로 구체 함수는 소스코드 의존성을 필요로 하기 때문에 오버라이드 하게 되면 의존성을 제거할 수 없게 되며, 의존성을 상속하게 된다.
    • 차라리 추상 함수로 선언하고 구현체들에서 각자의 용도에 맞게 구현해야 한다.
  • 구체적이며 변동성이 크다면 절대로 그 이름을 언급하지 말라.

 

팩토리

사실상 모든 언언에서 객체를 생성하려면 해당 객체를 구체적으로 정의한 코드에 대해서 의존성이 발생한다. 자바 등 객체 지향 언어에서 이처럼 바람직하지 못한 의존성을 처리할 때 추상 팩토리를 사용한다.

Application은 Service 인터페이스를 통해 ConcreteImpl을 사용하지만,

Application에서는 어떤 식으로든 ConcreteImpl의 인스턴스를 생성해야 한다.

Application은 ConcreteImpl에 대해서 의존성을 만들지 않으면서 인스턴스를 생성하기 위해서, Application은 ServiceFactory 인터페이스 makeSvc 메서드를 호출한다.

이 메소드(makeSvc)는 ServiceFactory로부터 파생된 ServiceFactoryImpl에서 구현된다. 그리고 ServiceFactoryImpl 구현체가 ConcreteImpl의 인스턴스를 생성한 후 Service 타입으로 반환한다.

 

 

소스 코드의 의존성은 그림의 곡선이 교차할 때 모두 한 방향으로 향한다. 구체 → 추상적인 쪽으로 향한다.

 

곡선은 곡선은 시스템을 두 가지 컴포넌트로 분류한다.

추상 컴포넌트는 애플리케이션의 모든 고수준 업무 규칙을 포함한다.

구체 컴포넌트는 업무 규칙을 다루기 위해 필요한 모든 세부사항을 포함한다.

제어 흐름을 소스 코드 의존성과는 정반대 방향으로 곡선을 가로지른다. 의존성과 제어 흐름과는 반대방향으로 역전된다. 이런 이유로 이 원칙을 의존성 역전이라고 부른다.

 

구체 컴포넌트

위의 사진의 구체 컴포넌트에는 구체적인 의존성이 하나 있기 때문에 DIP에 위배된다. 이는 일반적인 일이다. DIP 위배를 모두 없앨 수는 없다.

하지만 DIP를 위배하는 클래스들은 적은 수의 구체 컴포넌트 내부로 모을 수 있고, 이를 통해 시스템 나머지 부분과 분리할 수 있다.

 

결론

고수준의 아키텍처 원칙을 다루게 되면서 DIP는 몇 번이고 계속 등장할 것이다.

그림의 곡선은 아키텍처 경계가 될 것이다. 의존성은 이 곡선을 경계로 더 추상적인 엔티티가 있는 쪽으로만 향한다. 추후 이 규칙은 의존성 규칙이라 부를 것이다.

반응형

댓글