OTHER

[OTHER] 헥사고날 아키텍처

집한구석 2022. 9. 6. 13:24
728x90

계층형 아키텍처의 문제 

  • 계층형 아키텍처는 토대가 DB이기 때문에, DB 주도 설계를 유도함
  • 계층형 아키텍처는 DB중심적인 아키텍처이기 때문에 비즈니스 관점에서 맞지 않음 → 도메인 로직을 먼저 만들고 제대로 이해해야하 영속성과 웹계층을 만들 수있음
  • 계층형 아키텍처는 같은 계층에 있는 컴포넌트나 아래 계층에 접근이 가능하기 때문에 암묵적으로 용인하면 영속성 → 도메인으로 접근하는 코드가 늘어나게 됨
  • 계층형 아키텍처는 시간이 지나면서 시스템이 비대해질수록, 계층을 건너뛰어 접근하는 경우도 생기게 되면서, 도메인 로직이 전체에 걸쳐 책임이 섞이게 됨
  • 계층형 아키텍처의 이러한 문제의 해결방법으로는 DIP(의존성 역전법칙)으로 해결을 했었음 → 모든 계층에 DIP로 해결해서 적용하면 헥사고날 아키텍처의 형태를 띄게 됨

계층형 아키텍처에서 헥사고날 아키텍처 진화 과정 

  • 계층형 아키텍처
  • 의존성 역전 법칙을 적용한 계층형 아키텍처
  • 헥사고날 아키텍처

위 이미지 순서처럼 의존성 역전법칙을 통하여 헥사고날 아키텍처 형태로 진화


헥사고날 아키텍처 정의

https://masne.medium.com/hexagonal-architecture-part-1-b8357d3ee17d

  • 헥사고날 아키텍처는 어플리케이션 코어가 육각형으로 표현되기 때문에 정해졌음
  • 어댑터와 연결되는 4개 이상의 면을 가질 수 있음을 보여주기 위해 사각형 대신 육각형(헥사고날)으로 정함
  • 육각형 안에는 도메인 엔티티와 상호작용하는 유스케이스가 있음, 육각형에서 외부로 향하는 의존성이 없고 모든 의존성이 코어로 향함
  • 포트 앤 어댑터 아키텍처라고도 불리기도함

헥사고날 아키텍처 요소 및 구성

포트(port) 인터페이스로 계층간 경계를 지정하는 역할을 함, DI를 위한 추상화
애플리케이션 서비스와 어댑터 사이의 간접적인 계층이며, 계층에 대한 코드의 의존성을 없앰
  • 인풋 포트 : 유스케이스가 인풋포드에 해당
  • 아웃풋 포트 : 영속성 어댑터 인터페이스에 해당 
어댑터(adapter) 포트의 구현체이며 서비스를 호출하거나 서비스에 의해서 호출이 됨
  • 인바운드 어댑터 : 외부 요청 처리 (예시 : 기존 계층형 아키텍처에서 컨트롤러)
  • 아웃바운드 어댑터 : 외부와 연계 (예시 : 영속성 처리하는 repository)
유스케이스


시스템을 사용하는 클라이언트가 그 시스템을 통해 하고자하는 것, 도메인의 비즈니스 로직을 오케스트레이션하는 역할 (인풋 포트)
(예시 : 기존계층형 서비스 역할)
엔티티 도메인에서 다루는 핵심 개체 (예시 : 기존 계층형 아키텍처에서 JPA로 관리되는 엔티티)

헥사고날 아키텍처 예시 

패키지 구조 요약

  • Account 모듈? 에 관련된 패키지
  • domain, adapter, application으로 구성 
  • application 패키지에는 비즈니스 로직을 수행하는 서비스 계층이 포함
  • adapter 패키지는 어플리케이션 계층의 인커밍 포트인 즉 유스케이스를 호출하는 인바운드(웹)어댑터와, 아웃고잉 포트에 대한 구현을 제공하는 아웃바운드 어댑터인 영속성 어댑터를 포함
@WebAdapter
@RestController
@RequiredArgsConstructor
class SendMoneyController {
 
private final SendMoneyUseCase sendMoneyUseCase;
 
@PostMapping(path = "/accounts/send/{sourceAccountId}/{targetAccountId}/{amount}")
public void sendMoney() {
....
 
public interface SendMoneyUseCase {
 
boolean sendMoney(SendMoneyCommand command);    
 
....
 
@RequiredArgsConstructor
@UseCase
@Transactional
public class SendMoneyService implements SendMoneyUseCase {
 
    private final LoadAccountPort loadAccountPort;
    private final AccountLock accountLock;
    private final UpdateAccountStatePort updateAccountStatePort;
    private final MoneyTransferProperties moneyTransferProperties;
 
    @Override
    public boolean sendMoney(SendMoneyCommand command) {   
 
....
 
 
public interface LoadAccountPort {
 
    Account loadAccount(AccountId accountId, LocalDateTime baselineDate);
 
....
 
@RequiredArgsConstructor
@PersistenceAdapter
class AccountPersistenceAdapter implements
        LoadAccountPort,
        UpdateAccountStatePort {
 
    private final SpringDataAccountRepository accountRepository;
    private final ActivityRepository activityRepository;
    private final AccountMapper accountMapper;
 
    @Override
    public Account loadAccount(
                    AccountId accountId,
                    LocalDateTime baselineDate) {
...
  • 해당 구조로 하면 어댑터 같은 경우 쉽게 교체가 가능함 
  • 예를 들어 특정 DB를 변경해야 할 경우 아웃고잉포트들만 새로운 어댑터 패키지에 구현하고 기존 연동된 어댑터를 변경해주면 됨

참고 : https://github.com/wikibook/clean-architecture


헥사고날 아키텍처 요약

  • 계층형 아키텍처인 Controller - Service - Data Layer를 분리하여, 느슨하게 커플링된 어플리케이션을 구성
  • 어플리케이션 전체에 일관된 의존성 규칙을 적용하여, 자신이 코딩하지 않은 코드를 볼 때 비용을 낮춰줌 (유지보수성 증가)
  • 분리된 계층의 의존성을 최소화하여 독립된 테스트를 구성하게 해줌 

'OTHER' 카테고리의 다른 글

[OTHER] 동시성 문제 해결 방법  (0) 2022.09.01
[OTHER] 멱등성  (0) 2022.04.25
[OTHER] Semantic Versioning  (0) 2022.04.07
[OTHER] TDD (테스트 주도 개발론)  (0) 2021.11.14
[OTHER] 마이크로 서비스 아키텍처  (0) 2021.09.28