솜이의 데브로그

Chapter 2 ) 의존성 역전하기 본문

책을 읽자/만들면서 배우는 클린 아키텍처

Chapter 2 ) 의존성 역전하기

somsoming 2022. 10. 26. 01:21

Reference : 만들면서 배우는 클린 아키텍처

 

단일 책임 원칙

컴포넌트를 변경하는 이유는 오직 하나 뿐이어야 한다.
  • 컴포넌트를 변경할 이유가 오로지 한 가지라면 컴포넌트는 딱 한 가지 일만 하게 된다.
  • 아키텍처에서는, 컴포넌트를 변경할 이유가 한 가지라면 우리가 어떤 다른 이유로 소프트웨어를 변경하더라도 이 컴포넌트에 대해서는 전혀 신경 쓸 필요가 없다.
  • 변경할 이유라는 것은 컴포넌트 간의 의존성을 통해 쉽게 전파된다.
  • 많은 코드는 단일 책임 원칙을 위반하기 때문에 시간이 갈수록 변경하기가 더 어려워지고, 그로 인해 변경 비용도 증가한다.

 

의존성 역전 원칙

  • 계층형 아키텍처에서 계층 간 의존성은 항상 다음 계층인 아래 방향을 가리킨다.
    • 따라서 단일 책임 원칙을 고수준에서 적용할 때 상위 계층들이 하위 계층들에 비해 변경할 이유가 더 많다는 것을 알 수 있다.

의존성 역전 원칙

코드상의 어떤 의존성이든 그 방향을 바꿀 수 (역전시킬 수) 있다.

 

  • 위와 같은 구조를 가진 아키텍처에서, 도메인 계층에 영속성 계층의 엔티티와 리포지토리와 상호작용하는 서비스가 있다.
  • 엔티티는 도메인 객체를 표현하고 도메인 코드는 이 엔티티들의 상태를 변경하는 일을 중심으로 하기 때문에 엔티티를 도메인 계층으로 올린다.
  • 이렇게하면 영속성 계층의 리포지토리가 도메인 계층에 있는 엔티티에 의존하기 때문에 두 계층 사이에 순환 의존성(circular dependency)가 생긴다. 여기서 DIP를 적용한다.

  • 도메인 계층에 리포지토리에 대한 인터페이스를 만들고, 실제 리포지토리는 영속성 계층에서 구현하게 한다.도메인 계층에 인터페이스를 도입해서 의존성을 역전시킨다! (영속성 계층이 도메인 계층에 의존)

 

클린 아키텍처

  • 도메인 코드가 바깥으로 향하는 어떤 의존성도 없어야 한다.
  • 의존성 역전 원칙의 도움으로 모든 의존성이 도메인 코드를 향한다.

  • 위 아키텍처에서 가장 중요한 규칙은 의존성 규칙으로, 계층 간의 모든 의존성이 안쪽으로 향해야 한다는 것이다!
  • 이 아키텍처의 코어에는 주변 유스케이스에서 접근하는 도메인 엔티티들이 있다.
    • 유스케이스는 서비스.
  • 코어 주변으로 비즈니스 규칙을 지원하는 애플케이션의 다른 모든 컴포넌트들이 있다.
    • ‘지원’ : 영속성을 제공하거나 UI를 제공하는 것 등.
  • 바깥쪽 계층들은 다른 서드파티 컴포넌트에 어댑터를 제공.
  • 클린 아키텍처에서는 도메인 계층이 영속성이나 UI같은 외부 계층과 철저히 분리돼야 하므로 애플리케이션의 엔티티에 대한 모델을 각 계층에서 유지보수해야 한다.
    • 예를 들어 영속성 계층에서 ORM을 사용하는 경우, 엔티티 클래스를 필요로 한다.
    • 도메인 계층은 영속성 계층을 모르기 때문에 도메인 계층에서 사용한 엔티티 클래스를 영속성 계층에서 함께 사용할 수 없고 두 계층에서 각각 엔티티를 만들어야 한다.
    • 즉, 도메인 계층과 영속성 계층이 데이터를 주고받을 때, 두 엔티티를 서로 변환해야 한다.

 

육각형 아키텍처 (헥사고날 아키텍처)

  • 육각형 아키텍처는 애플리케이션 코어가 각 어댑터와 상호작용하기 위해 특정 포트를 제공하기 때문에 포트와 어댑터 아키텍처라고도 한다.
  • 육각형 안에는 도메인 엔티티와 이와 상호작용하는 유스케이스가 있다.
    • 모든 의존성은 코어를 향한다.
  • 육각형 바깥에는 애플리케이션과 상호작용하는 다양한 어댑터들이 있다.
  • 왼쪽의 어댑터들은 애플리케이션 코어를 호출하기 때문에 애플리케이션을 주도하는 어댑터들이고, 오른쪽에 있는 어댑터들은 애플리케이션 코어에 의해 호출되기 때문에 애플리케이션에 의해 주도되는 어댑터들이다.
  • 애플리케이션 코어와 어댑터들간의 통신이 가능하려면 애플리케이션 코어가 각각의 포트를 제공해야한다.
  • 주도하는 어댑터 (driving adapter)에게는 포트가 코어에 있는 유스케이스 클래스들에 의해 구현되고 호출되는 인터페이스.
  • 주도되는 어댑터 (driven adapter)에게는 그러한 포트가 어댑터에 의해 구현되고 코어에 의해 호출되는 인터페이스.

 

유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까?

  • 의존성을 역전시켜 도메인 코드가 다른 바깥쪽 코드에 의존하지 않게 함으로써 영속성과 UI에 특화된 모든 문제로부터 도메인 로직의 결합을 제거하고 코드를 변경할 이유의 수를 줄일 수 있다.
  • 도메인 코드는 비즈니스 문제에 딱 맞도록 자유롭게 모델링 될 수 있고, 영속성 코드와 UI 코드도 영속성 문제와 UI 문제에 맞게 자유롭게 모델링 될 수 있다.

이미지 참고1

이미지 참고2

이미지 참고3

 

 

느낀점

개념으로 보니까 너무 어렵고 특히 마지막에 헥사고날 아키텍처가 잘 와닿지 않는다..

코드로 보면서 더 이해해봐야겠다