Eternity's Chit-Chat

aeternum.egloos.com



Domain-Driven Design의 적용-1.VALUE OBJECT와 REFERENCE OBJECT 4부 Domain-Driven Design

지금까지 살펴본 방법에서는 Customer 클래스 자체에 ENTRY POINT의 컬렉션을 관리하는 인터페이스를 추가함으로써 시스템 내에 ENTRY POINT의 인스턴스가 하나만 유지되도록 만들었다. 또 다른 방법으로는 Customer 클래스와는 분리된 별도의 클래스에 Customer 클래스의 컬렉션 관리 인터페이스를 할당하는 방법이 있다.

 

우선 테스트 케이스를 작성하자.



CustomerTest.java

public void setUp() {

  Registrar.init();

}


public void testCustomerIdentical() {

  CustomerRepository customerRepository = new CustomerRepository();    

  Customer customer = new Customer("CUST-01", "홍길동", "경기도 안양시");

  customerRepository.save(customer);

  Customer anotherCustomer = customerRepository.find("CUST-01");

  assertSame(customer, anotherCustomer);

}


 

Customer 클래스를 통해 컬렉션 관리를 수행하던 이전의 예제와 달리 이번에는 CustomerRepository라는 별도의 REPOSITORY 객체를 사용해서 객체 컬렉션을 관리하고 있다.

 

별도의 객체로 검색 메커니즘을 분리했으므로 EntryPoint는 단순히 검색 키를 반환하는 메소드만을 제공하면 된다. 다음은 persist() 메소드를 제거한 EntryPoint 클래스 코드를 나타낸 것이다.



EntryPoint.java

package org.eternity.common;


public class EntryPoint {

  private final String identity;


  public EntryPoint(String identity) {

    this.identity = identity;

  }


  public String getIdentity() {

    return identity;

  }

}



Customer 클래스는 이제 더 이상 save() find() 메소드와 같은 컬렉션 관리 메소드를 제공하지 않아도 된다. 과감히 제거하자.



Customer.java

package org.eternity.customer;

 

import org.eternity.common.EntryPoint;


public class Customer extends EntryPoint {

private String customerNumber;

private String name;

private String address;

private long mileage;

      

public Customer(String customerNumber, String name, String address) {

super(customerNumber);

       this.customerNumber = customerNumber;

       this.name = name;

       this.address = address;

}

      

public void purchase(long price) {

       mileage += price * 0.01;

}

      

public boolean isPossibleToPayWithMileage(long price) {

       return mileage > price;

}

      

public boolean payWithMileage(long price) {

       if (!isPossibleToPayWithMileage(price)) {

             return false;

     }

            

       mileage -= price;

      

       return true;

}

      

public long getMileage() {

       return mileage;

}

}


Customer에 대한 컬렉션 관리 메커니즘을 제공하는 CustomerRepository Registrar를 사용하기 위한 세부 내용을 캡슐화 한다.



CustomerRepository.java

package org.eternity.customer;

 

import org.eternity.common.Registrar;

 

public class CustomerRepository {

 

public void save(Customer customer) {

       Registrar.add(Customer.class, customer);

}

 

public Customer find(String identity) {

       return (Customer)Registrar.get(Customer.class, identity);

}

}


테스트 케이스를 실행하자. 마침내 녹색 막대다! 예상한 대로 동일한 객체가 반환되었다. 한숨 돌렸다. 바야흐로 ENTRY POINT의 컬렉션을 관리할 수 있는 기본 인프라가 갖추어진 것이다. 이제 ENTRY POINT를 효율적으로 관리할 수 있게 되었다.

 

도메인의 복잡성

소프트웨어는 복잡하다. 0 1의 비트들을 갈아 먹이면 모든 것이 동작할 것이라는 단순한 예상과 달리, 0 1을 조합할 수 있는 무수히 많은 방법이 존재하기 때문에 소프트웨어는 복잡하다. 인간의 언어에 비해 표현력에 한계를 지닌 컴퓨터의 언어를 사용하기 때문에 단순할 것이라는 예상과 달리, 복잡한 인간 세상을 담아내야 하기 때문에 소프트웨어는 복잡하다. 설상가상으로 소프트웨어를 만드는 것이 근본적으로 불완전한 인간이기 때문에 소프트웨어 개발 과정 역시 복잡하고 불완전할 수 밖에 없다.

 

따라서 사람들은 지수적인 소프트웨어의 본질적인 복잡성을 선형적으로 완화하기 위해 다양한 기법들을 적용해 왔다. 이 기법들의 우두머리가 추상화(abstraction). 불필요한 군더더기를 제거하고 현재의 문제 해결에 필요한 핵심 개념만을 끌어 안음으로써 문제영역의 복잡성을 감소시키는 기법을 추상화라고 한다. REFERENCE OBJECTVALUE OBJECT의 개념 역시 도메인 영역을 추상화 시키는 한 방법이다.

 

