헥사고날 아키텍처(Hexagonal Architecture) : 지속 가능한 소프트웨어 설계

포트와 어댑터 아키텍처 라고도 불리는 헥사고날 아키텍처(Hexagonal Architecture) 인터페이스나 기반 요소(infrastructure)의 변경에 영향을 받지 않는 핵심 코드를 만들고 이를 견고하게 관리할 수 있도록 해준다. 

 

헥사고날 아키텍처를 설명하기전에 계층형 아키텍처와 클린 아키텍처, 그리고 도메인 주도 설계(DDD)에 대해서도 언급이 필요하다.

 

 

헥사고날 아키텍처는 전통 방식인 계층형 아키텍처의 단점을 보완하기 위해 설계되었다.

 

 

 

 

 

기존 계층형 아키텍처의 문제점은 무엇일까?

1. 데이터베이스, 영속성에 대한 의존성

도메인 계층이 데이터베이스에 의존하게 되어 데이터베이스에 변화가 일어나면 도메인 계층에도 변화가 생긴다. 서비스 계층에서도 영속성 모델을 도메인 모델처럼 사용하게 된다. 그렇다면 즉시로딩, 지연로딩, 트랜잭션, 플러시 등을 고려해야하고 영속성에 대한 의존이 프로젝트 전체적으로 퍼지게 되어 변경에 취약해진다.

 

 

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String username;

    // 즉시로딩, 지연로딩 등이 필요한 필드들
    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;
}




@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public User findUserByUsername(String username) {
        User user = userRepository.findByUsername(username);

        // 영속성 모델을 도메인 모델처럼 사용
        List<Order> orders = user.getOrders(); // 지연 로딩 문제 발생 가능

        return user;
    }
}

 

위 코드에선 몇 가지 문제점이 있다.

 

첫번째로 도메인 계층이 영속성 모델에 의존하고 있다.

UseService에서 User 엔티티를 직접 사용하고 있는데, 이처럼 도메인 계층이 데이터베이스와 영속성에 지나치게 의존할 경우, 데이터베이스에 대한 변경이 생기면 도메인 계층과 서비스 계층에도 영향을 미친다.

 

 

두번째로 영속성 관련 문제가 확산된다.

User 엔티티의 orders 필드는 LAZY로 설정되어 있어 지연 로딩이 발생할 수 있다. 지연 로딩이나 즉시 로딩과 같은 영속성 관련 문제를 도메인 로직에서 고려해야 하므로, 트랜잭션 범위 밖에서 접근할 경우 예외가 발생할 수 있다.

 

JPA는 트랜잭션 내에서만 데이터베이스와의 상호작용을 허용하므로, 지연 로딩된 필드에 접근할 때 트랜잭션이 존재하지 않으면 문제를 일으킨다.

 

 

세번째로 변경에 대해 취약하다. 만약 User 엔티티의 구조가 변경되면, 이를 사용하는 모든 코드에 수정이 필요하다. 이런 문제는 서비스 게층과 영속성 계층이 강하게 결합되어 있기 때문에 발생한다.

 

 

 

2. 아키텍처 경계를 강제할 수 없음

계층형 아키텍처에서는 상위 계층에 있는 컴포넌트에 접근할 목적으로 해당 컴포넌트를 하위 계층으로 내릴 수 있다. 이러한 행위가 반복되면 점점 경계가 모호해지고 허물어지게 된다.

 

 

3. 계층을 스킵 할 수 있음

 

위 사진 처럼 계층을 건너뛰는 것이 가능하다. 구현이 간단한 경우 Controller에서 바로 도메인을 참조하는 등의 로직을 작성할 수 있다. 이 경우의 문제는 기능 확장이 어렵고, 테스트가 복잡해진다.

 

 

4. 유스케이스가 숨겨질 수 있다.

개발자는 유스케이스를 어느 계층에나 자유롭게 생성할 수 있다. 이는 개발자가 유스케이스의 존재 여부를 파악하기 어려워서 동일한 로직을 다른 위치에 새롭게 구현하여 코드를 더럽히게 된다.

 

 

5. 서비스의 크기를 강제할 수 없다.

계층형 구조에선 서비스의 크기를 강제하지 않는다.

수십개의 서비스 로직을 한 곳에 전부 작성할 수도 있다. 이 경우 서비스 계층엔 너무 많은 의존을 가져 수많은 웹 계층이 해당 서비스를 의존하게 된다.

 

 

 

계층형 아키텍처는 데이터베이스 주도 설계를 유도한다. 

 

위 그림에서 보았듯이 계층형 아키텍처의 제일 토대에는 영속성이 있고 이는 곧 설계의 토대가 데이터베이스에 있다고 볼 수 있다.

 

좋은 객체지향 설계를 위해서는 각 객체가 수행해야 할 역할과 행동들을 중심으로 객체간 관계를 모델링 해야 한다. 그리고 모델링한 행동들에 따라 어플리케이션의 상태가 변경된다.

하지만 계층형 아키텍처에서 의존성의 방향이 아래 계층을 향하고 최하단에는 데이터베이스 관련 레이어가 존재하기 때문에 데이터베이스의 구조를 먼저 생각하고 이를 토대로 도메인 로직을 구현합니다.

 

