본문 바로가기
Architecture

[Architecture] 2. 계층형 아키텍처의 대안

by jn4624 2024. 4. 11.
반응형
첫번째 챕터에서는 계층형 아키텍처의 문제점에 대해 이야기하였다.
이번 챕터에서는 계층형 아키텍처의 대안에 대해 이야기 한다.

 

1. 단일 책임 원칙

단일 책임 원칙의 일반적인 해석은 아래와 같다.

 

"하나의 컴포넌트는 오로지 한 가지 일만 해야 하고, 그것을 올바르게 수행해야 한다."

 

이는 단일 책임이라는 말을 가장 직관적으로 해석한 것으로, 단일 책임 원칙이라는 이름에 오해의 여지가 있다는 점을 주의해야 하며, 단일 책임 원칙의 실제 의도가 아니다.

 

단일 책임의 원칙의 실제 정의는 아래와 같다.

 

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

 

'책임'은 '오로지 한 가지 일만 하는 것'보다 '변경할 이유'로 해석해야 한다.

 

컴포넌트를 변경할 이유가 오로지 한 가지라면 컴포넌트는 딱 한 가지 일만 하게 된다.

이보다 더 중요한 것은 변경할 이유가 오직 한 가지라는 그 자체다.

 

아키텍처에서 어떤 의미일까?

컴포넌트를 변경할 이유가 한 가지라면, 어떤 다른 이유로 소프트웨어를 변경하더라도 해당 컴포넌트에 대해서는 전혀 신경 쓸 필요가 없다.

소프트웨어가 변경되더라도 해당 컴포넌트는 여전히 기대한 대로 동작할 것이기 때문이다.

 

하지만 안타깝게도 변경할 이유라는 것은 컴포넌트 간의 의존성을 통해 너무도 쉽게 전파된다.

 

컴포넌트를 변경하는 이유가 되는 각각의 의존성

 

컴포넌트 A는 여러 컴포넌트에 의존하는 반면, 컴포넌트 E는 의존하는 것이 전혀 없다.

 

컴포넌트 E를 변경해야 할 이유는 새로운 요구사항에 의해 기능을 변경해야 할 때뿐이다.

반면, 컴포넌트 A는 여러 컴포넌트에 의존하고 있기 때문에 다른 컴포넌트의 변경으로 인해 함께 변경되어야 한다.

 

단일 책임 원칙의 위반으로 발생되는 문제

시간이 지날 수록 변경하기가 더 어려워지고, 그로 인해 변경 비용도 증가한다.

시간이 지날 수록 컴포넌트를 변경해야 할 더 많은 이유가 쌓여간다.

변경해야 할 이유가 많이 쌓인 후에는 하나의 컴포넌트를 변경하는 것이 다른 컴포넌트가 실패하는 원인으로 작용할 수 있다.

 

2. 의존성 역전 원칙

계층형 아키텍처에서 계층 간 의존성은 항상 아래 방향으로 향한다.

단일 책임 원칙을 고수준에서 적용할 때 상위 계층들이 하위 계층들에 비해 변경해야 할 이유가 더 많다는 것을 알 수 있다.

 

영속성 계층에 대한 도메인 계층의 의존성 때문에 영속성 계층을 변경할 때마다 잠재적으로 도메인 계층도 변경해야 한다.

그러나 도메인 코드는 애플리케이션에서 가장 중요한 코드로, 영속성 계층 변경에 영향을 받으면 안된다.

 

어떻게 의존성을 제거할 수 있을까?

의존성 역전 원칙(Dependency Inversion Principle, DIP)에 답이 있다.

 

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

 

의존성의 양쪽 코드를 모두 제어할 수 있을 때 의존성은 역전시킬 수 있다.

만약 서드파티 라이브러리에 의존성이 있다면, 해당 라이브러리를 제어할 수 없기 때문에 의존성은 역전시킬 수 없다.

 

의존성 역전은 어떻게 동작할까?

도메인 코드와 영속성 코드 간의 의존성을 역전시켜 영속성 코드가 도메인 코드에 의존하고, 도메인 코드를 변경해야 할 이유의 개수를 줄인다.

 

도메인 계층에 영속성 계층의 엔티티, 리포지토리와 상호 작용하는 서비스

 

위 구조를 예로 의존성을 제거해보자.

 

엔티티는 도메인 객체를 표현하고 도메인 코드는 해당 엔티티들의 상태를 변경하는 일을 중심으로 하기 때문에 엔티티를 도메인 계층으로 올린다.

 

그러나 영속성 계층의 리포지토리가 도메인 계층에 있는 엔티티에 의존하게 되기 때문에 두 계층 사이에 순환 의존성(circular dependency)이 생긴다.

해당 부분이 바로 DIP를 적용해야 하는 부분이다.

DIP를 적용하기 위해 도메인 계층에 리포지토리에 대한 인터페이스를 만들고, 실제 리포지토리는 영속성 계층에서 구현한다.

 

도메인 계층의 인터페이스 도입으로 역전된 의존성

 

3. 결론

엔티티를 도메인 계층으로 올리고, 도메인 계층의 인터페이스를 도입함으로써 의존성으로부터 도메인 로직을 해방시켰다.

이것이 바로 다음 챕터에서 살펴볼 두 가지 아키텍처 스타일의 핵심 기능이다.

 

Reference.

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

반응형