mingg IT

[DDD] 1장 도메인 모델 시작하기 본문

기타

[DDD] 1장 도메인 모델 시작하기

mingg123 2022. 7. 13. 22:22

1장 도메인 모델 시작하기

DDD 란?

Domain Driven Design (도메인 주도 개발)

  • DDD 특징
    • 기존 데이터 중심 접근법으로 부터 벗어나, 도메인을 중점으로 두고 설계 하는 것
    • 유비쿼터스 언어로 이루어짐. (ex UML, ERD, 등 모두가 이해할 수 있는 언어)
  • DDD 가 나오게 된 배경
    • 여러 요구사항을 올바르게 이해하고 설계하기 위해.
    • 특정 도메인을 개념적으로 표현한 것.도메인 모델 이란
  • 도메인 모델 표현
    • UI 표현
    • 응용
      • 사용자 요청한 기능을 실행. 업무 로직을 직접 구현하지 않고 도메인 계층을 조합해서 기능을 실행.
    • 도메인
      • 도메인 규칙을 구현함.
    • 인프라스트럭처
      • DB나 메시징 시스템과 같은 외부 시스템 연동도메인 모델 패턴

도메인 계층은 도메인의 핵심 규칙을 구현하기 때문에

주문 도메인의 경우 '출고 전에 배송지를 변경할 수 있다'는 규칙과 '주문 취소는 배송 전에만 할 수 있다'는 규칙을 구현한 코드가 도메인 계층에 위치해야함.

public class Order {
	private OrderState state;
	private ShippingInfo shippingInfo;

	public void changeShippingInfo(ShippingInfo newShippingInfo) {
		if (!state.isShippingChangeable()) {
			throw new IllegalStateException("can't change shipping in " + state);
		}
		this.shippingInfo = newShippingInfo;
	}

	public void changeShipped() {
		// 로직 검사
		this.state = OrderState.SHIPPED;
	}
	...
}
public enum OrderState {
	PAYMENT_WAITING {
		public boolean isShippingChangeable() {
			return true;
		}
	},
	PREPARING {
		public boolean isShippingChangeable() {
			return true;
		}
	},
	SHIPPED, DELIVERING, DELIVERY_COMPLETED;

	public boolean isShippingChangeable() {
		return false;
	}
}

이 코드는 주문의 상태에 따라 배송지를 변경하는 로직을 구현.

이는 주문과 관련된 중요 업무 규칙을 주문 도메인 모델인 Order에 구현해야함.

핵심 규칙을 구현한 코드는 도메인 모델에만 위치하기 때문에 규칙이 바뀌거나 규칙을 확장해야 할 때 다른 코드에 영향을 덜 주고 변경 내역을 모델에 반영할 수 있게 됨.

 

  • 도메인 모델 도출 방법
    • 요구 사항을 리스트업 함.
    • 주문 예시
    public class Order {
    	public void changeShipped() { ... }
    	public void changeShippingInfo(ShippingInfo newShipping) { ... }
    	public void cancel() { ... }
    	public void completePayment() { ... }
    }
    
    요구사항을 바탕으로 간단하게 어떤 메소드가 필요할 지 알 수 있음.또한 주문 도메인이 어떤 데이터로 이루어져있는지 유추 가능함.배송지 정보를 알 수 있고, 배송지 정보를 반드시 지정해야한다는 조건이 있음.

특정 조건이나 상태에 따라 제약사항이 달라짐. enum을 통해 사용할 수 있음.

public enum OrderState {
	PAYMENT_WAITING, 
	PREPARING, 
	SHIPPED, 
	DELIVERING, 
	DELIVERY_COMPLETED, 
	CANCELED 
}

public class Order {
	private OrderState state;

	public void cancel() { ... }
	public void verifyNotYetShipped() { ... }
}
  • 엔티티와 벨류
    • 엔티티는 고유한 식별자를 갖는다. (uuid, 특정 규칙, db 시퀀스, 값을 직접 입력 등으로 생성함)
    • 벨류는 개념적으로 하나를 표현함 ex) shippingInfo 내의 주소, 사람 정보
    • 벨류는 immutable 하게 관리하고, 벨류를 위한 타입을 설정할 수 있음.
public class Order {
	// OrderNo 타입 자체로 주문 번호임을 유추 가능함
	private OrderNo id;
	
	public OrderNo getId() {
		return id;
	}
}
  • 도메인 모델에서 setter 지양
    • changeShippingInfo()가 배송지 정보를 새로 변경하다는 의미를 가졌다면 setShippingInfo() 메서드는 단순히 배송지 값을 설정한다는 것을 뜻함.
    • 불안전한 상태에서 setter를 사용할 수도 있음 (이는 생성자를 이용하여 막을 수 있음)
  • 도메인 용어에 대한 중요성
    • 충분히 고민해보고 변수명 짓는 시간을 아까워 하지말자.
  •  
Comments