헥사고날 아키텍처에서 의존 역전 원칙(DIP) - f-lab-edu/msa-commerce-lab GitHub Wiki

DIP 란?

한 줄 요약: 비즈니스 로직이 데이터베이스나 프레임워크에 직접 의존하지 않고, 인터페이스(추상화)를 통해 의존 방향을 뒤집는 것

전통적인 방식 (문제)

OrderService → OrderJpaRepository (JPA에 직접 의존)

비즈니스 로직이 JPA에 종속되어, JPA를 MyBatis로 바꾸면 OrderService까지 수정해야 함

DIP 적용 (해결)

OrderService → OrderRepository (인터페이스) ← OrderJpaRepositoryAdapter (구현체)

비즈니스 로직은 인터페이스만 알고, 구현체는 바꿔 끼울 수 있음

헥사고날 아키텍처에서 어떻게 적용하나요?

핵심 개념: Port와 Adapter

Domain (비즈니스 로직)
    ↓ 의존
Port (인터페이스) ← 여기서 DIP 발생!
    ↑ 구현
Adapter (JPA, REST 등)
  • Port: 도메인이 정의한 인터페이스
  • Adapter: Port를 구현한 구체적인 기술 (JPA, REST API 등)

PR #58에서 적용한 방식

// 1. Port 정의 (domain/port/out/OrderRepository.java)
public interface OrderRepository {
    Order save(Order order);
    Optional<Order> findById(UUID id);
}

// 2. 도메인 서비스는 Port에만 의존
public class OrderService {
    private final OrderRepository orderRepository; // 인터페이스

    public Order createOrder(CreateOrderCommand command) {
        Order order = Order.create(command);
        return orderRepository.save(order);
    }
}

// 3. Adapter가 Port 구현 (infrastructure/adapter/out/persistence/OrderRepositoryImpl.java)
@Repository
public class OrderRepositoryImpl implements OrderRepository {
    private final SpringDataOrderRepository jpaRepository;

    @Override
    public Order save(Order order) {
        // JPA Entity로 변환 후 저장
        OrderEntity entity = mapper.toEntity(order);
        return mapper.toDomain(jpaRepository.save(entity));
    }
}

이렇게 하면 뭐가 좋나요?

  1. 기술 교체 용이: JPA → MyBatis로 바꿀 때 Adapter만 교체
  2. 테스트 쉬움: Mock 객체로 쉽게 테스트 가능
  3. 비즈니스 로직 집중: OrderService는 JPA를 전혀 몰라도 됨

멘토님께 논의하고 싶은 점

  1. 현재 구조가 DIP를 제대로 따르고 있는지?

    • Port가 도메인 계층에 있는지
    • 도메인 모델(Order)을 사용하는지, Entity를 사용하는지
  2. 어디까지 인터페이스를 만들어야 하는지?

    • 모든 Service에 UseCase 인터페이스가 필요한지
    • Repository만 인터페이스면 충분한지
  3. 성능과 설계의 균형

    • 추상화 계층이 성능에 영향을 주지 않는지
⚠️ **GitHub.com Fallback** ⚠️