Domain Layer에서 비즈니스 로직 처리하기

신광진·2021년 6월 5일
2
post-thumbnail

OVERVIEW

이번 포스팅에서는 Domain Layer를 이용해서 비즈니스 로직을 처리해야 하는 이유와 간단한 예제를 공부한다.

Spring Web 계층구조

우선 Spring의 Web 계층구조에 대해 살펴보자.

  • Web Layer
    • Controller, JSP/Freemarker 등의 뷰 템플릿 영역이다.
    • 이외에도 필터, 인터셉터, 컨트롤러 어드바이스 등 외부 요청과 응답에 대한 전반적인 영역을 의미한다.
  • Service Layer
    • @Service에 사용되는 서비스 영역이다.
    • 일반적으로 Controller와 Dao의 중간 영역에서 사용된다.
  • Repository Layer
    • Database와 같이 데이터 저장소에 접근하는 영역이다.
  • Dtos
    • Dto(Data Transfer Object)는 계층 간에 데이터 교환을 위한 객체들의 영역을 의미한다.
    • 예를 들어 뷰 템플릿 엔진에서 사용될 객체나 Repository Layer에서 결과로 넘겨준 객체 등이 이에 해당한다.
  • Domain Model
    • Domain이라 불리는 개발 대상을 모든 사람이 동일한 관점에서 이해할 수 있고 공유할 수 있도록 단순화시킨 것을 Domain Model이라고 한다.
    • 택시 앱이라고 하면 배차, 탑승, 요금 등이 모두 도메인이 될 수 있다.
    • 반드시 데이터베이스의 테이블과 관계가 있어야 하는 것은 아니다. VO처럼 값 객체들도 이 영역에 해당하기 때문이다.

비즈니스 로직은 어디에서 처리할까?

나는 비즈니스 로직은 Servier Layer에서 처리되어야 한다고 배웠다.
하지만 이 책에서는 Domain Layer에서 비즈니스 로직이 처리되어야 한다고 얘기하고 있다.
왜 Service Layer가 아닌 Domain Layer에서 비즈니스 로직을 처리해야 한다고 말하는지 두 방식을 예제코드로 비교해보자

Service Layer에서 비즈니스 로직 처리하기

@Transactional
public Order cancelOrder(int orderId) {
	
    // 1)
    OrderDto order = orderDao.selectOrders(orderId);
    BiliingDto billing = billingDao.selectBilling(orderId);
    DeliveryDto delivery = deliveryDao.selectDelivery(orderId);
    
    // 2)
    String deliveryStatus = delivery.getStatus();
    
    // 3)
    if("IN_PROGRESS".equals(deliveryStatus)) {
    	delivery.setStatus("CANCEL");
        deliveryDao.update(delivery);
    }
    
    // 4)
    order.setStatus("CANCEL");
    orderDao.update(order);
    
    billing.setStatus("CANCEL");
    deliveryDao.update(billing);
    
    return order;
}

Service Layer에서 비즈니스 로직을 처리하는 예제코드이다.
모든 로직이 서비스 클래스 내부에서 처리된다.
그러다 보니 서비스 계층이 무의미하며, 객체는 단순히 데이터 덩어리 역할만 하게된다.
이 비즈니스 로직을 도메인 모델에서 수행하도록 해보자

Domain Model에서 비즈니스 로직 처리하기

@Transactional
public Order cancelOrder(int orderId) {
	
    // 1)
    Orders order = ordersRepository.findById(orderId);
    Billing billing = billingRepository.findByOrderId(orderId);
    Delivery delivery = deliveryRepository.findByOrderId(orderId);
    
    // 2-3)
    delivery.cancel();
    
    // 4)
    order.cancel();
    billing.cancel();
    
    return order;
}

취소 이벤트를 처리하는 로직은 각각의 Domain Model에서 수행하고 있다.
Service Layer에서는 트랜잭션과 도메인 간의 순서만을 보장한다.

개인적인 생각

가장 큰 차이점은 객체를 얼마나 활용했는가라고 생각한다.
Service Layer에서 로직을 처리할 때는 객체는 쿼리 결과를 가지고 있는 상자정도로 사용되는 것 같다.
하지만 Domain Model에서 로직을 처리할 때는 각각의 객체들이 자신의 이벤트를 처리하는 것을 볼 수 있다.
즉, Domain Model에서 로직을 처리하는 방식이 객체를 더욱 활용하는 방법이라는 것이다.

하지만 JPA가 아닌 MyBatis를 사용하는 경우에는 Domain Model에서 비즈니스 로직을 처리하기는 방법을 사용하는 것이 쉽지 않아보인다.

결론적으로 두 가지 방법 모두 좋지만 객체지향관점에서는 Domain Model에서 비즈니스 로직을 처리하는 것이 좋다고 생각한다.

profile
이거 왜안되냐

0개의 댓글