ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [책 리뷰] DDD START! 도메인 주도 설계 구현과 핵심 개념 익히기
    자바/기타 2021. 5. 7. 11:07

    도메인

    • 소프트웨어로 해결하고자 하는 문제 영역
    • 한 도메인은 다시 하위 도메인으로 나눌 수 있다.

     

    도메인 모델

    • 특정 도메인을 개념적으로 표현한 것

     

    도메인 모델 패턴

    • 아키텍쳐상의 도메인 계층을 개체 지향 기법으로 구현하는 패턴
    • 핵심 규칙을 구현한 코드는 도메인 모델에만 위치하기 때문에 규칙을 바꾸거나 규칙을 확장해야 할 때 다른 코드에 영향을 덜 주고 변경 내역을 모델에 반영할 수 있다.
    • 도메인 계층은 도메인의 핵심 규칙을 구현한다.
      • 주문 도메인의 경우 '출고 전에 배송지를 변경할 수 있다'는 규칙과 '주문 취소는 배송 전에만 할 수 있다'는 규칙을 구현한 코드가 도메인 계층에 위치하게 된다.
    public class Order {
        private OrderState state;
        private ShippingInfo shippingInfo;
        
        public void changeShippingInfo(ShippingInfo newShippingInfo) {
        	if(!isShippingChanagable()) {
            	throw new IllegalStateException("can't change shipping in " + state);
            }
            this.shippingInfo = newShippingInfo;
        }
        private boolean isShippingChanagable(){
        	return state == OrderState.PAYMENT_WAITING || state == OrderState.PREPARING;
        }
        ...
     }
            
     public enum OrderState {
    	PAYMENT_WAITING, PREPARING, SHIPPED, DELIVERING, DELIVERY_COMPLETED;
     }

     

    엔티티

    • 엔티티의 가장 큰 특징은 식별자를 갖는다.
    • 식별자는 엔티티마다 고유해서 각 엔티티는 서로 다른 식별자를 갖는다.
    • 엔티티의 식별자는 바뀌지 않고 고유하기 때문에 두 엔티티 객체의 식별자가 같으면 두 엔티티는 같다고 판단할 수 있다.

     

    밸류 타입

    • 2개 이상의 필드가 개념적으로 완전한 하나를 표현할 때 사용
    • 엔티티 타입의 두 객체가 같은지 비교할 때 주로 식별자를 사용한다면 두 밸류 객체가 같은지 비교할 때는 모든 속성이 같은지 비교해야 한다.
    public class ShippingInfo {
        private String receiverName;
        private String receiverPhoneNumber;
        // private Receiver receiver; 밸류 타입 사용
        
        ...
    }
    
    public class Receiver {
        private String name;
        private String phoneNumber;
    }
    • 의미를 명확하게 표현하기 위해 하나의 필드를 밸류 타입으로 사용하는 경우도 있다.
    • 밸류 타입을 사용할 때 또 다른 장점은 밸류 타입을 위한 기능을 추가할 수 있다.
    • Money처럼 데이터 변경 기능을 제공하지 않는 타입을 불변(immutable)이라고 표현한다. 밸류 타입을 불변으로 구현하면 보다 안전한 코드를 작성할 수 있다.
    public class OrderLine {
        private Product product;
        private int price;
        private int quantity;
        private int amount;
        ...
    }
    
    public class Money {
        private int value;
        
        public Money add(Money money) {
        	return new Money(this.value + money.value);
        }
        public Money muliply(int multiplier) {
        	return new Money(this.value * multiplier);
        }
    }
    
    public class OrderLine {
        private Product product;
        private Money price;
        private int quantity;
        private Money amount;
        ...
    }

     

    인티티 식별자와 밸류 타입

    식별자를 위한 밸류 타입을 사용해서 의미가 잘 드러나도록 할 수 있다.

    public class Order {
        // OrderNo 타입 자체로 id가 주문번호임을 알 수 있다.
        private OrderNo id;
        
        ...
        
        public OrderNo getId() {
        	return id;
        }
    }

     

    도메인 모델에 set 메서드 넣지 않기

    • set 메서드는 도메인의 핵심 개념이나 의도를 코드에서 사라지게 한다.
    • 도메인 객체를 생성할 때 완전한 상태가 아닐 수도 있다.
    • 도메인 객체가 불완전한 상태로 사용되는 것을 막으려면 생성 시점에 필요한 데이터를 전달해주어야 한다. 즉 생성자를 통해 모든 데이터를 받아야 한다.
    • 생성자로 필요한 것을 모두 받으므로 생성자를 호출하는 시점에 필요한 데이터가 올바른지 검사할 수 있다.
    public class Order {
        public Order(Orderer orderer, List<OrderLine> orderLines, ShippingInfo shippingInfo, OrderState state) {
        	setOrderer(orderer);
            setOrderLines(orderLines);
            ...
        }
        
        private void setOrderer(Orderer orderer) {
        	if(orderer == null) throw new IllegalArgumentException("no orderer");
            this.orderer = orderer;
        }
        
        private void setOrderLines(List<OrderLine> orderLines) {
        	verifyOneOrMoreOrderLines(orderLines);
            this.orderLines = orderLines;
        }
        
        private void verifyOneOrMoreOrderLines(List<OrderLine> orderLines){
        	if(orderLines == null || orderLines.isEmpty()) {
            	throw new IllegalArgumentException("no OrderLine");
            }
        }
    }

     


    애그리거트

    애그리거트

    • 복잡한 도메인을 이해하고 관리하기 쉬운 단위로 만들려면 상위 수준에서 모델을 조망할 수 있는 방법이 필요한데, 그 방법이 바로 애그리거트이다.
    • 애그리거트는 모델을 이해하는데 도움을 줄 뿐만 아니라 일관성을 관리하는 기준이 된다.
    • 애그리거트는 관련된 모델을 하나로 모은 것이기 때문에 한 애그리거트에 속한 객체는 유사하거나 동일한 라이프사이클을 갖는다.
    • 애그리거트는 경계를 갖는다.
      • 애그리거트는 독립된 객체 군이며, 각 애그리거트는 자기 자신을 관리할 뿐 다른 애그리거트를 관리하지 않는다.
      • 경계를 설정할 때 기본이 되는 것은 도메인 규칙과 요구 사항이다.
    • 함께 변경되는 빈도가 높은 객체는 한 애그리거트에 속할 가능성이 높다.

     

    애그리거트 루트

    • 애그리거트에 속한 모든 객체가 일관성을 유지하려면 애그리거트 전체를 관리할 주체가 필요한데 이 책임을 지는 것이 애그리거트의 루트 엔티티이다.
    • 애그리거트 루트가 아닌 다른 객체가 애그리거트에 속한 객체를 직접 변경하면 안된다. 이는 애그리거트 루트가 강제하는 규칙을 적용할 수 없어 모델의 일관성을 깨는 원인이 된다.

    도메인 모델과 BOUNDED CONTEXT

    도메인 모델과 경계

    • 하위 도메인마다 사용하는 용어가 다르기 때문에 올바른 도메인 모델을 개발하려면 하위 도메인마다 모델을 만들어야 한다.

     

    BOUNDED CONTEXT

    • 모델의 경계를 결정하며 한 개의 BOUNDED CONTEXT는 논리적으로 한 개의 모델을 갖는다.

     

    BOUNDED CONTEXT 간 통합

    • 외부 연동을 위한 도메인 서비스 구현 클래스는 도메인 모델과 외부 시스템 간의 모델 변환을 처리한다.
    • 모델 간 변환이 복잡하면 별도 변환기를 둔다.
    • 메시지 큐를 이용한 통합

     

    마이크로서비스와 BOUNDED CONTEXT
    BOUNDED CONTEXT는 모델의 경계를 형성하는데, BOUNDED CONTEXT를 마이크로서비스로 구현하면 자연스럽게 컨텍스트별로 모델이 분리된다.

     

    BOUNDED CONTEXT 간 관계

    • 고객/공급자 관계를 갖는 BOUNDED CONTEXT
    • BOUNDED CONTEXT가 같은 모델을 공유하는 경우
    • 독립 방식

     

    컨텍스트 맵

    • BOUNDED CONTEXT 간의 관계를 표시한 것

     


    이벤트

    이벤트

    • 시스템 간 강결합의 문제
      • 트랜잭션 처리 이슈
      • 외부 서비스 성능에 직접적인 영향을 받는 문제
      • 도메인 객체에 서로 다른 도메인 로직이 섞이는 문제
    public class Order {
        verifyNotYetShipped();
        this.state = OrderState.CANCELED;
        
        this.refundStatus = REFUND_STARTED;
        try {
        	refundSvc.refund(getPaymentId());
            this.refundStatus = State.REFUND_COMPLETED;
        } catch (Exception ex) {
        	...
        }
    }

     

    지금까지 언급한 문제가 발생하는 이유는 주문 BOUNDED_CONTEXT와 결제 BOUNDED_CONTEXT간의 강결합(high coupling)때문이다.
    이런 강한 결합을 없앨 수 있는 방법이 있는데 그것은 바로 이벤트를 사용하는 것이다.

     

    이벤트의 개요

    • 이벤트가 발생한다는 것은 상태가 변경됐다는 것을 의미한다.

     

    이벤트의 용도

    • 도메인의 상태가 바뀔 때 다른 후처리를 해야 할 경우 후처리를 실행하기 위한 트리거로 이벤트를 사용할 수 있다.
    • 서로 다른 시스템 간의 데이터 동기화

     

    이벤트의 장점

    이벤트를 사용하면 서로 다른 도메인 로직이 섞이는 것을 방지할 수 있다.

    '자바 > 기타' 카테고리의 다른 글

    [UML] 클래스 다이어그램  (0) 2021.05.07
    [JAVA] Array 클래스  (0) 2021.04.30
    [JAVA] String 클래스  (0) 2021.04.30
    [JAVA] Map  (0) 2021.04.30
    [JAVA] 클래스의 구성 관계  (0) 2021.04.28

    댓글

Designed by Tistory.