-
DDD - Value Object와 Reference Object 4부JAVA/DDD 2020. 12. 24. 20:49
- 앞 선 예제에서는 Customer 클래스 자체에 ENTRY POINT의 컬렉션을 관리하는 인터페이스를 추가함으로써 시스템 내에 ENTRY POINT의 인스턴스가 하나만 유지되도록 만들었다.
- 또 다른 방법으로는 Customer 클래스와는 분리된 별도의 클래스에 Customer 클래스의 컬렉션 관리 인터페이스를 할당하는 방법이 있다.
1234567891011121314151617181920212223public 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);}cs - Customer 클래스를 통해 컬렉션 관리를 수행하던 이전의 예제와 달리
- 이번에는 CustomerRepository라는 별도의 REPOSITORY 객체를 사용해서 객체 컬렉션을 관리하고 있다.
- 별도의 객체로 검색 메커니즘을 분리했으므로 EntryPoint는 단순히 검색 키를 반환하는 메서드만을 제공하면 된다.
- 다음은 persist() 메소드를 제거한 EntryPoint 클래스 코드를 나타낸 것이다.
123456789101112131415161718192021public class EntryPoint {private final String identity;public EntryPoint(String identity) {this.identity = identity;}public String getIdentity() {return identity;}}cs - Customer 클래스는 이제 더 이상 save()와 find() 메소드와 같은 컬렉션 관리 메서드를 제공하지 않아도 된다.
- 과감히 제거하자.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273import 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;}}cs - Customer에 대한 컬렉션 관리 메커니즘을 제공하는 CustomerRepository는
- Registrar를 사용하기 위한 세부 내용을 캡슐화 한다.
12345678910public class CustomerRepository {public void save(Customer customer) {Registrar.add(Customer.class, customer);}public Customer find(String identity) {return (Customer)Registrar.get(Customer.class, identity);}}cs - 이제 테스트 케이스를 실행하자.
- 예상한 대로 동일한 객체가 반환되었다.
- ENTRY POINT의 컬렉션을 관리할 수 있는 기본 인프라가 갖추어진 것이다.
- 이제 ENTRY POINT를 효율적으로 관리할 수 있게 되었다.
도메인의 복잡성
- 소프트웨어는 복잡하다. 0과 1의 비트들을 갈아 먹이면 모든 것이 동작할 것이라는 단순한 예상과 달리, 0과 1을 조합할 수 있는 무수히 많은 방법이 존재하기 때문에 소프트웨어는 복잡하다.
- 인간의 언어에 비해 표현력에 한계를 지닌 컴퓨터의 언어를 사용하기 때문에 단순할 것이라는 예상과 달리, 복잡한 인간 세상을 담아내야 하기 때문에 소프트웨어는 복잡하다
- 설상가상으로 소프트웨어를 만드는 것이 근본적으로 불완전한 인간이기 때문에 소프트웨어 개발 과정 역시 복잡하고 불완전할 수밖에 없다.
- 따라서 사람들은 지수적인 소프트웨어의 본질적인 복잡성을 선형적으로 완화하기 위해 다양한 기법들을 적용해 왔다.
- 이 기법들의 우두머리가 추상화(abstraction)다. 불필요한 군더더기를 제거하고
- 현재의 문제 해결에 필요한 핵심 개념만을 끌어안음으로써 문제 영역의 복잡성을 감소시키는 기법을 추상화라고 한다.
- REFERENCE OBJECT와 VALUE OBJECT의 개념 역시 도메인 영역을 추상화시키는 한 방법이다.
- REFERENCE OBJECT와 VALUE OBJECT의 분리는 도메인 개념들의 추적성 및 식별성을 추상화하기 위한 분석 기법이다.
- 도메인 영역의 개념을 REFERENCE OBJECT와 VALUE OBJECT로 분리함으로써 도메인의 본질적인 특성에 초점을 맞추게 된다.
- 고객은 유일한가?
- 고객을 유일하게 구분 짓는 특성은 무엇일까?
- 시스템은 고객의 주문 및 구매 기록을 추적하기 위해 어떤 처리를 해야 하는가?
- 금액은 유일할 필요가 없는가?
- 단순하게 값만 비교하면 되는가?
- 도메인 개념에 대한 이런 질문들은 도메인에 대한 이해를 향상하고 소프트웨어의 전반적인 복잡성을 완화하는 유용한 분석 기법이다.
- REFERENCE OBJECT를 식별함으로써 시스템의 핵심 개념들의 생명 주기에 초점을 맞출 수 있다. VALUE OBJECT를 식별함으로써 도메인의 일부지만 중요하지 않은 개념들을 걸러낼 수 있다
- 메모리 상에서 REFERENCE OBJECT와 VALUE OBJECT를 관리하는 것은 그리 어렵지 않다.
- 그러나 데이터베이스와 같은 영속성 메커니즘이 끼어드는 순간 세상은 급격하게 일그러진다.
- 그 위에 다중 사용자 지원을 위한 동시성 메커니즘이 얹어지기라도 하면 REFERENCE OBJECT와 VALUE OBJECT에 대한 근본적인 개념에 금이 가기 시작한다.
- 이제부터는 단순히 언어적인 측면에서 객체를 구별하던 REFERENCE OBJECT와 VALUE OBJECT의 개념을 넘어 인프라 스트럭쳐나 구현과 세부 구현과 관련된 문제도 함께 고려해야 한다.
참조
이터니티 - Domain-Driven Design의 적용
'JAVA > DDD' 카테고리의 다른 글
AGGREGATE와 REPOSITORY 2부 (0) 2020.12.29 AGGREGATE와 REPOSITORY 1부 (0) 2020.12.28 DDD Value Object와 Reference Object 3부 (0) 2020.12.23 DDD - Value Object와 Reference Object 2부 (0) 2020.12.22 DDD - Value Object와 Reference Object (0) 2020.12.21