난이도 ⭐️⭐️
작성 날짜 2025.01.04
이벤트 스토밍을 통해 도메인을 모두 분리했다.
이제 코드를 작성할 때 DDD를 사용해야 한다.
이유는 다음과 같다.
🤔
코드 레벨에서 DDD를 잘 활용하기 위한 규칙은 무엇이 있을까?
도메인 값을 변경할 때 외부에서 변경하게 되면 예상하지 못한 변화가 생길 수 있기 때문에 도메인을 보호할 수 없다.
final, private 사용 그리고 setter 금지 등을 통해 객체 상태를 보호해야 한다.
public class Money {
private final int amount;
public static Money of(int amount) {
if (amount < 0) throw new IllegalArgumentException("금액은 음수가 될 수 없습니다.");
return new Money(amount);
}
}
비즈니스 규칙과 관련된 검증은 도메인 내부에서 진행하는 것이 좋다.
규칙을 집약해두어야, 나중에 기획이 바뀔 때에도 수월하며
도메인 외부 (서비스 등) 계층에서 수정되는 것을 막을 수 있다.
public class Order {
public void cancel() {
if (this.status != OrderStatus.WAITING) {
throw new IllegalStateException("이미 처리된 주문은 취소할 수 없습니다.");
}
this.status = OrderStatus.CANCELED;
}
}
어그리거트 내 루트 도메인과 연관된 다른 엔티티의 경우에는 루트 도메인을 통해서만 수정, 변경이 가능하다.
다방면에서 변경에 열려있는 경우, 일관된 흐름 파악이 어렵다.
public class Order {
private Long id;
private List<OrderItem> items;
public void addItem(Product product, int quantity) {
this.items.add(new OrderItem(product, quantity));
}
public int totalPrice() {
return items.stream().mapToInt(OrderItem::price).sum();
}
}
도메인 내에서 작성하기 어려운 로직의 경우, 해당 도메인의 서비스에 작성한다.
단, 해당 서비스는 다른 도메인을 변경할 수 없다.
public class TransferService {
public void transfer(Account from, Account to, Money amount) {
from.withdraw(amount);
to.deposit(amount);
}
}
Command Query 분리 전

Command Query 분리 후

출처 : https://wonit.tistory.com/628
Command와 Query에 대한 책임 분리로
DB를 분리한다면, 확실한 차이를 확인할 수 있을 것 같다!
로직 내에 다른 도메인에 대한 변경이나 연관된 커맨드가 발생하는 경우 이벤트를 터뜨려 강결합을 줄인다.
public class Order {
public void completePayment() {
this.status = OrderStatus.PAID;
DomainEvents.raise(new OrderPaidEvent(this.id));
}
}
@Component
public class OrderEventHandler {
@EventListener
public void handle(OrderPaidEvent event) {
// 알림 발송, 외부 API 호출 등
}
}
DDD 원칙을 지키기 위해선 평소 작성하던 코드의 형식에서 벗어나야 하는 것 같아 적응까진 시간이 좀 걸릴 것 같다!
그러나 확실히 개발자가 좋아하는 높은 응집도와 낮은 결합도에 도움이 되는 개념인 것 같아 확실히 체화시키고 싶다..!