도메인 객체의 생명주기

모든 객체에는 생명주기가 있다. MODEL-DRIVEN DESIGN에서는 이러한 객체들을 관리하는것이 중요하다.

도메인 객체의 관리와 관련된 문제는 두 가지 범주로 나뉜다.

  1. 생명주기 동안의 무결성 유지하기

  2. 생명주기 관리의 복잡성으로 모델이 난해해지는 것을 방지하기

AGGREGATE, FACTORY, REPOSITORY 세 가지 패턴을 사용해서 문제를 해결한다.

AGGREGATE

데이터 변경의 단위로 다루는 연관 객체의 묶음

경계 : AGGREATE에 무엇이 포함되고 포함되지 않는지를 정의
루트 : 하나만 존재하며, AGGREGATE에 포함된 특정 ENTITY를 가리킴

경계 안의 객체는 서로 참조할 수 있지만, 경계 바깥의 객체는 루트만 참조할 수 있다. AGGREGATE 적용 규칙

루트 ENTITY는 전역 식별성을 지니며 궁극적으로 불변식을 검사할 책임이 있다.

각 루트 ENTITY는 전역 식별성을 지닌다. 경계 안의 ENTITY는 지역 식별성을 지니며, 이러한 지역 식별성은 해당 AGGREGATE 안에서만 유일하다.

AGGREGATE 의 경계 밖에서는 루트 ENTITY를 제외한, AGGREGATE 내부의 구성요소를 참조할 수 없다.

AGGREGATE 안의 객체는 다른 AGGREGATE의 루트만 참조할 수 있다. 삭제 연산은 AGGREGATE의 객체 안에 모든 요소를 한 번에 제거해야 한다.

AGGREGATE 경계 안의 어떤 객체를 변경하더라도 전체 AGGREGATE의 불변식은 모두 지켜져야 한다.

FACTORY

객체를 생성하는 책임을 맡고있는 프로그램 요소

복합한 객체나 AGGREGATE를 생성하는데 필요한 지식을 캡슐화

클라이언트의 목적과 생성된 객체의 추상적인 관점을 반영하는 인터페이스를 제공

FACTORY 설계를 위한 기본 요건

각 생성 방법은 원자적이어야 하며, 생성된 객체나 AGGREGATE의 불변식을 모두 지켜야한다.

생성된 클래스보다는 생성하고자하는 타입으로 추상화되어야 한다.

다형성을 활용하지 않는 간단한 객체까지 FACTORY를 사용하면 이해하기 어려워질 수 있다.

공개 생성자만으로 충분한 경우

클래스가 타입인 경우, 클래스가 어떤 계층구조의 일부를 구성하지 않으며, 인터페이스를 구현하는 식으로 다형적으로 사용되지 않는 경우

클라이언트가 STRATEGY를 선택하는 한 방법으로서 구현체에 관심이 있는 경우

클라이언트가 객체의 속성을 모두 이용할 수 있어, 클라이언트에게 노출된 생성자 내에서 객체 생성이 중첩되지 않는 경우

생성자가 복잡하지 않은 경우 공개 생성자가 FACTORY와 동일한 규칙을 반드시 준수해야하는 경우

인터페이스 설계시 주의사항

각 연산은 원자적이어야 한다. 생성물을 만들어내는 데 필요한 것들을 모두 한번에 FACTORY로 전달해야 한다.

FACTORY는 자신에게 전달된 인자와 결합될 것이다. 인자를 어떻게 처리하느냐에 따라 결합의 정도가 달라진다.

ENTITY FACTORY와 VALUE OBJECT FACTORY

ENTITY FACTORY는 유효한 AGGREGATE를 만들어내는 데 필요한 필수 속성만 받아들이는 경향이 있다. 불변식에서세부사항을 필요로 하지 않는다면 생성 된 후에 추가해도 된다.

ENTITY는 식별성이 필요하며, 프로그램에서 식별자를 할당하는 경우라면 FACTORY가 관리하기 적절하다. VALUE OBEJCT는 불변적이므로 생성물이 완전히 최종적인 형태로 만들어진다.

저장된 객체의 재구성

재구성된 ENTITY FACTORY는 새로운 ID를 할당하지 않는다. 이전 객체와의 연속성을 잃어버리게 된다.

객체를 재구성하는 FACTORY는 불변식 위반을 다른 방식으로 처리한다. 불일치 문제를 해결하기 위한 전략이 필요하다.

REPOSITORY

객체를 이용하기 위해서는 객체에 대한 참조가 필요하다.

객체의 참조를 얻는 방법은

