네 개의 영역 표현(UI) 영역 사용자의 요청을 받아 응용 영역에 전달 응용 역영의 처리 결과를 다시 사용자에게 보여주는 역활 응용(Application) 영역 시스템이 사용자에게 제공해야 할 기능을 구현 예를들어 주문등록, 주문취소, 상품상세조회 등등 기능을 구현하기 위해 도메인 영역의 도메인 모델을 사용한다. 로직을 직접 수행하지 보다는 도메인 모델에 로직 수행을 위임한다. 도메인(Domain) 영역 도메인의 핵심 로직을 구현한다. 예를들어 주문 도메인인 경우 배송지 변경, 결제완료, 주문총액계산 등등 인프라스트럭처(Infrastructure) 영역 구현 기술에 대한 것을 다룬다. RDBMS 연동을 처리하고, 메시징 큐에 메시지를 전송하거나 수신하는 기능을 구현 HBase, 몽고DB등을 사용하여 데이..
DDD
반응형
시스템 간 강결합의 문제 만약 외부 시스템과의 연동으로 서비스를 구축할 경우, 외부 시스템이 정상적으로 작동하지 않을때 트랜잭션 처리로 인한 롤백이 애매해지게 된다. 롤백 처리를 하지 않고 추후에 처리를 할 수 있겠지만 문제가 되는 외부시스템에서 응답 시간이 오래 걸리게 되면 내부 서비스에도 영향을 준다. 그리고 외부 시스템이 내부 시스템 코드에 영향을 주는 문제도 생길 수 있다. 이는 외부 시스템과의 문제뿐만 아니라 내부 시스템간에도 생길수 있는 문제들이다. 이러한 문제는 BOUNDED COUNTEXT 간에 강결합(high coupling) 때문이다. 이러한 문제를 해결하는 방법이 있는데 그것은 바로 이벤트를 사용하는 것이다. 이벤트 관련 구성요소 이벤트 핸들러(handler)는 이벤트 생성 주체가 발..
JPA에서 동적 쿼리를 위한 스펙 구현 JPA는 다양한 검색 조건 조합을 위해 CritetiaBuilder와 Predicate를 이용해서 검색 조건을 구현해야 한다. /* JPA 리포지터리를 위한 Specification 인터페이스 */ public interface Specification { Predicagte toPredicate(Root root, CriteriaBuilder cb); } /* 스펙 구현 */ public class OrdererSpec implements Specification { private String ordererId; public OrdererSpec(String ordererId) { this.ordererId = ordererId; } @Overridee publi..
엔티티 (ENTITY) 고유의 식별자를 갖는 객체로 자신의 라이프사이클을 갖는다. 도메인 모델의 데이터를 포함하며 해당 데이터와 관련된 기능을 함께 제공한다. 밸류 (VALUE) 고유의 식별자를 갖지 않는 객체로 주로 개념적으로 하나인 도메인 객체의 속성을 표현할 때 사용한다. 엔티티의 속성으로 사용될 뿐만 아니라 다른 밸류 타입의 속성으로도 사용될 수 있다. 애그리거트 (AGGREGATE) 관련된 엔티티와 밸류 객체를 개념적으로 하나로 묶은 것 도메인 서비스 (DOMAIN SERVICE) 특정 엔티티에 속하지 않는 도메인 로직을 제공한다. 도메인 로직이 여러 엔티티와 밸류를 필요로 할 경우 도메인 서비스에서 로직을 구현한다. 예를 들어 '할인 금액 계산'은 상품, 쿠폰, 회원 등급, 구매 금액 등 다양..
표현 영역과 응용 영역은 사용자와 도메인을 연결해 주는 매개체 역활을 한다. 응용(Application) 영역 도메인 객체를 사용해 사용자가 요청한 기능을 실행한다. 표현 영역에서 보았을때 응용 서비스는 도메인 영역과 표현 영역을 연결해 주는 창구인 파사드(facade) 역활을 한다. 도메인 로직의 일부를 구현하지 않도록 주의해야 한다. 주된 역활 중 하나는 트랜잭션 처리이다. 응용 서비스의 구현 응용 서비스 자체는 복잡한 로직을 수행하지 않기 때문에 구현은 어렵지 않다. 구현은 어렵지 않지만 응용 서비스의 크기는 생각해보아야 한다. 보통 다음의 두 가지 방법 중 한 가지 방식으로 구현한다. 한 응용 서비스 클래스에 한 도메인의 모든 기능 구현하기 예) MemberService, OrderService ..
참조 투명성 관련 문제 public class OrderLine { privateProduct product; private Money price; private int quantity; public OrderLine(Product product, Money price, int quantity) { this.product = product; this.price = price; this.quantity = quantity; } } Product product = new Product("티셔츠"); Money price = new Money(1000); OrderLine line = new OrderLine(product, price, 2); // OrderLine에 price값이 변경될 수 있다. pric..
여러 애그리거트가 필요한 기능 도메인 영역의 코드를 작성하다 보면 한 애그리거트로 기능을 구현할 수 없을 때가 있다. 여러 애그리거트로 로직을 구현하게 되면 어떤 애그리거트가 주체인지 애매하다. 만약 한 애그리거트가 주체로 구현할 경우 해당 애그리거트는 책임 범위를 넘어서는 기능을 구현하기 때문에 코드가 길어지고 외부에 대한 의존이 높아지게 된다. 게다가 애그리거트의 범위를 넘어서는 도메인 개념이 애그리거트에 숨어들어서 명시적으로 드러나지 않게 된다. 이런 문제를 해소하기 위해 도메인 서비스를 별도로 구현한다. 도메인 서비스란? 한 애그리거트에 넣기 애매한 도메인 개념을 구현하려면 애그리거트에 억지로 넣기보다는 도메인 서비스를 이용하여 도메인 개념을 명시적으로 드러내면 된다. 도메인 서비스는 상태가 없이..
애그리거트와 트랜잭션 한 애그리거트가 여러곳의 호출에 의해 동시에 변경이 되는 걸 방지하기 위해 트랜잭션 처리 기법이 필요하다. 트랜잭션 처리 방식에는 선점(Pessimistic) 잠금과 비선점(Optimistic) 잠금 두 가지 방식이 있다. 선점(Pessimistic) 잠금 선점 잠금이란 먼저 애그리거트를 구한 스레드가 애그리거트 사용이 끝날때까지 다른 스레드가 해당 애그리거트를 수정하는 것을 막는 방식이다. 스레드1이 애그리거트를 수정하는 동안 블록킹이 되고 트랜잭션이 커밋되는 대기하고 있던 스레드2가 작동한다. 선점 잠금은 보통 DBMS가 제공하는 행 단위 잠금을 사용해서 구현한다. JPA의 EntityManager는 LockModeType을 인자로 받는 find() 메서드를 제공하는데, Lock..
애그리거트간에 참조 한 객체가 다른 객체를 참조하는 것 처럼 애그리거트도 다른 애그리거트를 참조한다. 애그리거트의 관리 주체가 애그리거트 루트이므로 애그리거트에서 다른 애그리거트를 참조하는 것은 애그리거트의 루트를 참조하는 것과 같다. 애그리거트를 참조하면 한 애그리거트에서 다른 애그리거트를 수정하지 않도록 주의해야 한다. JPA를 사용할 경우 지연(Lazy)로딩과 즉시(Eager)로딩 두가지 방식으로 로딩이 가능하다. 아이디를 이용한 간접 참조 ID를 이용한 참조는 DB 테이블에서 외래키를 사용해 참조한다. 장점 한 애그리거트에서 다른 애그리거트를 수정하는 문제를 원척적으로 방지할 수 있다. 애그리거트의 경계를 명확히 하고 물리적인 연결을 제거하기 때문에 모델의 복잡도를 낮춰준다. 애그리거트 간의 의존..
DIP(역전 의존 원칙)이란? 서비스가 특정 시스템에 의존성을 가지게 되면 서비스 자체만으로 테스트 수행이 어렵고 종속되는 시스템에 따라 서비스의 코드가 지속적으로 변경될 여지가 있다. 저수준 모델이 고수준 모델에 의존하도록 바꾸는 것 변경에 유연하고 테스트가 쉬움 핵심은 의존 관계를 맺을 때 변화하기 쉬운 것에 의존하기보다는, 변화하지 않는 것에 의존 해야한다. 예시 신용카드 클래스를 만든다고 했을때 신용카드에는 여러가지 종류에 은행이 있을것이다. class ShinhanCard { // 신한카드 public void pay() { // 결제 ... } public void pause() { // 카드정지 ... } } class HyunDaiCard { // 현대카드 public void pay() ..