지원 서재
작성일
2024. 5. 20. 15:45
작성자
달빛오리

06 도메인 객체의 생명주기

 

도메인 객체

  1. 생명주기 동안의 무결성 유지
  2. 생명주기 관리의 복잡성으로 모델이 난해해지는 것 방지

 

세가지 패턴

  • AGGREGATE (집합체) : 소유권과 경계를 명확하게 정의하여 객체 간의 연관관계를 확실히 한다.
  • FACTORY (팩토리) : 복잡한 객체와 AGGREGATE를 생성 및 재구성하여 내부 구조를 캡슐화 한다.
  • REPOSITORY (레포지터리) : 인프라스트럭처를 캡슐화하여 영속 객체를 찾아 조회한다.

 

AGGREGATE (집합체)

목표 : ENTITY와 VALUE OBJECT 각각의 경계를 정의하는 AGGREGATE를 생성해라.

 

소프트웨어 설계

  • 대부분의 업무 도메인은 상호 연관의 정도가 높아 관계망이 많고 복잡하다.
  • 모델 내에서 복잡한 연관관계를 맺는 객체를 대상으로 변경의 일관성을 보장하기 쉽지 않다.
  • 여기서 잠금 기법은 다수의 사용자가 사용하는 시스템에 적합하지 않다.
  • 도메인을 심층적으로 이해하고 있어야 한다.
  • 경합이 높은 지점을 느슨하게 하고 엄격한 불변식을 엄격하게 지켜지게 하는 모델을 만들어야 한다.

 

AGGREGATE 

  • 데이터 변경을 단위로 하는 연관 객체의 묶음
  • 루트 (ROOT) + 경계 (BOUNDARY)
  • 루트는 단 하나만 존재하며 AGGREGATE에 존재하는 특정 엔티티를 의미
  • 경계 안의 객체들은 서로 참조 가능, 경계 밖의 객체는 해당 AGGREGATE의 요소 중 루트만 참조 가능
  • 루트 이외의 엔티티는 지역 식별성을 지니며 해당 AGGREGATE 내에서만 구분

 

불변식

  • 데이터가 변경될 때마다 유지돼야 하는 일관성 규칙
  • 불변식에는 AGGREGATE를 구성하는 각 구성요소 간의 관계도 포함된다.
  • 한 AGGREGATE에 적용된 불변식은 각 트랜잭션이 완료될 때 이행된다.
  • AGGREGATE 경계 안 어떤 객체를 변경하더라도 불변식은 지켜져야 한다.

 

예제) 구매주문 시스템

 

시스템의 문제

  1. 새로운 주문 품목이 추가될 때마다 한도 초과 여부를 체크해야 한다.
    → 올바르지 않은 불변식 이행
  2. 구매 주문이 삭제/저장될 때 주문 품목도 함께 삭제/저장해야 하는데 관계를 어디서 끊어야 하는지 명확하지 않다.
    → 변화 관리의 문제
  3. 데이터베이스에서 다수의 사용자로 인한 경합 문제가 발생한다.
    → 올바르지 않은 데이터베이스 공유

 

올바르지 않은 해결 > 데이터베이스 잠금 기법

  • 개별 트랜잭션에서 동시 수정이 진행된다면 다른 사용자의 변경 내역이 포함되지 않을 것이다.
  • 두 사용자가 각자 작업을 하고 나면 도메인 모델의 불변식을 위반한 채로 데이터베이스에 저장된다.

 

올바른 해결 > 도메인에 AGGREGATE 적용

Part의 가격이 Purchase Order Line Item의 가격으로 복사된다.

  1. 품목은 여러 구매 주문에서 사용된다.
  2. 구매 주문보다는 품목의 변경이 더 적다.
  3. 주문한 품목의 가격은 현재 품목 가격과 다를 수 있다.

 

FACTORY (팩토리)

목표 : 복잡한 객체와 AGGREGATE의 인스턴스를 생성하는 책임을 하는 FACTORY를 만들어라.

 

객체 생성

  • 객체의 존재 이유와 관련 없거나 해당 객체의 역할을 보조하지 않는다면 해당 객체에서 제거해야 한다.
  • 객체를 생성하는 것과 별개로 생성된 객체를 가지고 연산하는 것은 생성된 객체의 책임이 아니다.
  • 복잡한 객체를 생성/연산하는 것은 도메인 계층의 책임이지만 이것이 모델을 표현하는 객체에 속하지 않는다.

 

