도메인 주도 개발 시작하기 (5) - 스프링 데이터 JPA를 이용한 조회 기능

Jaewoo Ha·2022년 12월 9일
0

5.1 CQRS 란?

CQRS는 명령 모델과 조회 모델을 분리하는 패턴이다.

명령 모델

  • 상태를 변경하는 기능을 구현할 때 사용
  • 도메인 모델은 명령 모델로 주로 사용

조회 모델

  • 데이터를 조회하는 기능을 구현할 때 사용

5.2 검색을 위한 스펙

  • 검색 조건이 고정되어 있고 단순하면 특정 조건으로 조회하는 기능을 만들 수 있다.
  • 다양한 조건으로 조합해야될 떄마다 정의를 find로 할 필요는 없다.
interface OrderDataDao {
    fun findById(id: OrderNo): OrderData?
    fun findByOrderer(ordererId: String, fromData: Date, toDate: Date): List<OrderData>
}

검색 조건을 다양하게 조합해야할 때 사용할 수 있는 것이 스펙이다. 스펙은 애그리거트가 특정 조건을 충족하는지를 검사할 때 사용하는 인터페이스다.

interface Specification<T> {
    fun isSatisfiedBy(agg: T): Boolean
}

위 코드의 agg 파라미터는 검사 대상이 되는 객체다. 스펙을 레포지터리에 사용하면 agg는 애그리거트 루트가 되고, 스펙을 DAO에 사용하면 agg는 검색 결과로 리턴할 데이터 객체가 된다.

class OrderSpec(private var ordererId: String): Specification<Order> {

    fun OrdererSpec(ordererId: String) {
        this.ordererId = ordererId
    }

    override fun isSatisfiedBy(agg: Order): Boolean {
        return agg.orderId.memberId.id.equals(ordererId)
    }
}

레포지터리나 DAO는 검색 대상을 걸러내는 용도로 스펙을 사용한다. 만약 레포지터리가 메모리에 모든 애그리거트를 보관하고 있다면 다음과 같이 스펙을 사용할 수 있다.

class MemoryOrderRepository: OrderRepository {
    
    fun findAll(spec: Specification<Order>): List<Order> {
        val allOrders = findAll()
        return allOrders.stream()
            .filter { order -> spec.isSatisfiedBy(order)}
            .toList()
    }
}

특정 조건을 충족하는 애그리거트를 찾고 싶으면 원하는 스펙을 생성해서 레포지터리에 전달해 주기만 하면 된다.

결론

실제 스펙은 이렇게 구현하지 않는다. 모든 애그리거트 객체를 메모리에 보관하기도 어렵고 설사 메모리에 보관할 수 있다 하더라도 조회 성능에 심각한 문제가 발생하기 떄문이다. 스펙은 사용하는 기술에 맞춰 구현하면 된다.

5.3 스프링 데이터 JPA를 이용한 스펙 구현

JPA에 있는 specification을 통해 구현한 spec은 아래의 코드와 같다.

class OrderIdSpec(private var ordererId: String): Specification<OrderSummary> {

    fun OrdererSpec(ordererId: String) {
        this.ordererId = ordererId
    }

    override fun toPredicate(
        root: Root<Order>,
        query: CriteriaQuery<*>,
        criteriaBuilder: CriteriaBuilder
    ): Predicate? {
        return criteriaBuilder.equal(root.get(OrderSummary.ordererId), ordererId)
    }
}
profile
내일의 코드는 더 안전하고 깔끔하게

0개의 댓글