본문 바로가기

Spring

의존성 역전하기와 육각형 아키텍쳐

1) 단일 책임 원칙

- 일반적으로 단일 책임 원칙은

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

  고 하지만, 이는 단일 책임 원칙의 실제 의도는 아닙니다.

  단일 책임 원칙의 실제 정의는

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

  즉, 단일 책임 원칙을 '단일 변경 이유 원칙'으로 바꿔야 할 수도 있습니다. 

 

- 만약 컴포넌트를 변경할 이유가 한 가지라면 우리가 어떤 다른 이유로 소프트웨어를 

  변경하더라도 이 컴포넌트에 대해서는 전혀 신경 쓸 필요가 없습니다. 

 

- 많은 코드는 단일 책임 원칙을 위반하기 때문에 시간이 갈수록 변경하기가 더 어려워지고,

  그로 인해 변경 비용도 증가합니다. 

  시간이 갈수록 컴포넌트를 변경할 더 많은 이유가 쌓여갑니다. 

  변경할 이유가 많이 쌓인 후에는 한 컴포넌트를 바꾸는 것이 다른 컴포넌트가 실패하는 원인으로

  작용할 수 있습니다. 

 

 

2) 의존성 역전 원칙

- 계층형 아키텍처에서 계층 간 의존성은 항상 다음 계층인 아래 방향을 가리킵니다.

  단일 책임 원칙을 고수준에서 적용할 때, 상위 계층들이 하위 계층들에 비해

  변경할 이유가 더 많다는 것을 알 수 있습니다. 

 

- 그러므로 영속성 계층에 대한 도메인 계층의 의존성 때문에 영속성 계층을 변경할 때마다

  잠재적으로 도메인 계층도 변경해야 합니다. 

  그러나 도메인 코드는 애플리케이션에서 가장 중요한 코드입니다.

  따라서 영속성 코드가 바뀐다고 해서 도메인 코드까지 바꾸고 싶지는 않습니다.

 

- 의존성 역전 원칙이 답을 알려줍니다.

  의존성 역전 원칙은 '코드 상의 어떤 의존성이든 그 방향을 바꿀 수 있다'는 것입니다.

 

- 사실 의존성의 양쪽 코드를 모두 제어할 수 있을 때만 의존성을 역전시킬 수 있습니다.

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

  의존성은 역전시킬 수 없습니다. 

 

- 의존성 역전은 도메인 코드와 영속성 코드 간의 의존성을 역전시켜서 

   영속성 코드가 도메인 코드에 의존하고, 도메인 코드를 '변경할 이유'의 개수를 줄이는 것입니다.

 

- 즉, 도메인 계층에 인터페이스를 도입함으로써 의존성을 역전시킬 수 있고,

  그 덕분에 영속성 계층이 도메인 계층에 의존하게 됩니다. 

 

 

3) 클린 아키텍쳐

- 로버트 C. 마틴은 '클린 아키텍쳐'라는 책에서 설계가 비즈니스 규칙의 테스트를 용이하게 하고,

  비즈니스 규칙은 프레임워크, 데이터베이스, UI 기술, 그 밖의 외부 애플리케이션이나 인터페이스로부터

  독립적일 수 있다고 이야기했습니다.

 

- 이는 도메인 코드가 바깥으로 향하는 어떤 의존성도 없어야 함을 의미합니다. 

  대신 의존성 역전 원칙의 도움으로 모든 의존성이 도메인 코드를 향하고 있습니다. 

  다음 그림은 클린 아키텍처를 추상화해서 보여줍니다. 

- 이 아키텍처에서 계층들은 동심원으로 둘러싸여 있습니다.

  이 아키텍처에서 가장 중요한 규칙은 의존성 규칙으로, 계층간의 모든 의존성이 안쪽으로 향해야 한다는 것입니다.

 

- 이 아키텍처의 코어에는 주변 유스케이스에서 접근하는 도메인 엔티티들이 있습니다. 

  이 코어 주변으로 비즈니스 규칙을 지원하는 애플리케이션의 다른 모든 컴포넌트들을 확인할 수 있습니다. 

  여기서 '지원'은 영속성을 제공하거나 UI를 제공하는 것 등을 의미합니다. 

  또한 바깥쪽 계층들은 다른 서드파티 컴포넌트에 어댑터를 제공할 수 있습니다. 

 

