06 도메인 객체의 생명주기
도메인 객체
- 생명주기 동안의 무결성 유지
- 생명주기 관리의 복잡성으로 모델이 난해해지는 것 방지
세가지 패턴
- AGGREGATE (집합체) : 소유권과 경계를 명확하게 정의하여 객체 간의 연관관계를 확실히 한다.
- FACTORY (팩토리) : 복잡한 객체와 AGGREGATE를 생성 및 재구성하여 내부 구조를 캡슐화 한다.
- REPOSITORY (레포지터리) : 인프라스트럭처를 캡슐화하여 영속 객체를 찾아 조회한다.
AGGREGATE (집합체)
목표 : ENTITY와 VALUE OBJECT 각각의 경계를 정의하는 AGGREGATE를 생성해라.
소프트웨어 설계
- 대부분의 업무 도메인은 상호 연관의 정도가 높아 관계망이 많고 복잡하다.
- 모델 내에서 복잡한 연관관계를 맺는 객체를 대상으로 변경의 일관성을 보장하기 쉽지 않다.
- 여기서 잠금 기법은 다수의 사용자가 사용하는 시스템에 적합하지 않다.
- 도메인을 심층적으로 이해하고 있어야 한다.
- 경합이 높은 지점을 느슨하게 하고 엄격한 불변식을 엄격하게 지켜지게 하는 모델을 만들어야 한다.
AGGREGATE
- 데이터 변경을 단위로 하는 연관 객체의 묶음
- 루트 (ROOT) + 경계 (BOUNDARY)
- 루트는 단 하나만 존재하며 AGGREGATE에 존재하는 특정 엔티티를 의미
- 경계 안의 객체들은 서로 참조 가능, 경계 밖의 객체는 해당 AGGREGATE의 요소 중 루트만 참조 가능
- 루트 이외의 엔티티는 지역 식별성을 지니며 해당 AGGREGATE 내에서만 구분
불변식
- 데이터가 변경될 때마다 유지돼야 하는 일관성 규칙
- 불변식에는 AGGREGATE를 구성하는 각 구성요소 간의 관계도 포함된다.
- 한 AGGREGATE에 적용된 불변식은 각 트랜잭션이 완료될 때 이행된다.
- AGGREGATE 경계 안 어떤 객체를 변경하더라도 불변식은 지켜져야 한다.
예제) 구매주문 시스템
시스템의 문제
- 새로운 주문 품목이 추가될 때마다 한도 초과 여부를 체크해야 한다.
→ 올바르지 않은 불변식 이행 - 구매 주문이 삭제/저장될 때 주문 품목도 함께 삭제/저장해야 하는데 관계를 어디서 끊어야 하는지 명확하지 않다.
→ 변화 관리의 문제 - 데이터베이스에서 다수의 사용자로 인한 경합 문제가 발생한다.
→ 올바르지 않은 데이터베이스 공유
올바르지 않은 해결 > 데이터베이스 잠금 기법
- 개별 트랜잭션에서 동시 수정이 진행된다면 다른 사용자의 변경 내역이 포함되지 않을 것이다.
- 두 사용자가 각자 작업을 하고 나면 도메인 모델의 불변식을 위반한 채로 데이터베이스에 저장된다.
올바른 해결 > 도메인에 AGGREGATE 적용
- 품목은 여러 구매 주문에서 사용된다.
- 구매 주문보다는 품목의 변경이 더 적다.
- 주문한 품목의 가격은 현재 품목 가격과 다를 수 있다.
FACTORY (팩토리)
목표 : 복잡한 객체와 AGGREGATE의 인스턴스를 생성하는 책임을 하는 FACTORY를 만들어라.
객체 생성
- 객체의 존재 이유와 관련 없거나 해당 객체의 역할을 보조하지 않는다면 해당 객체에서 제거해야 한다.
- 객체를 생성하는 것과 별개로 생성된 객체를 가지고 연산하는 것은 생성된 객체의 책임이 아니다.
- 복잡한 객체를 생성/연산하는 것은 도메인 계층의 책임이지만 이것이 모델을 표현하는 객체에 속하지 않는다.
FACTORY
- 클라이언트의 목적과 생성된 객체의 추상적인 관점을 반영하는 인터페이스 제공
- 복잡한 객체 생성/연산 과정을 캡슐화
- 클라이언트가 구상 클래스와 결합되는 것 방지
FACTORY 설계
- 각 생성 방법은 원자적이어야 하고 불변식을 모두 지켜야 한다.
- 일관성 있는 상태에서만 객체를 만들어낼 수 있어야 한다.
- ENTITY : 전체 AGGREGATE를 생성하는 것
- VALUE OBJECT : 모든 속성이 올바른 최종 상태로 초기화되는 것
- 생성된 클래스가 아닌 생성하고자 하는 타입으로 추상화되어야 한다.
FACTORY 위치
- 이미 존재하는 AGGREGATE에 요소를 추가해야 한다면 루트에 FACTORY METHOD를 만들 수 있다.
- AGGREGATE의 무결성을 루트가 보장하고 외부로부터 AGGREGATE의 내부 구현을 감출 수 있다.
- 루트가 해당 FACTORY에 있기에 적절하지 않다면 독립형 FACTORY를 만들어도 된다.
생성자만으로 충분한 경우
- FACTORY는 다형성을 활용하지 않는 간단한 객체를 더 어렵게 만들 수 있다.
- 이럴 경우 PUBLIC CONSTRUCTOR를 사용하는 편이 좋다.
FACTORY METHOD 설계
- 각 연산은 원자적이야 하므로 결과물을 만들어내기에 필요한 모든 것은 한번에 FACTORY에 전달해야 한다.
- FACTORY는 자신에게 전달된 인자에 신경 쓴다면 결합이 높아진다는 의미임으로 의존성이 적당해야 한다.
저장된 객체의 재구성
- 재구성에 사용된 ENTITY FACTORY는 새로운 ID를 할당하지 않는다.
- 객체를 재구성하는 FACTORY는 불변식 위반을 다른 방식으로 처리할 것이다.
REPOSITORY (레포지터리)
목표 : 모델 객체를 추가/삭제하는 메서드를 만들어 실제로 데이터를 삽입/삭제하는 연산을 하는 REPOSITORY를 만들어라.
객체 참조 생성
- 객체를 생성하여 객체 참조를 만든다.
- 객체의 연관관계를 토대로 객체 참조를 찾는다.
데이터베이스 질의 직접 수행의 문제점
- 데이터베이스에서 필요한 데이터만 가져와 생성자나 FACTORY에 넘기면 모델에 집중하기 힘들어진다.
- AGGREATE나 캡슐화 같은 특징을 활용하는 것을 우회하려 한다.
- 그렇게 되면 코드는 업무에 관한 정보를 전해주지 않고 오로지 데이터 조회 기술만을 다루게 된다.
- 모델 객체를 다룰 때 (이면의 장치를 통해) 데이터베이스 객체가 자동으로 삽입/삭제 되도록 해야 한다.
도메인 주도 설계의 목표는 기술보다는 도메인에 대한 모델에 집중해 더 나은 소프트웨어를 만들어내는 것
REPOSITORY
- 영속화된 객체의 생명주기를 관리하기 위한 단순한 모델을 클라이언트에게 제시한다.
- 데이터베이스 코드 또는 데이터베이스 전략과 도메인 설계를 분리한다.
- 객체 접근에 관한 설계 결정을 전한다.
- 테스트에 사용될 가짜 구현을 손쉽게 만들 수 있다.
REPOSITORY 설계
- 가장 간단하게는 질의에 구체적인 매개변수를 직접 입력하도록 할 수 있다.
- 여기에 SPECIFICATION 질의를 사용하면 가장 보편적인 REPOSITORY 질의를 생성할 수 있다.
- 데이터가 어디에 있든 (어느 저장소를 이용하든) 클라이언트 코드는 동일하게 유지되어야 한다.
- 따라서 저장, 조회, 질의 메커니즘을 캡슐화한다.
REPOSITORY 개념
- 타입을 추상화한다.
- 클라이언트와의 분리를 활용한다.
- 트랜잭션 제어를 클라이언트에 둔다.
07 언어의 사용 (확장 예제)
(생략)
'꾸준히 하기 > 스터디' 카테고리의 다른 글
모델 주도 설계의 기본 요소 | 04 - 05 (0) | 2024.05.07 |
---|---|
동작하는 도메인 만들기 | 01 - 03 (0) | 2024.04.29 |