FACTORY

  • 클라이언트의 목적과 생성된 객체의 추상적인 관점을 반영하는 인터페이스 제공
  • 복잡한 객체 생성/연산 과정을 캡슐화
  • 클라이언트가 구상 클래스와 결합되는 것 방지

 

FACTORY 설계

  • 각 생성 방법은 원자적이어야 하고 불변식을 모두 지켜야 한다.
  • 일관성 있는 상태에서만 객체를 만들어낼 수 있어야 한다.
    • ENTITY : 전체 AGGREGATE를 생성하는 것
    • VALUE OBJECT : 모든 속성이 올바른 최종 상태로 초기화되는 것
  • 생성된 클래스가 아닌 생성하고자 하는 타입으로 추상화되어야 한다.

 

FACTORY 위치

  • 이미 존재하는 AGGREGATE에 요소를 추가해야 한다면 루트에 FACTORY METHOD를 만들 수 있다.
  • AGGREGATE의 무결성을 루트가 보장하고 외부로부터 AGGREGATE의 내부 구현을 감출 수 있다.
  • 루트가 해당 FACTORY에 있기에 적절하지 않다면 독립형 FACTORY를 만들어도 된다.

 

생성자만으로 충분한 경우

  • FACTORY는 다형성을 활용하지 않는 간단한 객체를 더 어렵게 만들 수 있다.
  • 이럴 경우 PUBLIC CONSTRUCTOR를 사용하는 편이 좋다.

 

FACTORY METHOD 설계

  • 각 연산은 원자적이야 하므로 결과물을 만들어내기에 필요한 모든 것은 한번에 FACTORY에 전달해야 한다.
  • FACTORY는 자신에게 전달된 인자에 신경 쓴다면 결합이 높아진다는 의미임으로 의존성이 적당해야 한다.

 

저장된 객체의 재구성

  1. 재구성에 사용된 ENTITY FACTORY는 새로운 ID를 할당하지 않는다.
  2. 객체를 재구성하는 FACTORY는 불변식 위반을 다른 방식으로 처리할 것이다.

 

REPOSITORY (레포지터리)

목표 : 모델 객체를 추가/삭제하는 메서드를 만들어 실제로 데이터를 삽입/삭제하는 연산을 하는 REPOSITORY를 만들어라.

 

객체 참조 생성

  • 객체를 생성하여 객체 참조를 만든다.
  • 객체의 연관관계를 토대로 객체 참조를 찾는다.

 

데이터베이스 질의 직접 수행의 문제점

  • 데이터베이스에서 필요한 데이터만 가져와 생성자나 FACTORY에 넘기면 모델에 집중하기 힘들어진다.
  • AGGREATE나 캡슐화 같은 특징을 활용하는 것을 우회하려 한다.
  • 그렇게 되면 코드는 업무에 관한 정보를 전해주지 않고 오로지 데이터 조회 기술만을 다루게 된다.
  • 모델 객체를 다룰 때 (이면의 장치를 통해) 데이터베이스 객체가 자동으로 삽입/삭제 되도록 해야 한다.

 

 

도메인 주도 설계의 목표는 기술보다는 도메인에 대한 모델에 집중해 더 나은 소프트웨어를 만들어내는 것

 

REPOSITORY

  • 영속화된 객체의 생명주기를 관리하기 위한 단순한 모델을 클라이언트에게 제시한다.
  • 데이터베이스 코드 또는 데이터베이스 전략과 도메인 설계를 분리한다.
  • 객체 접근에 관한 설계 결정을 전한다.
  • 테스트에 사용될 가짜 구현을 손쉽게 만들 수 있다.

 

REPOSITORY 설계

  • 가장 간단하게는 질의에 구체적인 매개변수를 직접 입력하도록 할 수 있다.
  • 여기에 SPECIFICATION 질의를 사용하면 가장 보편적인 REPOSITORY 질의를 생성할 수 있다.
  • 데이터가 어디에 있든 (어느 저장소를 이용하든) 클라이언트 코드는 동일하게 유지되어야 한다.
  • 따라서 저장, 조회, 질의 메커니즘을 캡슐화한다.

즉, REPOSITORY는 데이터 저장소를 캡슐화한다.

REPOSITORY 개념

  • 타입을 추상화한다.
  • 클라이언트와의 분리를 활용한다.
  • 트랜잭션 제어를 클라이언트에 둔다.

07 언어의 사용 (확장 예제)

 

(생략)