비즈니스 로직은 어디에서 처리해야 하는가 - 스프링 웹 계층

6

Spring

목록 보기
5/12

많은 사람들이 스프링 웹 계층(Spring Web Layer)에 대해서 오해하고 있는 것이 있다. 바로 Service에서 비즈니스 로직을 처리해야 한다는 것이다.

나 또한 비즈니스 로직은 서비스 계층(Service Layer)에서 처리해야 한다고 알고 있었다.

하지만 서비스 계층은 트랜잭션과 도메인간의 순서만 보장할 뿐 비즈니스 로직을 담당하는 계층이 아니다.

"그럼 비즈니스 로직은 누가 처리하는가" 라고 물을 수 있다.

위의 사진은 스프링 웹 계층의 대표적인 사진이다.

각 계층에 대해서 간단하게 설명하자면 아래와 같다.

  • Web Layer : 뷰 영역이다. 이외에도 필터, 인터셉터, 컨트롤러 어드바이스 등을 이야기 하는 외부 요청과 응답에 대한 전반적인 영역을 이야기한다.

  • Service Layer : Web Layer와 Repository Layer 의 중간 영역이다.

  • Repository Layer : 데이터베이스에 직접적으로 접근하는 계층이다. JPA를 사용하지 않는 사람들은 DAO라고 생각하면 편하다.

  • DTOs : 계층 간의 데이터 교환을 위한 객체이다.

  • Domain Model : 모든 사람이 동일한 관점에서 이해할 수 있고 공유할 수 있도록 단순화 시킨 것이다.

위의 5가지 계층에서 비즈니스 로직을 처리해야 하는 계층은 바로 Domain 이다.

기존의 모든 비즈니스 로직이 서비스 클래스 내부에서 처리된다면 서비스 계층이 무의미해지고, 객체는 데이터를 담고있는 데이터 덩어리 역할만 하게 된다.

반면에 도메인 모델에서 비즈니스 로직을 처리할 경우 각자의 역할만 담당하게 되며 서비스 메소드는 트랜잭션과 도메인 간의 순서만 보장해 줄 수 있다.

따라서 도메인이 비즈니스 로직을 가지고 객체 지향의 특성을 적극적으로 활용하는 것을 도메인 모델 패턴이라고 한다. 이를 활용하면 서비스의 복잡도를 낮추는 효과를 얻을 수 있다.

말로 하면 잘 이해가 안될 수 있다. 코드를 보면서 이해해 보자.


슈도 코드

@Transactional
public Order cancelOrder(int orderId){
	1) 데이터베이스로부터 주문정보, 결제정보 배송정보 조회

	2) 배송 취소를 해야 하는지 확인

	3) if(배송 중이라면){
			배송 취소로 변경
		}
	4) 각 테이블에 취소 상태 Update
}

서비스 계층에서 비즈니스 로직을 처리할 때

@Transactional
public Order cancelOrder(int orderId){
	
	OrderDto order = ordersDao.selectOrders(orderId);
	BillingDto billing = billingDao.selectBilling(orderId);
	DeliveryDto delivery = deliveryDao.selectDelivery(orderId);

	String deliveryStatus = delivery.getStatus();

	if("IN_PROGRESS".equals(deliveryStatus)){
		delivery.setStatus("CANCEL");
		deliveryDao.update(delivery);
	}

	order.setStatus("CANCEL");
	ordersDao.update(order);

	billing.setStatus("CANCEL");;
	deliveryDao.update(billing);

	return order;
}

도메인 모델 패턴

@Transactional
public Order cancelOrder(int orderId){
	
	Orders order = orderRepository.findById(orderId);
	Billing billing = billingRepository.findByOrderId(orderId);
	Delivery delivery = deliveryRepository.findByOrderId(orderId);

	
	delivery.cancel();

	
	order.cancel();
	billing.cancel();

	return order;
}

한 눈에 봐도 코드가 간결해지고 각 도메인이 자신의 이벤트를 처리하며 객체 지향스러워 진 것이 보인다.

물론 각각의 장단점이 있겠지만 도메인 모델 패턴을 한 번 고려해 보는 것도 좋을 것 같다.

reference

0개의 댓글