객체를 생성
이미 알고있는 객체로부터 연관관계를 탐색
데이터베이스에서 질의를 통해 획득

이 중 3번의 방식은 질의 결과를 손쉽게 객체로 변환할 수 있어 도움이 되지만 남용할 경우 문제가 있다.

도메인이 아닌 기술적 메커니즘에 관해 더 생각하게 된다.
AGGREGATE나 캡슐화 같은 특징을 활용하는 것을 우회하려 하고, 데이터를 직접 획득해서 조작하게 된다.
도메인 로직이 질의와 클라이언트 코드로 들어가고, ENTITY와 VALUE OBJECT는 데이터 컨테이너로 전락한다.
도메인 계층에 대한 개발자들의 이해 수준을 낮춰 모델과 도메인 계층을 동떨어진 것으로 만든다.

REPOSITORY를 사용하면 위의 문제를 해결할 수 있다.

REPOSITORY의 이점

영속화된 객체를 획득하고 해당 객체의 생명주기를 관리하기 위한 단순한 모델을 클라이언트에게 제공한다.

영속화 기술과 다수의 데이터베이스 전략 및 다수의 데이터 소스로부터 애플리케이션과 도메인 설계를 분리해준다.

객체 접근에 관한 설계 결정을 전해준다.

테스트에서 사용할 가짜 구현을 손쉽게 대체할 수 있다.(메모리 상의 컬렉션을 이용)

REPOSITORY에 질의하기

구체적인 매개변수를 직접 입력하는 질의

가장 만들기 쉬움 특정 유형의 요약 연산을 반환한다는 개념과도 잘 맞아떨어짐

SECIFICATION(명세)에 기반을 둔 질의

클라이언트가 질의의 획득 방법에 신경쓰지 않고 원하는 바를 획득할 수 있음 사용 가능한 인프라스트럭처에 따라 적용하기 어려울 수도 있음

  • 클라이언트 코드가 REPOSITORY 구현을 무시한다 (개발자는 그렇지 않지만)

    • REPOSITORY가 의도하지 않은 방식으로 사용된다면 수행 성능이 극단에 치우칠 수 있다.

    • 상세한 구현까지는 아니더라도 캡슐화된 행위를 활용하는 것에 내포된 의미를 알아야 한다.

  • REPOSITORY 구현

    • 타입을 추상화한다.

      • 타입은 인터페이스가 될 수도 있고 구체적인 구상 클래스가 될 수도 있다.

    • 클라이언트와의 분리를 활용한다.

      • REPOSITORY의 구현을 자유롭게 변경할 수 있게 된다.

      • 영속화 전략을 자유롭게 교체할 수 있게 된다.

    • 트랜잭션 제어를 클라이언트에 둔다.

      • 트랜잭션 관리가 좀 더 단순해진다.

  • FACTORY와의 관계

    • FACTORY가 새로운 객체를 만들어 내는 데 반해 REPOSITORY는 기존 객체를 찾아낸다.

    • FACTORY는 객체를 인스턴스화하고, 클라이언트는 객체를 REPOSITOY에 추가한다. REPOSITORY는 데이터베이스 내의 객체 저장소를 캡슐화한다.

  • 관계형 데이터베이스를 위한 객체 설계

    • 관계형 데이터베이스는 비객체 구성요소이다. 그러나 데이터베이스는 다른 구성요소에 비해 객체 모델에 직접적으로 관련되어 있다. 이러한 불일치는 객체 모델에 영향을 줄 수 있다.

    • 매핑 도구가 충분히 정교하기 때문에 관계형 테이블 설계에서 도메인 모델을 반영할 필요는 없다. 하지만 MODEL-DRIVEN DESIGN에 제기된 주장들(분석 모델과 설계 모들의 분리를 피하자)을 받아들이자면

      • 어느정도 객체 모델의 풍부함을 희생해야 하고

      • 데이터베이스 설계도 변경(선태적 비정규화 같은)해야 한다.

      • 그렇지 않으면 모델과 구현 간의 밀접한 결합을 잃어버릴 수 있다.

    • 매핑은 투명해야 하고, 매핑도구에 작성된 코드를 통해 쉽게 이해할 수 있어야 한다.

      • 데이터 모델과 객체 모델이 서로 갈라지게 해서는 안된다.

        • 일부 객체 관계의 풍부함을 희생해서 관계 모델에 밀접하게 한다.

        • 정규화같은 정형화된 관계 표준을 절충해서 객체 매핑을 단순하게 한다.

      • 객체 시스템 외부의 프로세스는 이러한 객체 저장소에 접근해서는 안된다.

Last updated