책 일지/만들면서 배우는 클린 아키텍쳐

2장 의존성 역전하기

worldi 2024. 1. 1. 23:30

목차에 앞서서, SOLID 의 핵심 기능 중 하나인 S와 D를 먼저 이야기 나누어 보겠다.

단일 책임 원칙 (SRP)

Single Responsibility Principle 로 직역하자면 하나의 컴포넌트는 오로지 한 가지 일만 해야하고, 그것을 올바르게 수행해야 한다는 의미이다.

 

하지만, 실제 정의는 다음과 같다.

컴포넌트를 변경하는 이유는 오직 하나뿐이어야 한다.

 

즉, 책임은 오로지 한가지 일을 하는 것 보다 “변경할 이유” 로 해석되어야 한다.

 

 

다음과 같이, E는 다른 컴포넌트에 의존하지 않으므로, E를 변경할 이유는 새로운 요구사항에 의해 E의 기능을 바꾸어야 할 때이다.

 

하지만, A와 같은 경우, 여러 컴포넌트에 의존하고 있기 때문에, 직접적인 B, C 의존성은 물론, 간접적인 D, E의 변경 또한 신경써줘야 한다.

이를 통해, 단일 책임 원칙을 위반하게 되고, 시간이 갈 수록 변경하기가 더 어려워지며 변경 비용이 증가한다.

이는 추후 한 컴포넌트를 바꾸는 것이 다른 컴포넌트가 실패하는 원인으로 작용할 수 있다.

 

의존성 역전 원칙

계층형 아키텍처에서, 상위 계층 들이 하위 계층들을 의존하므로, 변경할 이유가 더 많다는 것을 알 수 있다.

 

즉, 도메인 계층이 영속성 계층을 의존하기 때문에 영속성 계층을 변경하게 되면, 잠재적으로 도메인 계층도 변화한다.

이를 어떻게 해결할 수 있을까?

 

바로 의존성 역전 원칙이다! (Dependency Inversion Principle, DIP)

 

코드상의 어떤 의존성이든 그 방향을 바꿀 수 있다.

 

 

단, 조건으로 의존성의 양쪽 코드를 모두 제어할 수 있을 때 의존성을 역전시킬 수 있다. 즉 다른 라이브러리에 의존성이 있다면, 해당 라이브러리를 제어할 수 없기에 의존성 역전이 불가능하다.

 

도메인 코드와 영속성 코드간의 의존성을 역전시켜서 영속성 코드가 도메인 코드에 의존하도록 변경해보면,

다음과 같다.

도메인 계층에 인터페이스를 도입함으로써, 의존성을 역전시킬 수 있으며 이를 통해 영속성 계층이 도메인 계층을 의존할 수 있다.

 

클린 아키텍처

로버스 C. 마틴이 클린아키텍처를 다음과 같이 말한다.

비즈니스 규칙의 테스트를 용이하게 하고, 비즈니스 규칙은 프레임워크, 데이터베이스, UI, 외부 애플리케이션, 인터페이스로 부터 독립적이다.

 

이는, 도메인 코드가 어떤 의존성을 갖고 있지 않고, 모든 의존성이 도메인 코드로 향하게 두어야 함을 의미한다.

 

여기서 중요한 점은 계층 간의 모든 의존성이 안쪽으로 향해야 하게 한다는 점이다.

 

아키텍처의 코어에는 주변 유스케이스에서 접근하는 도메인 엔티티들이 있다.그리고 유스케이스는 서비스로 단일 책임을 갖기 위해, 조금 더 세분화되어 있다. 이를 통해 넓은 서비스 문제를 피할 수 있다.

 

이를 구현하기 위해선, 도메인 계층과 외부 계층이 철저히 분리 되어야 하므로 애플리케이션의 각 엔티티에 대한 모델을 각 계층에서 유지보수하여야 한다.

 

즉, 영속성 계층에서 ORM을 쓴다고 가정한다면, 데이터베이스 구조 및 객체 필드와 데이터베이스 칼럼의 매핑을 서술한 메타데이터를 담고 있는 엔티티 클래스를 필요로 한다.

 

도메인 계층은 영속성 계층을 모르기 때문에, 이는 도메인 계층과 영속성 계층 각각 엔티티를 만들어야 한다. 즉, 도메인 계층과 영속성 계층이 데이터를 주고 받을 때, 두 엔티티를 서로 변환해야한다는 뜻이다.

 

 

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

육각형 아키텍처는 알리스테어 콕번이 만든 용어로, 클린 아키텍처에서의 같은 양상을 띤다.

 

 

육각형 아키텍처는 다음과 같이, 애플리케이션이 다른 시스템이나 어댑터와 연결되는 4개 이상의 면을 가질 수 있음을 보여주기 위해 일반적인 사각형 대신, 육각형을 사용하였다.

 

육각형 안에는 도메인 엔티티와 상호작용하는 유스케이스가 있고, 모든 의존성은 도메인 쪽으로 향하는 것을 알 수 있다.

 

또한 육각형 바깥쪽에는 애플리케이션과 상호작용하는 여러 어댑터가 존재한다. 이는 데이터베이스 뿐만 아니라, 웹 어댑터, 외부 어댑터를 포함한다.

 

이는 포트와 어댑터 아키텍처 로도 알려져있다. 가장 바깥쪽의 계층은 애플리케이션과 다른 시스템 간의 번역을 담당하는 어댑터로 구성돼 있다. 그리고 포트+ 유스케이스 구현체를 결합해 애플리케이션 계층을 구성한다. 그리고 안에 계층은 도메인 엔티티가 위치한다.

 

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

의존성 역전을 이용하여 도메인 코드가 다른 외부 코드를 의존하지 않는다는 것이 핵심이다.

이를 통해, 도메인 코드를 변경할 이유를 줄이고, 유지보수성을 좋게한다.