DDD START! (5)

이유진·2023년 11월 26일
post-thumbnail

Aggregate

도메인에 대한 구성/관계를 표현할 때, ERD를 그린다면 개별 테이블 간 관계 파악으로 어려움을 겪을 수 있다.
해당 도메인 요소 간 관계를 표현할 때 Aggregate를 사용한다면 상위수준에서 도메인 모델 간 관계를 파악할 수 있다.

동일한 Aggregate에 속한 객체는 동일한 라이프 사이클을 갖는다.
한 Aggregate에 속한 객체는 다른 Aggregate에 속하지 않는다.

ex) 쇼핑몰의 Aggregate

  • 주문 - Address, Delivery, OrderLine, Order, Shipping, Receiver, Orderer
  • 분류
  • 상품
  • 리뷰
  • 결제
  • 회원

"주문" Aggregate에서는 배송지(Address)를 수정할 수 있지만, 회원 비밀번호를 변경하진 않는다.

"주문"과 "리뷰" 는 페이지에서 함께 보여주지만, 생성 시기/수정 시기가 다르기 때문에 같은 Aggregate로 볼 수 없다.

Aggregate Root

Aggregate는 여러 객체로 구성되기 때문에 한 객체 상태만 정상이면 안된다.
모든 객체가 정상 상태를 가져야 한다.

Aggregate 내 모든 객체가 일관된 상태를 유지하려면, Aggregate 전체를 관리하는 주체가 필요하고 이것을 Aggregate Root(대표 Entity)라고 한다.

ex) 주문 Aggregate
포함된 Entity: Address, Delivery, OrderLine, Order, Shipping, Receiver, Orderer

  • 주문 Aggregate의 Aggregate Root: Order
    주문 Aggregate는 배송지 변경, 상품변경과 같은 기능을 제공한다.
    Order에서 해당 기능을 구현한 메서드를 제공한다.

Aggregate Root를 통해서만 도메인 로직을 구현하게 만드려면?

  • 필드를 변경하는 set 메서드를 public으로 만들지 않는다
  • Value 타입은 불변으로 구현한다

공개 Set 메서드

왜 공개 set을 피해야 할 까?
도메인 객체 외에서 set으로 값을 변경하게 되면 해당 값이 어디서 변경되는지 파악하기 쉽지 않다.
➡️ 도메인 로직이 한 곳으로 응집되지 않는다

만약에 배송상태 를 취소로 변경한다고 할 때,

  • setShippingStatus("cancel"): X
  • 배송 Entity에 cacel 메서드 구현: O ➡️ 의미가 명확해진다
public class Shipping {
	...
    
    public void cancel() {
    	this.shippingStatus = cancel;
    }
}

트랜잭션

  • 트랜잭션 범위는 작을수록 좋다
  • 한개의 트랜잭션이 한 테이블을 수정하는 것 보다 세 개 테이블을 수정하는 것을 비교하면 성능에 차이가 있다
  • 잠금대상이 많아진다 == 동시에 처리할 수 있는 트랜잭션 개수가 줄어든다 ➡️ 전체적인 성능 (처리량)을 떨어뜨린다
  • 한 개의 트랜잭션에서는 한개의 Aggregate만 수정한다
  • 도메인 이벤트를 사용하면 한 트랜잭션에서 한 개의 Aggregate를 수정하면서 동기/비동기로 다른 Aggregate 상태를 변경하는 코드를 작성할 수 있다
profile
BackEnd Developer

0개의 댓글