ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DDD - Dependency Injection과 AOP 1부
    JAVA/DDD 2021. 1. 11. 19:29
    • 애플리케이션의 모든 기억들은 종료되는 순간 깨끗하게 증발돼 버리고 만다. 
    • 애플리케이션은 상태를 끊임없이 기록하고, 기억을 재생하고, 현실을 재구성해야 한다. 
    • 유효 시간이 지나고 단기 기억 상실증으로 인해 모든 기억이 소멸되더라도 기록을 통해 어플리케이션의 기억을 되돌릴  있어야 한다.

     

    • 애플리케이션이 기억을 재생할 수 있다고 해서 모든 기억을 동시에 복구하는 것은 소모적인 일이다.
    • 살아오면서겪은 모든 일들을 일일이  기억하고 있을 수는 없다.
    • 애플리케이션 역시 마찬가지다. 지금 처리하기 위해 필요한 최소한의 정보만 기억하고 있으면 된다. 

     

    • 시스템의 메모리는 한정된 자원이다. 
    • 지금 당장 필요하지도 않은 정보들을 유지하기 위해 값비싼 자원을 낭비할 필요는 없다. 
    • 잠시 잊어 버렸다가 필요할  기록을 들춰 보면 된다.

     

     

    • 인간이 컴퓨터에게  최고의 선물은 영구적인 기억력이다. 
    • 그러나 영구적인 기억력이 하늘에서 뚝하고 떨어지는 것은 아니다. 
    • 애플리케이션을망각의 늪에서 구원하기 위해서는 지금까지 우리가 망각하고 있던  가지 요소가 필요하다. 
    • 바로 영속성(persistence) 그것이다.

     

     

     

    도메인 객체의


    • 주문 도메인에서 ENTRY POINT 대한 저장, 조회 등의 컬렉션 연산을 수행하기 위해 REPOSITORY 사용했다.
    • 주문 도메인을 분석한  Customer, Product, Order ENTRY POINT 식별하고 
    •  ENTRY POINT 생명 주기를 관리하기 위해 CustomerRepository, ProductRepository, OrderRepository 도메인 모델에 추가했다.

     

    주문 도메인 모델의 REPOSITORY

     

    • Order OrderLineItem 생명 주기를   자세히 살펴보자.
    • Order OrderLineItem Customer newOrder() 메소드를 통해 생성된다.
    • newOrder() 메소드는 Order CREATION METHOD order() 호출하며,  메소드는 내부적으로 생성자를 호출하여 Order 클래스를 생성한  반환한다.
    • OrderLineItem Order with() 메소드를 사용하여 생성되며, with() 메소드 역시 OrderLineItem 생성자를 호출하여 인스턴스를 생성한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class Order {
        
        public static Order order(String orderId, Customer customer) {
            return new Order(orderId, customer);
        }
        
        Order(String orderId, Customer customer) {
            super(orderId);
            this.customer = customer;
        }
        
        public Order with(String productName, int quantity)
                throws OrderLimitExceededException {
            return with(new OrderLineItem(productName, quantity));
        }
    }
    cs

     

    • Order OrderLineItem 생성자가 호출되는 순간 사용자가 입력한 주문 정보를 저장하고 있는 주문 AGGREGATE가 생성된다. 
    • 그러나 객체를 생성하는 것으로 끝난다면 지금까지 이야기해 왔던 REFERENCE OBJECT 추적성과 유일성을 만족시킬  없다. 
    • 생성된 주문 객체가 어플리케이션의 생명주기 동안 동일한 객체로 참조되기 위해서는 REPOSITORY 필요하다. 

     

    • 생성된 객체는 REPOSITORY 의해 관리되며 객체가 필요한 경우 REPOSITORY 통해 해당 REFERENCE OBJECT 얻을  있게 된다. 
    • 물론 REPOSITORY 통해 등록된 객체와 조회된 객체의 식별자(identity)는 동일해야 한다. 테스트를 추가하자.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class OrderTest {
     
        public void testOrderIdentical() throws Exception {
            Order order = customer.newOrder("CUST-01-ORDER-01")
                    .with("상품1"10)
                    .with("상품2"20);
            orderRepository.save(order);
     
            
            Order anotherOrder = orderRepository.find("CUST-01-ORDER-01");
            assertEquals(order, anotherOrder);
        }
    }
     
    cs

     

    • 테스트는 통과한다.
    • REPOSITORY 통해 등록된 주문 객체들은 추적성과 유일성이라는 REFERENCE OBJECT 본연의 특성을 만족시키고 있다.

     

    • 이번에는 생성된 주문 내역을 삭제하는 시나리오를 구현해 보자.
    • 문의 생명 주기를 관리하는 클래스는 OrderRepository이므로 여기에 삭제 관련 메서드를 추가하자.
    • 먼저 OrderRepositoryTest 클래스에 주문을 삭제하는 테스트를 추가하자.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class OrderTest {
     
        public void testDeleteOrder() throws Exception {
     
            orderRepository.save(customer.newOrder("CUST-01-ORDER-01")
                    .with("상품1"5)
                    .with("상품2"20);
            
            Order order = orderRepository.find("CUST-01-ORDER-01");
            orderRepository.delete("CUST-01-ORDER-01");
     
            
            assertNull(orderRepository.find("CUST-01-ORDER-01"));
            assertNotNull(order);
        }
    }
     
    cs

     

    • 주문 건을 생성한  REPOSITORY 등록한다. 
    • 등록이 성공하면 해당 주문을 REPOSITORY로부터 삭제한다. 삭제 역시 조회의 경우와 마찬가지로 삭제할 주문 객체를 명시하기 위해 주문 ID 인자로 전달한다.
    • REPOSITORY에서 삭제되었다는 것을 확인하기 위해 주문 객체를 조회한  결괏값이 null인지를 확인한다.

     

    • 테스트 메서드는 REPOSITORY에서 delete() 메소드를 호출하여 주문 객체를 삭제하기 전에 find() 메소드를 호출하여 REPOSITORY로부터 생성된 객체에 대한 참조를 보관한다.
    • delete() 메소드를 호출하여 REPOSITORY로부터 해당 객체를 삭제한  앞에서 조회한 객체가 null이 아닌지를

     

    • REPOSITORY 관점에서의 삭제는  이상 해당 객체를 REFERENCE OBJECT 취급하지 않겠다는 것을 의미한다. 
    • , 시스템이 해당 주문 객체의 추적성을 보장하지 않겠다는 의미이다. 
    • 따라서 일단 삭제가 완료되면  이상 REPOSITORY 통해 해당 객체를 얻을  없게 된다. 

     

    • 이것을 주문 객체 자체의 소멸과 혼동해서는  된다. 
    • 단지 주문 객체가 REPOSITORY 제어에서 벗어나 추적성과 유일성을 잃을 뿐이지 객체 자체가 소멸되는 것은 아니다. 
    • 객체의 소멸은 가비지 컬렉터에 의해서만 가능하다.

     

    • REPOSITORY 삭제 메서드를 추가하기 위해 Registrar 삭제와 관련된 기본 기능을 추가하자. 
    •  ENTRY POINT 클래스와 연관된 Map으로부터 검색 키의 엔트리를 삭제한  반환하도록 구현한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Registrar {
     
        public static EntryPoint delete(Class<?> entryPointClass,
                                        String objectName) {
            return soleInstance.deleteObj(entryPointClass, objectName);
        }
     
        @SuppressWarnings("unused")
        private EntryPoint deleteObj(Class<?> entryPointClass, String objectName) {
            Map<String,EntryPoint> theEntryPoint =
                    entryPoints.get(entryPointClass);
            return theEntryPoint.remove(objectName);
        }
    }
    cs

     

    • Registrar 사용하여 OrderRepository 주문 삭제 메소드를 추가한다.

     

    1
    2
    3
    4
    5
    6
    7
    public class OrderRepository {
     
        public Order delete(String identity) {
            return (Order)Registrar.delete(Order.class, identity);
        }
    }
     
    cs

     

    • 테스트는 통과한다.
    • 시스템은 REFERENCE OBJECT 정상적으로 추적하고 있으며, REPOSITORY 객체의 생명 주기를 관리하기 위해 필요한 모든 기능을 제공하고 있다. 

     

    참조


    이터니티 - Domain-Driven Design의 적용

     

    'JAVA > DDD' 카테고리의 다른 글

    DDD - Dependency Injection과 AOP 3부  (0) 2021.01.22
    DDD - Dependency Injection과 AOP 2부  (0) 2021.01.22
    AGGREGATE와 REPOSITORY 5부  (0) 2021.01.08
    AGGREGATE와 REPOSITORY 4부  (0) 2021.01.05
    Aggregate와 Repository 3부  (0) 2020.12.30
Designed by Tistory.