
EDA(Event Driven Architecture)는 결합력을 확 낮추고, 확장 가능 이벤트를 기반인 구조
DDD(Domain Driven Design)와 EDA사이의 통신 방식이 Event!
그래서... DDD를 구현하는 도중..
도메인 모델 패턴(Domain Model pattern)과
트랜잭션 스크립트 패턴(Transaction Script Pattern)은
비즈니스 로직을 처리하는 대표적인 방식이라고 한다.
특정 작업 단위(트랜잭션)로 나눠서 각각의 로직을 절차적으로 처리하는 방식
아마 우리가 흔히 사용했던 방식일거라고 생각한다.

내가 했던 프로젝트 코드인데, 회원정보를 삭제하는 메소드다.
이 순서대로 순차적으로 진행이 된다.
트랜잭션(Transaction)
DB에 데이터를 읽고 쓸 때, 한 번에 수행되어야 하는 논리적인 작업 단위
트랜잭션이 결국은 한 작업의 단위이기 때문에,
트랜잭션 스크립트 패턴 이라고 부른다.
그러니까 간단하게 말해, 그냥 한 작업으로 묶었다! 라고 생각하면 된다.
비즈니스 로직을 도메인 객체 안에 포함하여 객체 지향적으로 관리
도메인 주도 설계(DDD)에서 많이 사용하는 방식이다.
비즈니스 로직을 도메인 객체 안에 포함하여 객체 지향적으로 관리한다.
도메인 모델 패턴의 목적은
"코드가 도메인의 진짜 모습을 닮도록 설계해서, 비즈니스 개념이 자연스럽게 흘러가게 만드는 것"
이 목표다.
@Getter
public class Order {
private String id;
private List<OrderLine> orderLines;
private OrderState state;
private Money totalAmounts;
private ShippingInfo shippingInfo;
public Order(List<OrderLine> orderLines, ShippingInfo shippingInfo) {
id = UUID.randomUUID().toString();
setOrderLines(orderLines);
setShippingInfo(shippingInfo);
state = OrderState.PAYMENT_WAITING;
}
/**
* 배송 정보 설정
*/
private void setOrderLines(List<OrderLine> orderLines) {
if (isEmptyLOrderLines(orderLines)) {
throw new IllegalStateException(ErrorMessages.NO_ORDER_LINE.getMsg());
}
this.orderLines = orderLines;
calculateTotalAmounts();
}
private boolean isEmptyLOrderLines(List<OrderLine> orderLines) {
return orderLines == null || orderLines.isEmpty();
}
/**
* 수신자 설정
*/
private void setShippingInfo(ShippingInfo shippingInfo) {
if (isBlankShippingInfo(shippingInfo)) {
throw new IllegalStateException(ErrorMessages.NO_SHIPPING_INFO.getMsg());
}
this.shippingInfo = shippingInfo;
}
private boolean isBlankShippingInfo(ShippingInfo shippingInfo) {
return shippingInfo == null || shippingInfo.isBlank();
}
/**
* 배송 전 상태 확인 메소드
*/
private void verifyBeforeShipping() {
if (state != OrderState.PAYMENT_WAITING && state != OrderState.PREPARING) {
throw new IllegalStateException(ErrorMessages.ALREADY_SHIPPED.getMsg());
}
}
/**
* 주문 총액 계산 메소드
*/
private void calculateTotalAmounts() {
this.totalAmounts = new Money(orderLines.stream()
.mapToInt(x -> x.getAmounts().getValue()).sum());
}
}
현재 코드는 Order 도메인이다.
클래스 안에 필요한 각 인스턴스들 뿐만 아니라,
배송 정보 설정, 수신자 설정, 주문 상태 변경 메소드들, 배송 전 상태 확인 메소드, 주문 총액 계산 메소드
(주문 상태 변경은 내가 뺐다. 너무 길어...)
비즈니스 로직 마저, 도메인 클래스 안에 포함되어 있다.
Order 객체가
배송 정보 설정, 수신자 설정, 주문 상태 변경 메소드들, 배송 전 상태 확인 메소드, 주문 총액 계산 메소드
이러한 비즈니스 로직들을 스스로 수행한다.
객체 자체가 가지고 있기 때문에, 객체 지향적인 설계다.
제품과 고객 간 관계를 통해, 다양한 비즈니스 규칙을 객체 간 상호작용으로 처리할 수 있다.
예: "VIP 고객은 10% 할인된 가격으로 제품을 주문할 수 있다"
// 트랜잭션 스크립트 패턴 예시
if (customer.getGrade().equals("VIP")) {
price = product.getPrice() * 0.9;
}
이 로직이 서비스나 컨트롤러에 막 섞여 있다고 하자.
제품도 고객도 아무 책임을 안 짐 → 객체 의미 X
로직이 바뀌면 여기저기 고쳐야 한다.
// 손님
class Customer {
/**
* 할인율 연산 메소드
*/
public Money calculateDiscountPrice(Product product) {
if (this.grade == VIP) {
return product.getPrice().times(0.9);
}
return product.getPrice();
}
}
// 주문
class Order {
/**
* 주문 생성 메소드
*/
public static Order create(Customer customer, Product product) {
Money discounted = customer.calculateDiscountPrice(product);
return new Order(customer, product, discounted);
}
}
정확하게
할인은 Customer가 담당하게 된다.
주문은 Order가 담당하게 된다.
→ 고객-제품-주문이 서로 역할 분담해서 협력
비즈니스 규칙을 if문 뭉치로 때우는 게 아니라,
"도메인 객체들이 서로 책임지고 협력하면서 처리하도록 만드는 것"
이 도메인 모델 패턴의 주요 목적이다.