헥사고날 아키텍처
12 Aug 2024Hexagonal Architecture에 대해서 공부하고 해당 내용을 정리해보자.
먼저 헥사고날 아키텍처에 대해 알기 전에 계층형 아키텍처에 대해서 알아보자.
계층형 아키텍처란?
계층형 아키텍처는 시스템의 구성 요소를 여러 개의 계층으로 분리하여 각 계층이 특정 역할을 수행하도록 하는 패턴이다.
소프트웨어 개발에서 가장 일반적으로 널리 사용되고 있는 아키텍처다.
유지보수가 용이하고 테스트를 작성하기가 쉽다는 장점이 있다.
계층형 아키텍처의 문제
계층형 아키텍처의 정의를 들었을 때는 딱히 단점은 없어 보인다.
실제로 계층형 아키텍처는 견고한 아키텍처 패턴이다.
계층을 잘 이해하고 구성한다면 웹 계층이나 영속성 계층에 독립적으로 조메인 로직을 작성할 수 있다.
잘 만들어진 계층형 아키텍처는 선택의 폭을 넓히고, 변화하는 요구사항과 외부 요인에 빠르게 적응할 수 있게 해준다.
이런 계층형 아키텍처에 문제는 무엇일까?
- 계층형 아키텍처는 데이터베이스 주도 설계를 유도한다.
- 정의에 따르면 전통적인 계층형 아키텍처의 토대는 데이터베이스다.
- 웹 계층은 도메인 계층에 의존하고, 도멩ㄴ 계층은 영속성 계층에 의존하기 때문에 자연스레 데이터베이스에 의존하게 된다.
- 지름길을 택하기 쉬워진다.
- 계층형 아키텍처에서 적용되는 규칙은 특정한 계층에서는 같은 계층에 있는 컴포넌트나 아래에 있는 계층에만 접근 가능하다는 것이다.
- 만약 상위 계층에 위치한 컴포넌트에 접근해야 한다면 컴포넌트 계층을 아래로 내려버리면 된다. -> 지름길
- 테스트하기 어려워진다.
- 엔티티의 필드를 단 하나만 조작하면 되는 경우에 웹 계층에서 바로 영속성 계층에 접근하면 도메인 계층을 건드릴 필요가 없지 않을까? 라고 생각할 수도 있다.
- 한 두번은 괜찮지만 점점 해당 작업은 문제가 생긴다.
- 단 하나의 필드를 조작하는 것이 불과하더라도 도메인 로직을 웹 계층에 구현하는 것은 아키텍처를 제대로 활용하지 못하는 것이며, 테스트를 작성할 때 웹 계층 테스트에서 다른 계층에 대한 의존성(모킹 등)이 발생할 수 있다.
- 유스케이스를 숨긴다.
- 유스케이스가 간단해서 도메인 계층을 생략한다면 다른 계층에 존재할 수도 있기 때문에 새로운 기능을 추가할 적당한 위치를 찾기 어려워진다.
- 계층형 아키텍처는 도메인 서비스의 너비에 관한 규칙을 강제하지 않는다.
- 넓은 서비스는 영속성 계층에 많은 의존성을 갖게 되고, 다시 웹 레이어의 많은 컴포넌트가 이 서비스에 의존하게 된다.
- 동시 작업이 어려워진다.
- 계층형 아키텍처는 여러 개발자가 동시에 작업하기가 어렵다.
- 모든 것이 영속성 계층 위에 만들어지기 때문에 영속성 계층을 먼저 개발해야 하고, 그 다음에 도메인 계층, 마지막으로 웹 계층을 만들어야 한다.
계층형 아키텍처는 올바르게 사용하면 유지보수하기 쉬워지지만 많은 것들이 잘못된 방향으로 흘러가도록 용인한다.
헥사고날 아키텍처는 이러한 계층형 아키텍처의 문제를 해결해준다.
헥사고날 아키텍처란?
- 헥사고날 아키텍처는 소프트웨어 설계 패턴 중 하나로, 소프르트웨어 애플리케이션을 비즈니스 로직과 외부 요소를 명확하게 분리해 독립성과 확장성을 높이려는 아키텍처다.
- 헥사고날 아키텍처는 비즈니스 로직이 중심이 되어, 그 외부에 여러 개의 포트와 어댑터가 둘러싸고 있는 구조다.
- 이를 통해 애플리케이션은 비즈니스 로직과 외부 시스템 간의 연결 방식을 변경하기 쉬워진다.
- 핵심 비즈니스 로직이 독립적으로 구현되어 있어 외부 시스템과 무관하게 동작한다.
- 외부 시스템과 독립적이기 때문에 테스트가 용이하며, 특정 포트나 어댑터만 교체해도 전체 시스템에 영향을 주지 않는다.
- 클린 아키텍처에서는 설계가 비즈니스 규칙의 테스트를 용이하게 하고, 비즈니스 규칙은 프레임워크, 데이터베이스, UI 기술, 그 밖의 외부 애플리케이션이나 인터페이스로부터 독립적일 수 있다.
- 이 아키텍처에서 가장 중요한 규칙은 의존성 규칙으로, 계층 간의 모든 의존성이 안으로 향해야 한다는 것이다.
- 이러한 아키텍처는 대가가 따른다. 예를 들어 도메인 계층과 영속성 계층이 데이터를 주고 받을 때, 두 엔티티를 서로 변환해야 한다.
- 하지만 다시 바꿔서 생각해보면 도메인 코드를 영속성 계층과의 결합이 제거된 상태이므로 바람직한 결과라고도 생각할 수 있다.
예제 코드
먼저 대표적인 헥사고날 아키텍처의 구조를 확인해보자.
이러한 아키텍처를 토대로 예제 코드의 구조를 설계한 구조이다.
먼저 Front에서 해당 헥사곤으로 API 요청을 할 수 있게 Adapter, port를 구현해보자.
다음으로 User 서비스에 접근할 수 있게 application 에서 usecase를 정의하자.
application 에 CreateUserService를 정의한다.
UserDomain의 로직을 가져다 사용한다.
헥사곤의 핵심인 UserDomain을 정의한다.
이제 도메인 로직을 처리했고 결과도 나왔으니 UserPersistencePort와 외부 Persistence 어댑터로 결과를 보내자.
외부 Persistence 코드를 정의한다.