본문 바로가기
개발 방법론

헥사고날 아키텍처와 어댑터-포트 아키텍처 소개

by 시니성 2023. 9. 5.

헥사고날 아키텍처는 어플리케이션의 핵심 로직을 기술적인 세부 사항으로부터 격리시키는 설계 패턴입니다. 이 아키텍처는 중심에 위치한 애플리케이션의 비즈니스 로직을 기술적인 세부 사항(예: 프레임워크, UI, 데이터베이스)으로부터 격리시켜 변경에 유연하게 만듭니다.

주요 구성요소

  • Entity: 애플리케이션의 핵심 비즈니스 로직을 포함하는 도메인 객체입니다.
  • UseCase: 애플리케이션의 유스케이스를 구현하는 로직입니다.
  • Port: 애플리케이션과 외부 세계(예: 웹, 데이터베이스) 사이의 인터페이스입니다.
    • Incoming Port: 애플리케이션으로 들어오는 요청을 받는 인터페이스입니다.
    • Outgoing Port: 애플리케이션에서 외부로 요청을 보내는 인터페이스입니다.
  • Adapter: 포트를 통해 애플리케이션과 외부 세계를 연결하는 구현체입니다.

예시 시나리오

상품을 조회하는 애플리케이션을 만들어 보겠습니다.

1. Entity

// Product.kt
data class Product(val id: Long, val name: String, val price: Double)

2. UseCase

// GetProductUseCase.kt
interface GetProductUseCase {
    fun getProductById(id: Long): Product?
}

// GetProductService.kt
class GetProductService(val productRepository: ProductRepositoryPort) : GetProductUseCase {
    override fun getProductById(id: Long): Product? {
        return productRepository.findById(id)
    }
}

3. Port

  • Incoming Port: 외부에서 상품 조회 요청을 받습니다.
// Incoming.kt
interface ProductQueryPort {
    fun getProduct(id: Long): Product?
}
  • Outgoing Port: 상품 정보를 데이터베이스에서 조회하는 요청을 보냅니다.
// Outgoing.kt
interface ProductRepositoryPort {
    fun findById(id: Long): Product?
}

4. Adapter

  • Incoming Adapter: Spring Controller로 구현합니다.
// ProductController.kt
@RestController
class ProductController(val getProductUseCase: GetProductUseCase) {

    @GetMapping("/product/{id}")
    fun getProduct(@PathVariable id: Long): ResponseEntity<Product> {
        val product = getProductUseCase.getProductById(id)
        return ResponseEntity.ok(product)
    }
}
  • Outgoing Adapter: Spring Data Repository로 구현합니다.
// ProductRepositoryAdapter.kt
interface ProductRepositoryAdapter : JpaRepository<Product, Long>, ProductRepositoryPort {
    override fun findById(id: Long): Product? = getOne(id)
}

이렇게 헥사고날 아키텍처를 통해 우리는 애플리케이션의 핵심 로직을 외부 세계로부터 격리시킬 수 있습니다. 이로써 변경에 더 유연하게 대응할 수 있게 되었습니다.

: 이 예제는 간소화된 형태입니다. 실제로는 예외 처리, 서비스 계층, DTO 등 여러 추가적인 부분이 필요할 수 있습니다. 또한 프론트엔드 부분은 React, Redux 등의 스택을 사용하여 구현될 수 있습니다.