- 도메인 코드에서는 어떤 영속성 프레임워크나 UI 프레임워크가 사용되는지 알 수 없기 때문에

  특정 프레임워크에 특화된 코드를 가질 수 없고 비즈니스 규칙에 집중할 수 있습니다. 

  그래서 도메인 코드를 자유롭게 모델링 할 수 있습니다.

  예를 들어, 도메인 주도 설계를 가장 순수한 형태로 적용해 볼 수도 있습니다. 

 

- 짐작했을지도 모르지만 클린 아키텍처에는 대가가 따릅니다

   도메인 계층이 영속성이나 UI같은 외부 계층과 철저하게 분리돼야 하므로

   애플리케이션의 엔티티에 대한 모델을 각 계층에서 유지보수해야 합니다. 

 

- 가령 영속성 계층에서 ORM 프레임워크를 사용한다고 해봅시다

   일반적으로 ORM 프레임워크는 데이터베이스 구조 및 객체 필드와

   데이터베이스 칼럼의 매핑을 서술한 메타데이터를 담고 있는 엔티티 클래스를 필요로 합니다. 

 

- 도메인 계층은 영속성 계층을 모르기 때문에 도메인 계층에서 사용한 엔티티 클래스를

   영속성 계층에서 함께 사용할 수 없고 두 계층에서 각각 엔티티를 만들어야 합니다.

   즉, 도메인 계층과 영속성 계층이 데이터를 주고 받을 때, 두 엔티티를 서로 변환해야 합니다. 

   이는 도메인 계층과 다른 계층들 사이에서도 마찬가지입니다. 

 

- 하지만 이것은 바람직한 일입니다. 이것이 바로 도메인 코드를 프레임워크에  특화된 문제로부터 

  해방시키고자 했던, 결합이 제거된 상태입니다. 

  예를 들어, JPA에서는 ORM이 관리하는 엔티티에 인자가 없는 기본 생성자를 추가하도록 강제합니다.

  이것이 바로 도메인 모델에는 포함해서는 안 될 프레임워크에 특화된 결합의 예입니다. 

 

 

4) 육각형 아키텍쳐

- '육각형 아키텍처'라는 용어는 알리스테어 콕번이 만든 용어로,

   꽤 오랫동안 사용되어 왔습니다.

 

- 위의 그림은 육각형 아키텍처가 어떤 모양인지 보여줍니다. 

  애플리케이션 코어가 육각형으로 표현되어 이 아키텍처의 이름이 되었습니다. 

  

- 육각형 안에는 도메인 엔티티와 이와 상호작용하는 유스케이스가 있습니다. 

  육각형에서 외부로 향하는 의존성이 없기 때문에 로버트 C. 마틴이 클린 아키텍처에서 제시한

  의존성 규칙이 그대로 적용됩니다. 

  대신 모든 의존성은 코어로 향합니다

 

- 육각형 바깥에는 애플리케이션과 상호작용하는 다양한 어댑터들이 있습니다. 

  웹 브라우저와 상호작용하는 웹 어댑터도 있고, 일부 어댑터는 외부 시스템과 상호 작용하며,

  데이터베이스와 상호 작용하는 어댑터도 있습니다. 

 

- 왼쪽에 있는 어댑터들은 애플리케이션을 주도하는 어댑터들입니다.

  반면, 오른쪽에 있는 어댑터들은 애플리케이션에 의해 주도되는 어댑터들입니다. 

 

- 애플리케이션 코어와 어댑터들 간의 통신이 가능하려면 애플리케이션 코어가 

  각각의 포트를 제공해야 합니다. 

  주도하는 어댑터(driving adapter)에게는 그러한 포트가

  코어에 있는 유스케이스 클래스들에 의해 구현되고 호출되는 인터페이스가 될 것이고,

  주도되는 어댑터(driven adpater)에게는 그러한 포트가

  어댑터에 의해 구현되고 코어에 의해 호출되는 인터페이스가 될 것입니다.

 

- 이러한 핵심 개념으로 인해 이 아키텍쳐 스타일은 '포트와 어댑터' 아키텍처로도 알려져 있습니다. 

  클린 아키텍처처럼 육각형 아키텍처도 계층으로 구성할 수 있습니다. 

 

참고

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

https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html 

'Spring' 카테고리의 다른 글

롬복 어노테이션과 사용시 주의할 점  (0) 2022.08.26
롬복  (0) 2022.08.21
의존관계 자동 주입  (0) 2022.08.21
컴포넌트 스캔  (0) 2022.08.19
웹 서버와 WAS  (0) 2022.08.14