하지만 비즈니스 관점에서는 데이터베이스 주도 설계는 옳지 않은 방법이다. 도메인 로직을 구성하고 로직을 제대로 이해했는지 먼저 확인하지 않고 영속성 계층과 웹 계층을 만들게 된다. 데이터 베이스 계층을 중심으로 아키텍처가 만들어지는 이유는 ORM을 사용하기 때문이다.

 

 

 

 

 

 

클린 아키텍처란?

 

클린 아키텍처에 대해 잠깐 살펴보면 비즈니스 규칙이 외부로부터 독립적으로 만들어 테스트를 용이하게 하고, 비즈니스 규칙이 외부의 영향을 받지 않도록 하는 아키텍처이다.

 

 

클린 아키텍처는 다음과 같은 특징이 있다.

  • 도메인 코드가 바깥으로 향하는 어떠한 의존성도 없어야 한다. 즉, 모든 의존성은 안쪽을 향하고 있다.
  • 도메인은 어떤 영속성 프레임워크가 사용되는지 알 수 없다.
  • 영속성 계층이 도메인 게층에 의존하고, 영속성 엔티티를 도메인 엔티티로 변환하는 과정이 필요하다.
  • 도메인 밖에는 유스케이스가 있고, 이는 단일 책임을 갖기 위해 조금 더 세분화 되어 있다.

 

 

 

 

 

헥사고날 아키텍처(Hexagonal Architecture) 란? 

 

 

헥사고날 아키텍처클린 아키텍처를 일반화한 구조 중 하나이며, 유지보수성확장성을 높이기 위해 고안되었다. 클린 아키텍처를 구체화한게 헥사고날 이라 설명하는 사람도 있다.

 

헥사고날 아키텍처는 어댑터와 포트를 중심으로 구성되어 있다. 이를 통해 비즈니스 로직을 외부로부터 격리시켜 외부 시스템과 의존성을 최소화 한다.

 

 

 

- 핵심 비즈니스 로직은 중앙의 도메인 영역에 위치하며, 입출력을 처리하는 포트와 어댑터를 통해 외부와 소통한다.

- 도메인 로직과 인프라 스트럭처 계층을 명확히 분리함으로써 변경 사항이 도메인 로직에 미치는 영향을 줄일 수 있다.

- 해당 구조는 유지보수를 용이하게하여 시스템의 다양한 부분을 독립적으로 개발하고 테스트할 수 있는 환경을 제공한다.

- 헥사고날 아키텍처는 도메인 중심 설계와 밀접하게 연관되어있어 비즈니스 로직의 중심성을 강조한다.

 

 

 

 

헥사고날 아키텍처와 도메인 주도 설계는 왜 밀접하게 연관되어 있다고 하는걸까?

도메인 주도 설계는 소프트웨어 개발에서 비즈니스 도메인의 복잡성을 관리하는 방법론이다.

헥사고날 아키텍처는 이런 방법론을 보완해준다.

 

DDD는 도메인 모델 중심으로 시스템을 설계하고, 헥사고날 아키텍처는 이러한 도메인 모델을 효과적으로 구현할 수 있는 구조를 제공한다.

 

 

DDD를 실제로 구현할 때에는 크게 3가지 Layer로 구분하는 것이 핵심이다.

 

Application Layer: 주로 도메인과 Repository를 바탕으로 실제 서비스(API)를 제공하는 계층

Domain Model Layer: Entity를 활용해 도메인 로직(비즈니스 로직)이 수행되는 계층

Infrastructure Layer: 외부와 통신(RDBMS, Redis, HttpClient, ...)을 담당하는 계층

 

 

DDD를 적용함으로써 개발자는 비즈니스 로직을 더 깊이 이해할 수 있다.

 

이 과정에서 헥사고날 아키텍처는 도메인 로직과 인프라 스트럭처 사이의 결합도를 낮추는 역할을 한다. 도메인 로직을 중심으로 시스템을 구성하며 이를 통해 요구사항의 변경이 시스템 전체에 미치는 영향을 최소화할 수 있기 때문이다.

 

 

 

헥사고날 아키텍처 장단점

장점

  • 유연성 : 외부 시스템이나 인프라와의 의존성이 낮아 구성요소를 쉽게 교체하거나 업데이트가 가능
  • 테스트 용이성 : 비즈니스 로직을 독립적으로 테스트할 수 있음
  • 유지보수성 : 책임이 분리되어 있어 코드의 이해와 수정이 용이

단점

  • 구현 복잡성 : 포트와 어댑터를 구성하고 관리하는데 복잡함
  • 초기 개발 시간 증가

 

 

 

마치며..

헥사고날 아키텍처를 실제로 적용해 본 적이 없다. 그래서 흔히들 말하는 헥사고날 아키텍처의 장단점이 아직 크게 와닿지는 않는다.

 

직접 헥사고날 아키텍처 기반의 프로젝트를 코드로 보고, 실제로 작성해봐야 그 차이를 확실히 이해할 수 있을 것 같다.

 

계층형 아키텍처와 클린 아키텍처를 적용해 프로젝트를 진행하면서 느꼈던 불편함이나 애매함, 그리고 어려움은 다른 개발자들도 많이 겪고 고민하고 있다는 것을 알게 되었다.

 

 

 

세상에 완벽한 아키텍처는 없다. 헥사고날 아키텍처도 불편한 점, 아쉬운 점이 분명히 존재하겠지만, 다양한 아키텍처에 대한 지식을 넓혀가면서 더 효율적인 개발 방법을 찾기 위해 꾸준히 관심을 기울일 생각이다.