REFERENCE OBJECTVALUE OBJECT의 분리는 도메인 개념들의 추적성 및 식별성을 추상화하기 위한 분석 기법이다. 도메인 영역의 개념을 REFERENCE OBJECTVALUE OBJECT로 분리함으로써 도메인의 본질적인 특성에 초점을 맞추게 된다.

 

고객은 유일한가? 고객을 유일하게 구분 짓는 특성은 무엇일까? 시스템은 고객의 주문 및 구매 기록을 추적하기 위해 어떤 처리를 해야 하는가? 금액은 유일할 필요가 없는가? 단순하게 값만 비교하면 되는가?

 

도메인 개념에 대한 이런 질문들은 도메인에 대한 이해를 향상시키고 소프트웨어의 전반적인 복잡성을 완화시키는 유용한 분석 기법이다. REFERENCE OBJECT를 식별함으로써 시스템의 핵심 개념들의 생명 주기에 초점을 맞출 수 있다. VALUE OBJECT를 식별함으로써 도메인의 일부지만 중요하지 않은 개념들을 걸러낼 수 있다.

 

메모리 상에서 REFERENCE OBJECTVALUE OBJECT를 관리하는 것은 그리 어렵지 않다. 그러나 데이터베이스와 같은 영속성 메커니즘이 끼어드는 순간 세상은 급격하게 일그러진다. 그 위에 다중 사용자 지원을 위한 동시성 메커니즘이 얹어지기라도 하면 REFERENCE OBJECTVALUE OBJECT에 대한 근본적인 개념에 금이 가기 시작한다. 이제부터는 단순히 언어적인 측면에서 객체를 구별하던 REFERENCE OBJECTVALUE OBJECT의 개념을 넘어 인프라 스트럭쳐나 구현과 세부 구현과 관련된 문제도 함께 고려해야 한다.

 

다음 아티클에서는 REFERENCE OBJECTVALUE OBJECT를 사용하여 간단한 도메인을 모델링하고 이번 아티클에서 간단하게 설명한 ENTRY POINT AGGREGATE, REPOSITORY에 관해 좀 더 자세히 살펴보기로 한다. 


핑백

  • Domain-Driven Design | Jongmin Kim's Blog 2014-09-02 01:18:36 #

    ... Driven Design의 적용-2.AGGREGATE와 REPOSITORY 1부 2008/11/17 Domain-Driven Design의 적용-1.VALUE OBJECT와 REFERENCE OBJECT 4부 [4] 2008/11/17 Domain-Driven Design의 적용-1.VALUE OBJ ... more

덧글

  • 김성현 2009/08/05 12:20 # 삭제

    안녕하세요
    궁금 한게 있어서요...
    한곳에서 Map으로 Customer를 관리하게 되는데
    Customer가 수백만명 이라면 Map에 수백만건이 들어가는 구조가 맞나요?
    그렇다면 성능상의 문제나 메모리 문제는 없나 궁금해서요
    좋은 하루 되세요~
  • 이터너티 2009/08/05 17:04 #

    안녕하세요.
    여기에서는 도메인 객체의 컬렉션을 관리하는 Repository의 개념을 설명하기 위해 메모리 상의 Map으로 구현한 것이고요, 4장의 영속성 메커니즘에 관련된 설명을 보시면 아실 수 있지만 실제로는DB를 사용해서 관리합니다.
    단, Repository 자체는 내부적으로 DB를 사용하는지 메모리를 사용하는지에 무관하기 때문에 설계/구현 시 단순히 객체 컬렉션 관리라는 의미로 인터페이스를 구성하는 것이 좋습니다.
    문의 주신 내용은 연재의 후반부에 가면 자연스럽게 해결되리라 생각합니다.
    감사합니다. ^^
  • 김성현 2009/08/05 17:35 # 삭제

    감사합니다 ^^
    후딱 읽어야 겠네요~!
  • 영농후계자 2009/11/04 18:00 # 삭제

    정말 깔끔하게 정리를 잘해주셨네요.
    감사합니다.
  • 최빈 2013/10/02 14:49 # 삭제

    정말 읽기 쉽게 잘써주셨네요 머릿속에 쏙쏙 들어옵니다. 감사합니다 ~!!
  • 핼리 2014/05/09 08:44 # 삭제

    역시나 ㅎㅎ
  • 이주형 2015/07/16 12:57 # 삭제

    훌륭한 글 고맙습니다.
  • 이터너티 2015/07/16 14:43 #

    도움이 되셨으면 좋겠네요. ^^
※ 로그인 사용자만 덧글을 남길 수 있습니다.