[백엔드 첫 걸음] API를 만들기 전 알아야 할 것 (스프링)

khyojun·2022년 8월 11일
1
post-thumbnail

지금부터는 정말 표현상으로는 달린다는 표현이 맞을 거 같다. 실습을 하면서 천천히 따라가기는 하는데 이젠 진짜 보면서 와... 이건 또 뭐야? 하는 느낌이다. 차근차근 정리하면서 따라가보도록 하자.


📌API를 만들기 위하여서 필요한 3개의 클래스

  • Request 데이터를 받을 Dto
  • API 요청을 받을 Controller
  • 트랜잭션, 도메인 기능 간의 순서를 보장하는 Service

그런데 여기서 보게 되면은 Service부분에서는 비즈니스 로직을 처리해야한다고 오해하는 경우가 많다고 한다.

그치만 실상은 그렇지 않고 그저 Service에서는 트랜잭션과 도메인 기능 간의 순서만 보장을 한다는 것이다.

그렇다면 비즈니스 로직은 누가 처리를 하는것인지? 라고 질문이 올 수 있는데 이 그림을 보면서 이해하는 시간을 가져본다.

📕 Web Layer

  • 흔히 우리가 사용하는 컨트롤러와 JSP/Freemarker등의 뷰 템플릿 영역(화면에 보여지는 영역)이다.
  • 이외에도 필터(@Filter), 인터셉터, 컨트롤러 어드바이스 등 외부 요쳥과 응답에 대한 전반적인 영역을 이야기를 한다.

📕 Service Layer

  • @Service에 사용되는 서비스 영역이다.
  • 일반적으로 Controller와 *Dao의 중간 영역에서 사용된다.
  • @Transactional이 사용되어야 하는 영역이다.

📕 Repository Layer

  • Database와 같이 데이터 저장소에 접근하는 영역이다.
  • *Dao(Data Access Object) 영역으로 이해하면 쉬울것이다.

📕 Dtos??!

  • *Dto(Data Transfer Object)는 계층 간에 데이터 교환을 위한 객체를 이야기하는데 Dtos는 이들의 영역을 얘기를 한다.
  • 예시를 들어볼 때 뷰 템플릿 엔진에서 사용될 객체나 Repository Layer에서 결과로 넘겨준 객체 등이 이들을 이야기를 한다고 한다.

📕 Domain Model

  • 도메인이라 불리는 개발 대상을 모든 사람이 동일한 관점에서 이해할 수 있고 공유할 수 있도록 단순화시킨 것을 도메인 모델이라고 한다.
  • 택시 앱이라고 칠 때 : 배차, 탑승, 요금 등이 모두 도메인이 될 수 있다고 한다.
  • @Entity가 사용된 영역이 도메인 모델이라고 이해해도 된다.
  • 무조건 데이터베이스의 테이블과 연관이 있어야 하는 건 또 아니다.
  • VO?처럼 값 객체들도 이 영역에 해당하기 때문

이렇게 5가지의 Layer들에서 비즈니스 처리를 담당해야 할 곳은?

Service가 아닌 Domain이라고 한다.

🏸 Why?

트랜잭션 스크립트

✔ 기존에 Service에서 모든 비즈니스 로직을 처리하는 것들을: 트랜잭션 스크립트라고 한다.

이런것의 단점은? 프로젝트가 커지게 된다면 하나의 서비스에서 더욱 많은 모델을 읽어 로직이 구성이 되면 될수록 서비스의 복잡도가 매우 높아진다는 것이다.

복잡도가 높으면? -> 유지보수가 힘듬...
결국 나중에 힘들어진다는 것이다.
그렇기 때문에 트랜잭션, 도메인 간 순서 보장을 하는 역할만 Service에서 하는것이 좋다.

그렇다면 코드로도 한 번 알아볼까?

주문 취소 로직을 수도 코드로 한번 확인해본다.

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

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

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

위 코드를 트랜잭션 스크립트 패턴으로 된 Service코드도 한 번 확인해보자.

@Transactional
public Order cancelOrder(int orderId){
	//1)
	OrderDto order = ordersDao.selectOrders(orderId);
	BillingDto 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");
	ordersDao.update(order);

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

	return order;
}

위 코드는 서비스 클래스 내부에서 모든 로직을 다 처리하게 된다. 이 코드를 보니 뭔가 로직도 커지고 엔티티 객체들이 활용된다는 느낌보다는 그냥 데이터 덩어리의 역할만 하는 것으로 느껴진다.

아래는 비즈니스 로직이 도메인 모델에서 처리될 경우이다.

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

	//2-3)
	delivery.cancel();

	//4)
	order.cancel();
	billing.cancel();

	return order;
}

위 코드랑 비교해 봤을때 너무나도 깔끔해졌다. 그리고 order, billing, delivery가 각자 취소 이벤트 처리를 하고 서비스 메소드는 그저 트랜잭션과 도메인 간의 순서만 보장한다.

위 예제들에서는 간단하게 취소하는 로직만 봤지만 말그대로 규모가 많이 커지게 된다면 Service가 구현된 layer는 보기도 싫을 정도로 코드가 복잡해질 거 같다는 생각이 많이 든다.....

*친 부분(잘 몰랐던 부분)

🏸 Dao?

Data Access Object: DB를 사용해 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 객체
ex) repository package에 해당이 된다.
jpa의 경우 JPARepository를 사용하는 경우가 DAO의 예시이다.

실제 DB에 접근하여 CRUD하는 객체

🏸 Dto?

Data Transfer Object의 줄임말이다. VO(Value Object)라고도 표현하는데, 계층간 데이터 교환을 위한 자바빈즈(Java Beans)다.
이 객체는 데이터베이스 레코드의 데이터를 매핑하기 위한 데이터 객체를 말한다. DTO는 보통 로직을 가지고 있지 않고 data와 그 data에 접근을 위한 getter, setter만 가지고 있다.

그저 DB에 있는 데이터를 매핑하기 위한 용도

  • 데이터를 주고받을 포맷(계층 간 데이터 교환을 위한 객체)

🏸 VO?

각 계층간 데이터 교환을 위한 자바 객체를 의미한다. 이 객체는 데이터를 각 레이어 간에 전달하는 목적을 가지고 있으며 객체의 속성과 getter, setter만 가지고 있다. DTO(Data Transfer Object)로 불릴 수도 있다. 

🏸 DTO vs VO

DTO와 VO는 어찌보면 동일한 개념이지만 VO는 Read Only의 속성을 지니고 있다.

오늘 등록에 대해 API를 실습하기 이전 너무나도 용어적으로나 지식적으로나 짚고 넘어가야 할 부분들이 많은 것 같다. 하나하나 차근히 넘어가야 할 것 같다.

참고

  1. 이동욱 저자의 <스프링 부트와 AWS로 혼자 구현하는 웹 서비스>
  2. https://gh402.tistory.com/53
  3. https://spring.io/guides/gs/testing-web/
profile
코드를 씹고 뜯고 맛보고 즐기는 것을 지향하는 개발자가 되고 싶습니다

0개의 댓글