일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- head first
- Java
- Design Pattern
- 자바8인액션
- facade pattern
- Stream
- AWS101
- CQRS
- 자바8
- web
- Java in action
- jsp
- 자바
- spring Batch
- Java8
- spring
- domain
- Java 8 in action
- SERVLET
- Java8 in action
- Template Method Pattern
- Clean Code
- ddd
- 디자인 패턴
- 스트림
- 패스트캠퍼스
- spring boot
- 자바의 신
- 클린코드
- Was
- Today
- Total
목록개발 성장기/DDD (11)
주난v 개발 성장기
CQRS - Command Query Responsibility Segregation 단일 모델의 단점 조회 화면의 특성상 속도가 빨라야 하는데, 여러 애그리거트에서 데이터를 가져와야 할 경우 구현 방법을 고민해야 한다. (ex. 주문 상세 조회 시에 주문, 상품, 회원 정보를 모두 조회해한다.) ID를 이용해서, 애그리거트를 참조하는 방식을 사용하면 즉시 로딩과 같은 최적화 기능을 이용 못하고, 여러번 select를 해야함으로 속도에 문제가 생긴다. ID가 아니라 직접 참조하는 방식으로 연결해도 즉시 로딩이나 지연 로딩을 처리해야 하므로, 네이티브 쿼리를 사용해야 할 수도 있다. 이러한 고민은 단일 도메인을 사용하기 때문이다. 해결법은 상태 변경을 위한 모델과 조회를 위한 모델을 분리하는 것! CQRS..

구매를 취소하면 환불을 처리해야 한다. 이 때, 환불 기능을 실행하는 주체는 주문 도메인 엔티티가 될 수 있다. 도메인 객체에서 환불 기능을 실행하려면 1. 도메인 서비스를 파라미터로 전달받아 처리 public class Order { public void cancel(RefundService refundService) { // 처리 refundService.refund(getPaymentId()); } } - 주문 로직과 결제 로직이 섞이는 문제 - 기능 확장의 어려움 발생 - 메일을 보낸다고 했을 때, 메일 발송 Service를 파라미터에 추가해줘야한다. - 더불어 트랜잭션 처리도 복잡해진다. 2. 응용 서비스에서 별도 환불 기능 실행 - CancelOrderService 구현 - 응용 서비스에서 C..

도메인 모델과 경계 한 도메인은 여러 하위 도메인으로 구분되기 때문에, 한 개의 모델로 여러 하위 도메인을 모두 표현하려다보면 모든 하위 도메인에 맞지 않는 모델을 만들게 된다. (ex. 주문 - 상품 / 배송 - 상품 / 재고 - 상품) 논리적으로는 같아 보이지만, 실제로 사용하는 방법은 다 다르다 하위 도메인마다 같은 용어라도, 의미가 다르고 지칭하는 용어가 다를 수 있기 때문에, 한 개의 모델로 모든 하위 도메인을 표현할 수 없다. 여러 하위 도메인의 모델이 섞이기 시작하면 모델의 의미가 약해지고, 요구사항을 모델에 반영하기가 어렵다. 모델은 구분되는 경계를 가지게 되는데 이를 BOUNDED CONTEXT라 한다. BOUNDED CONTEXT 모델의 경계를 결정하며, 한 개의 BOUNDED CONT..

애그리거트와 트랜잭션 운영자 스레드와 고객 스레드는 개념적으로 동일한 애그리거트지만, 물리적으로는 다른 애그릭더트 객체 이다. 운영자 스레드가 주문 애그리거트 객체의 배송 상태를 변경했는데, 고객이 그 사이에 배송지 정보를 변경 --> 애그리거트의 일관성이 깨진다. 이를 보완하는 트랜잭션 처리 기법이 필요! 1. 선점(Pessimistic) 잠금 - 먼저 애그리거트를 구한 스레드가 사용이 끝날 때까지 다른 스레드가 해당 애그리거트를 수정하는 것을 막는다. 한 스레드가 애그리거트를 구하고 수정하는 동안 다른 스레드가 수정할 수 없으므로, 동시에 데이터를 수정하는 충돌 문제 해결 가능 선점 잠금 방식은 DBMS가 제공하는 행 단위 잠금을 사용해서 구현한다. LockModeType.PESIMISTIC_WRIT..

여러 애그리거트가 필요한 기능 한 애그리거트로 기능을 구현할 수 없을 때가 있다. (ex. 결제 금액 계산 로직...상품 / 주문 / 할인 쿠폰 / 회원 애그리거트를 모두 필요로 함) 주문 금액을 계싼하는 것은 주문 애그리거트에서 할 수 있지만, 실제 결제 금액은 누구의 책임일까..? 주문 애그리거트가 필요 데이터를 모두 가지고, 주문 애그리거트에서 처리..? 계산 로직이 주문 애그리거트에 있는 문제 할인 건이 생겨도, 주문 쪽 코드를 수정해야 함 --> 애그리거트는 자신의 책임 범위를 넘어서는 기능을 구현, 의존성이 증가 도메인 서비스 한 애그리거트에 억지로 넣기보다 도메인 서비스를 이용해서 도메인 개념을 명시적으로 드러내면 된다. public class DiscountCalculationService..
도메인 영역만 잘 만든다고, 사용자의 요구를 충족한다고 끝나는 것은 아니다. 도메인이 제 기능을 하려면 사용자와 도메인을 연결해 주는 매개체가 필요하다. (표현 - 응용 - 도메인) 표현 영역 - 사용자의 요청 해석 (어떤 기능을 실행하고 싶어하는지...), 응용 서비스 실행 - 응용 서비스에서 원하는 형태로 사용자의 요청을 변환 응용 영역 - 기능 제공 - repository로 부터 도메인 객체를 구하고, 사용 - 유효성 검사, 애그리거트 CRUD, 결과 리턴 이외의 것이 들어있으면 도메인 로직의 일부를 구현하고 있을 가능성이 있다. - 트랜잭션 처리 도메인 로직 넣지 않기 public class ChangePasswordService { public void changePassword(String m..

repository는 애그리거트의 저장소 find 메서드 정의로 조회를 할 수 있지만, 너무 많아지고 조합이 다양할 경우 스펙(Specification)을 이용 스펙(specification)은 애그리거트가 특정 조건을 충족하는지 여부를 검사 public interface Speficiation { public boolean isSatisfiedBy(T aggregation); } public class OrdererSpec implements Specification { private String orderId; public OrdererSpec(String ordererId) { this.ordererId = ordererId; } @Override public boolean isSatisfiedBy..

JPA를 이용한 리포지터리 구현 - 애그리거트를 어떤 저장소에 저장하느냐! - RDBMS를 사용한다면 JPA를 들 수 있다. - 도메인 모델과 관계형 데이터 모델 간의 매핑 처리 기술(ORM - Object Relation Mapping) 모듈 위치 팀 표준에 따라 domain.impl에 인프라 스트럭쳐 코드를 구현할 수 있지만, 좋은 설계는 아니다. 가능하면 구현 클래스를 인프라 스트럭쳐에 위치시켜 의존을 낮춰야한다. 매핑 구현 애그리거트 루트는 엔티티 이므로, @Entity로 설정한다. @Embeddable public class Orderer { @Embedded @AttributesOverrides( @AttributeOverride(name = "id", column = @Column(name ..