프로그래밍 노트/도메인 주도 설계(DDD)

CQRS(Command Query Responsibility Segragation)은 상태를 변경하는 명령(Command)모델과 조회(Query)를 위한 모델을 분리하는 패턴이다. CQRS를 적용하면 어떤 장점이 있을까? 단일 모델의 단점 주문 내역 조회기능을 구현하려면 여러 애그리거트에서 데이터를 가져와야 한다. Order: 주문 정보 Product: 상품 이름 Member: 회원 이름, ID 여러 애그리거트의 데이터가 필요한데 어떻게 구현해야할까? 식별자를 이용하여 애그리거트를 참조하는 방식 즉시 로딩(eager loading)과 같은 JPA 쿼리 최적화 기능을 사용할 수 없음 한 번의 SELECT 쿼리로 조회 화면에 필요한 데이터를 구할 수 없음(성능상 문제 발생) 직접 애그리거트를 참조하는 방식 ..
시스템 간 강결합은 어떻게 없앨 수 있을까? 쇼핑몰에서 구매 취소를 하면 환불 처리가 되어야 한다. 이때 환불기능을 실행하는 주체는 주문 도메인이 될 수 있으며, 환불 기능을 실행하기 위해서 환불 도메인 서비스를 파라미터로 전달받아 실행할 수 있다. class Order { // 외부 서비스 실행을 위해 도메인 서비스를 파라미터로 전달 받음 fun cancel(refundService: RefundService) { verifyNotYetShipped() this.state = OrderState.CANCELED this.refundStatus = State.REFUND_STARTED try { refundService.refund(getPaymentId()) this.refundStatus = Stat..
도메인 모델과 경계 도메인을 완벽하게 표현하는 단일 모델을 만드려는 시도를 하지 말자!! 한 도메인은 다시 여러 하위 도메인으로 구분되기 때문에 여러 하위 도메인을 모두 표현하려고하면 오히려 모든 하위 도메인에 맞지 않는 모델을 만들게 된다. 하위 도메인마다 같은 용어라도 의미가 다를 수 있음 하위 도메인마다 같은 대상이라도 지칭하는 용어가 다를 수 있음 따라서, 올바른 도메인 모델을 개발하려면 하위 도메인마다 모델을 만들어야한다. case1. 같은 용어라도 의미가 다른 경우 (feat. 상품 모델) 카탈로그 도메인에서의 상품 상품 이미지, 상품명, 상품 가격, 상세 설명 과 같은 상품 정보 위주 재고 관리 도메인에서의 상품 실존하는 개별 객체를 추적하기 위한 목적으로 사용 주문 도메인에서의 상품 배송 ..
도메인 영역의 코드를 작성하다 보면 한 애그리거트로 기능 구현이 불가능할 때가 존재한다. 바로 결제 금액 계산 로직인데, 실 결제 금액을 계산할 때는 아래 정보들이 필요하다. 상품 애그리거트 : 구매하는 상품의 가격 필요 주문 애그리거트 : 상품별 구매 개수 필요 할인 쿠폰 애그리거트 : 쿠푠별로 지정한 할인 금액이나 비율에 따라 주문 총 금액을 할인하는 정보 필요 회원 애그리거트 : 회원 등급에 따른 추가 할인 정보 필요 그렇다면 실제 결제 금액을 계산해야하는 주체는 어떤 애그리거트 일까? if. 주문 애그리거트에서 필요한 데이터를 모두 가지게 한다면? (계산 책임을 주문 애그리거트에 할당) 할인 정책이 변경되었을 때 주문 애그리거트가 갖고 있는 구성 요소와 관련이 없음에도 결제 금액 계산 책임이 주문..
표현 영역(Presentation Layer) 사용자의 요청을 해석 사용자가 실행하고 싶은 기능을 판별하고 그 기능을 제공하는 응용 서비스를 실행 응용 서비스의 메서드가 요구하는 파라미터와 표현 영역이 사용자로부터 전달받은 데이터는 형식이 일치하지 않기 때문에 표현 영역은 서비스가 요구하는 형식으로 사용자 요청을 변환 필요 응용 영역(Application Layer) 실제 사용자가 원하는 기능을 제공 @PostMapping("/member/join") fun join(req: HttpServletRequest): ModelAndView { val emal = req.getParameter("email") val password = req.getParameter("password") // 요청을 응용 서비..
애그리거트? 도메인 객체 모델이 복잡해지면 개별 구성요소 위주로 모델을 이해하게 되고 전반적인 구조나 도메인 간의 관계를 파악하기 어려워진다. 관계 파악이 어렵다? 라는 의미는? 확장하기가 어렵다. 세부적인 모델만 이해한 상태로는 코드 수정이 꺼려진다. (전체 모델이 망가질 수 있으므로) 변경을 최대한 회피하는 쪽으로 요구사항을 협의하게 된다. 장기적으로는 코드를 수정하기 더 어렵게 만든다. 위는 애그리거트 단위로 모델을 묶어서 표현한 것 애그리거트를 사용함으로써 모델 간의 관계를 개별 모델 수준과 상위 수준에서 모두 이해가 가능하다. 모델 이해도를 증가시킴 일관성을 관리하는 기준이 됨 (한 애그리거트에 속한 객체는 유사하거나 동일한 LifeCycle을 갖는다.) 이것이 애그리거트의 필요성이다. 유의할 ..
Application Layer ? Domain Layer ? 앞에서 선택한 아키텍처를 사용하게 되면 응용 영역에서 사용자에게 제공해야할 기능을 구현하게 된다. 주문이란 하위 도메인을 예로 들면 주문 등록, 주문 취소, 상품 상세 조회와 같은 기능을 제공한다. 응용 영역(Application)은 기능을 구현하기 위해 도메인 영역에 존재하는 도메인 모델을 사용한다. class CancelOrderService { @Transactional fun cancelOrder(orderId: String) { val order = findOrderById(orderId) if (order == null) throw new OrderNotFoundException(orderId) order.cancel() // 위임..
도메인이란 무엇을 뜻할까? 도메인을 한 줄로 정의하자면 소프트웨어로 해결하고자 하는 문제 영역을 뜻한다. 만약, 우리가 온라인 서점이라는 서비스를 제공한다면 온라인 서점은 도메인(domain)이 될 수 있다. 그리고 도메인은 여러 하위 도메인으로 구성된다. 온라인 서점 (도메인) 주문 (하위 도메인) 정산 (하위 도메인) 배송 (하위 도메인) 결제 (하위 도메인) 고객이 책을 주문하고 결제하면 책이 배송된다. 이렇게 하위 도메인은 다른 도메인이랑 엮이면서 완전한 기능을 제공하게 된다. 도메인 모델? 다양한 정의가 존재하는데 아래 내용만 짚고 넘어가자 특정 도메인을 개념적으로 표현한 것 도메인이 제공하는 기능(메소드)와 주요 데이터(프로퍼티)를 가지고 있는 모델 도메인 계층을 구현할 때 사용하는 객체 모델..
깡냉쓰
'프로그래밍 노트/도메인 주도 설계(DDD)' 카테고리의 글 목록