헥사고날 아키텍쳐
목표 : 응용 프로그램의 비즈니스 로직을 외부 세계로부터 격리시켜 유연하고 테스트하기 쉬운 구조를 만드는 것
핵심 비즈니스 로직은 중앙의 도메인 영역에 위치하며, 입력과 출력을 처리하는 포트와 어댑터를 통해 외부와 소통한다.
헥사고날 아키텍쳐의 장단점
장점
- 유연성 : 외부 시스템이나 인프라와의 의존성을 낮추어, 구성 요소를 쉽게 교체하거나 업데이트 할 수 있다.
- 테스트 용이성 : 비즈니스 로직을 독립적으로 테스트할 수 있어 품질 향상과 개발 속도 향상에 도움이 된다.
- 유지보수성 : 책임이 분리되어 있어, 코드의 이해와 수정이 용이하며, 변화에 빠르게 대응할 수 있다.
단점
- 구현 복잡성 : 포트와 어댑터를 구성하고 관리하는데 약간의 복잡성이 따른다.
- 초반 개발 시간 증가 : 아키텍처를 처음 구축할 때 시간과 노력 필요
헥사고날 아키텍쳐 구조
포트 (인터페이스)
포트는 애플리케이션 코어의 경계를 정의하며, 애플리케이션 코어가 제공해야 할 기능을 나타내며 어댑터를 통해 애플리케이션 코어에 접근하는 인터페이스이다.
Input Port : 외부 요청이 애플리케이션 코어로 들어오는 경로를 정의한다. 예를 들어, 웹 요청, GUI 이벤트, 스케줄링 이벤트 등이 인커밍 포트를 통해 애플리케이션 코어로 들어올 수 있다.
- Spring Web MVC의 Controller와 Service 사이의 인터페이스
Output Port : 애플리케이션 코어가 외부 세계에 서비스를 제공하기 위한 경로를 정의한다. 예를들어 데이터베이스, 메시징 시스템, 웹 서비스 등에 데이터를 전송하거나 요청하는 경우에 사용한다.
- Spring web MVC의 Repository와 Service 사이의 인터페이스
어댑터 (구현체)
어댑터는 포트를 통해 애플리케이션 코어와 외부 세계를 연결한다. 어댑터는 특정 외부 기술이나 프레임워크에 의존적인 로직을 담당하며, 이를 통해 애플리케이션 코어는 외부와의 결합도를 최소화하고, 어댑터를 통한 교환 가능성을 확보한다.
Input Adapter : 사용자 인터페이스, 테스트 또는 외부 시스템으로부터의 요청을 애플리케이션 코어로 주도하는데 사용된다.
- Spring Web MVC의 Controller
Output Adapter : 애플리케이션 코어에서 외부에 데이터를 전달하는 역할을 담당한다. 예를들어, 데이터베이스에 데이터를 저장하거나 외부 시스템에 메세지를 전송하는 등의 역할을 한다.
- Spring Web MVC의 Repository
유즈케이스
Clean Architecture에서 사용하는 용어로 Spring Web MVC의 Service 영역에 해당한다.
헥사고날 아키텍쳐 예시
Kafka와 같은 외부 시스템과 연동하는 경우 헥사고날 아키텍쳐의 장점을 알 수 있다.
3계층 아키텍쳐에서 kafka 적용
// KafkaProducer.java
public class KafkaProducer {
public void send(User user) {
// 카프카에 사용자 정보 전송
}
}
// UserService.java
public class UserService {
private UserRepository userRepository;
private KafkaProducer kafkaProducer;
public UserService(UserRepository userRepository, KafkaProducer kafkaProducer) {
this.userRepository = userRepository;
this.kafkaProducer = kafkaProducer;
}
public void createUser(String name, String email) {
User user = new User(name, email);
userRepository.save(user);
kafkaProducer.send(user);
}
}
헥사고날 아키텍쳐에서 kafka 적용
// OutputPort.java
public interface OutputPort {
void sendMessage(User user);
}
// KafkaAdapter.java
public class KafkaAdapter implements OutputPort {
private KafkaProducer kafkaProducer;
public KafkaAdapter(KafkaProducer kafkaProducer) {
this.kafkaProducer = kafkaProducer;
}
public void sendMessage(User user) {
kafkaProducer.send(user);
}
}
// CreateUserUseCaseImpl.java
public class CreateUserUseCaseImpl implements CreateUserUseCase {
private UserRepository userRepository;
private OutputPort outputPort;
public CreateUserUseCaseImpl(UserRepository userRepository, OutputPort outputPort) {
this.userRepository = userRepository;
this.outputPort = outputPort;
}
public void createUser(String name, String email) {
User user = new User(name, email);
userRepository.save(user);
outputPort.sendMessage(user);
}
}
기존 아키텍쳐의 경우 UserService 클래스가 카프카와 직접 연결되어 있다. 이 경우 UserService는 Kafka에 대한 의존성을 가지게 된다.
반면 헥사고날 아키텍쳐에서는 OutputPort 인터페이스를 통해 외부 시스템과의 의존성을 분리한다.
이러한 구조를 통해 외부 시스템 변경이 있을 때에도 비즈니스 로직에 영향을 최소화 하고 유연성을 확보할 수 있다.
만약 메세지 서비스를 Kafka에서 RabbitMQ로 변경한다고 생각해보자.
기존 3계층 아키텍쳐의 경우 KafaProducer라는 클래스를 직접 의존하고 있기에, RabbitMQProducer라는 새로운 클래스를 생성하고 이를 사용하게 될 것이다.
하지만 핵사고날 아키텍쳐에서는 Output Port의 구현체를 KafkaAdapter 에서 새로 생성한 RabbitMQAdapter로 변경해주면 비즈니스 로직의 변화 없이 구현체만 바꾸는 것으로 빠르게 대응할 수 있을 것이다.
마무리
블로그 탐색중에 헥사고날 아키텍쳐라는 새로운 키워드를 발견하여 이에대해 간단히 조사해 보았다. 키워드를 발견했을때는 아키텍쳐에 깜짝 놀랄만한 변화가 있을 것 같았지만, 읽어보니 느낀점은 Spring 웹 서비스에서는 메세징 서비스와 같은 외부와 통신하는 부분을 한번 더 인터페이스로 감싸서 접근하는 방식으로 의존성을 줄인 것이라는 느낌이 든다.
아직 경험이 많이 부족하여 크게 와닿지 않는 것 같지만, 소스코드 탐색중에 Port, Adapter, UseCase와 같은 생소한 단어가 나와도 대응할 수 있는 얕은 지식이 생겼다. 또한, 다음 서비스를 개발 할 때 위 처럼 외부와 통신하는 서비스의 변경을 고려한 설계를 하게 된다면, 헥사고날 아키텍쳐를 도입하는 것을 고려해 볼 수 있을 것 같다.
Reference
https://tech.osci.kr/hexagonal-architecture/
https://velog.io/@coconenne/%ED%97%A5%EC%82%AC%EA%B3%A0%EB%82%A0-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%96%B4%EB%8C%91%ED%84%B0%EC%99%80-%ED%8F%AC%ED%8A%B8-%EA%B2%B0%ED%95%A9%EB%8F%84%EB%A5%BC-%EB%82%AE%EC%B6%B0%EB%B3%B4%EC%9E%90
'TIL' 카테고리의 다른 글
구글 코랩에서 Stable Diffusion WebUI API 호출하기 (2) | 2024.10.18 |
---|---|
2024.09.27 (6) | 2024.09.27 |
Retry 전략 (7) | 2024.09.25 |
Vite, Webpack, Babel 관계 정리 (0) | 2024.05.24 |
자바스크립트 비동기 처리 알아보기 (3) | 2024.04.01 |