ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2부. 소프트웨어에서 표현되는 모델 : 엔티티, 값 객체 (Entity, Value Object)
    Domain Driven Design 2021. 3. 16. 15:09

    [Domain Driven Design] - 2부. 소프트웨어에서 표현되는 모델 : 연관 관계(association)

     

    2부 모델 주도 설계의 기본 요소 - 표현 모델 (연관관계)

    모델과 구현은 상세한 수준에서 연결돼야 한다. 객체 간의 연관관계를 이해하고 묘사하는 것이 간단할 수 있지만 실제 구현하기에는 어려운 문제일 수 있다. 상세한 구현 결정은 Model-Driven-Design

    sungman.tistory.com

     

    이전 글에서 모델 주도 설계가 실제 구현으로 연결 짓는 것이 어려운 일임을 말하고, 이를 쉽게 하기 위해 객체 간의 연관관계에 대해 설명하였다.

     

     

    이어서 모델을 표현하는 패턴에 대해 알아보도록 하자

    우선, 이번 글에서는 엔티티(Entity)와 Value Object(vo, 개인적으로 직역한 '값 객체' 표현이 어색하다)에 대해 살펴보도록 한다.

     

     

    엔티티 Entity (참조 객체)

    엔티티는 본질적으로 연속성과 식별성이 이어지느냐를 기준으로 정의된다.

     

    엔티티의 특징을 살펴보자

    • 자신의 생명주기 동안 형태와 내용이 급격하게 바뀔 수 있지만 연속성을 유지해야 한다.
    • 엔티티를 추적하려면 엔티티에 식별성이 정의되어 있어야 한다.
    • 엔티티의 클래스 정의와 책임, 속성, 연관관계는 엔티티에 포함된 특정 속성보다는 엔티티의 정체성에 초점을 맞춰야 한다.

     

    친구의 은행 계좌로 이체를 했는데, 동명이인의 타인에게 돈이 이체된다고 상상해본다면 쉽다.

    친구의 계좌로 이체할 때 친구의 이름, 나이, 거주 중인 주소 등이 필요하거나 중요한가? 당연히 친구의 계좌를 식별할 수 있는 계좌번호가 중요하다. 나이는 시간이 지나면 바뀌고, 주소 또한 이사가면 바뀔 것이다. 이러한 속성들이 일치하지 않는 것은 중요하지 않다.

     

    객체 모델링을 할 때 객체의 속성에 집중하곤 한다. 엔티티의 근본적인 개념은 객체의 생명주기 내내 이어지는 추상적인 연속성이고, 이는 여러 형태를 거쳐 전달된다.

     

    그리고 식별성으로 객체를 구분하는 엔티티 패턴을 사용한다면 아래의 사항들을 지킬 수 있도록 하자

    • 클래스 정의를 단순하게 하고 생명주기의 연속성과 식별성에 집중하라
    • 객체의 형태나 이력에 관계없이 각 객체를 구별하는 수단을 정의하라
    • 객체의 속성으로 객체의 일치 여부를 판단하는 요구사항에 주의하라
    • 각 객체에 대해 유일한 결과를 반환하는 연산을 정의하라
    • 식별 수단은 외부에서 가져오거나, 자체적으로 만든 임의의 식별자일 수 있지만, 모델에서 식별성을 구분하는 방법과 일치해야 한다.
    • 모델은 동일하다는 것이 무슨 의미인지 정의해야 한다.

     

    어디에서 어떻게 사용되는지에 따라 식별성이 필요할 수도, 없을 수도 있다. 경기장 좌석으로 예를 들어보자

     

    경기장의 좌석을 예약하는 애플리케이션이 있다. 경기장 좌석은 엔티티인가?

     

    좌석이 지정석이라면 각 입장권에는 좌석번호가 적혀 있을 것이다. 그렇다면 좌석은 엔티티이다. 좌석의 가격, 위치 등의 속성이 있겠지만 좌석을 식별하는데 좌석번호만이 사용될 것이다.

     

    반대로, 입장권을 가진 사람이 빈 좌석에 선착순으로 아무데나 앉을 수 있는 일반석이라면 어떨까? 이 때는 좌석을 구분할 필요가 없을 것이다. 아마 전체 좌석의 개수만이 중요한 요소일 것이다. 좌석에 좌석번호가 여전히 남아있다 해도 애플리케이션에서 좌석번호를 관리할 필요가 있을까? 일반석에는 좌석번호에 대한 제약조건이 없으니 특정 좌석과 입장권의 관계를 만드는데 오류를 만들 뿐이다.

    이러한 경우에는 좌석은 엔티티가 아니고 식별자도 필요 없다. 

     


    값 객체 Value Object

    시스템에서 모든 객체들이 엔티티로 존재하는 것은 아니다. 식별성과 연속성을 가질 필요 없이 도메인의 서술적인 측면을 나타내는 객체도 있다.

     

    Value Object는 모델의 어떤 속성에 대해 표현하기 위한 목적으로 사용하는 패턴이다.

     

    Value Object의 특징은 다음과 같다.

    • 해당 Value Object가 전달하려는 속성의 의미를 표현하고 관련 기능을 갖는다.
    • 불변적(immutable)이다.
    • 다른 여러 객체를 조립한 것일 수 있다.
    • 엔티티를 참조할 수도 있고, 엔티티의 속성으로 사용될 수도 있다.
    • 여러 객체 간 오가는 메시지의 매개변수로 전달되기도 한다.
    • 식별성과 연속성을 갖지 않는다.
      때문에 엔티티와는 다르게 필요한 설계상의 복잡성을 피할 수 있다.
    • Value Object를 구성하는 속성은 개념적 완전성(conceptual whole)을 형성해야 한다.

     

    구성하는 속성이 개념적 완전성을 형성해야 한다는 의미에 대해 예를 들어보자

     

    고객이라는 Value Object 객체가 있을 때 우편번호, 도, 시군구, 읍면동 같은 속성은 고객 객체에서 별개 속성이 아니다. 때문에 하나의 완전한 주소라는 클래스로 구성함으로써 고객 객체를 더 단순화하며 응집도 높은 Value Object를 설계할 수 있다.

     

    Value Object는 참조한 Entity의 정보를 제공할 수 있고, 개념적으로 완전해야 한다.

     

    Value Object의 설계

    Value Object는 식별성 없이 오직 속성에 집중하므로, 어떤 인스턴스를 사용하든 그것은 중요하지 않다.

    이렇게 제약조건이 줄어들면 설계를 단순화하거나 성능의 최적화를 이끌 수 있다. 하지만 이를 위해 복사, 공유, 불변성에 대한 의사결정이 필요하다.

     

    다시 위의 고객 객체를 통해 예를 들어보자

     

    두 고객 객체의 이름이 같다면, 이름 자체에는 식별성, 연속성이 필요없이 철자(속성)만이 중요하기 때문에 이름 속성에 대한 객체는 서로 바꿔도 상관 없을 것이다. 이 때 이름에 대해 두 객체 간 복사 가능하다.

     

    그렇다면 두 고객 객체의 이름이 다른 인스턴스를 가질 필요가 없을 수도 있다. 그러면 두 객체는 이름을 공유할 수 있다. 하지만, 만약 한 고객 객체가 개명해서 이름을 변경한다면 같은 이름 인스턴스를 공유하는 다른 객체에도 변경이 발생할 것이다. 때문에 이러한 예상치 못한 변경을 방지하며 안전하게 객체를 공유하기 위해선 공유되는 객체가 불변적(immutable)해야 한다.

     

    공유가 유용한 Value Object 케이스

    • 공간을 절약하거나 데이터베이스 내의 객체 수를 줄이는 것이 중요한 경우
    • 통신 부하가 낮은 경우(ex. 중앙집중형 서버)
    • 공유 객체의 불변성이 엄격하게 지켜지는 경우 

     

    다른 예를 들어, 주택 설계 소프트웨어를 개발한다고 생각해보자

    30층 높이의 10호까지 가지는 아파트에 한 세대 당 콘센트가 10개씩 보유하고 있다고 가정한다. 그리고 각 콘센트가 갖는 속성들이 같아(ex. 220V) 상호 교환이 가능하다고 가정한다.

     

    30층 * 10호 * 10개 콘센트 = 총 3,000개의 콘센트를 하나의 인스턴스를 생성하여 공유하여 객체의 수를 줄여 성능을 최적화할 수 있다. 대형 시스템일수록 큰 효과를 발휘할 것이다.

     

    그러나, 아주 특별하게도 성능적으로 크리티컬한 문제로 Value Object의 변경을 허용하는 경우가 아래처럼 존재한다.

    (정말 특별하고 예외적인 경우에 대해 말한 것이므로 성능에 큰 문제를 주는 경우가 아니라면 Value Object는 불변적으로 설계하며, 변경이 가능하다면 공유해서는 안된다.)

    • Value가 자주 변경되는 경우
    • 객체 생성이나 삭제에 비용이 큰 경우
    • 교체로 인해(변경이 아닌) 클러스터링이 제한되는 경우
    • Value를 공유할 일이 그리 많지 않거나 클러스터링을 향상시키기 위해서나 다른 기술적인 이유로 공유가 보류된 경우

     

    위의 예 중 클러스터링 관련하여 이해가 가지 않으니 어떤 클러스터링을 말하고 있는지 예를 들어보자

     

    하위 수준에 위치한 데이터베이스는 디스크 상의 물리적인 위치에 데이터를 놓고 물리적인 부분을 옮기고, 데이터를 읽어들이는데 시간을 소요한다. 잘 만들어진 데이터베이스는 물리적 주소를 클러스터링하여 관련 데이터를 한 번의 연산으로 빠르게 읽어올 수 있을 것이다.

     

    한 객체가 다른 여러 객체에서 참조되고 있다면 그러한 객체 중 일부는 멀리 위치하고 있을 수 있고, 이를 읽어오기 위해서 추가적인 연산이 필요할 것이다.  때문에 동일한 인스턴스의 참조를 공유하는 것이 아닌 사본을 만들어 사용하는 방식을 사용하는 경우가 있다. 그리고 분산 시스템에서 다른 서버에 위치한 Value Object의 참조를 갖고 있을 경우 메시지에 대한 응답이 느려질 수 있다. 이 때 객체의 사본을 다른 서버로 전달하는 식으로 사용한다.

     

    Value Object의 연관관계 설계

    마지막으로 Value Object의 연관관계에 대해 간단한 제약조건에 대해 알아본다.

     

    Value Object 간의 연관관계에서는 양방향 관계를 가져서는 안된다. 두 Value Object가 서로를 가리키는 것은 그저 식별성 없는 어떤 객체가 자신을 가리키는데, 이 객체와 내용이 같은 어떤 객체를 해당 객체에서 역으로 가르키는 것으로 아무 의미 없는 관계인 것이다.

     

    때문에 Value Object 간 양방향 연관관계는 완전히 제거하도록 노력해야 한다.

     

     

     

     

    다음 글 : [Domain Driven Design] - 2부. 소프트웨어에서 표현되는 모델 : 서비스(Service)

     

    2부 모델 주도 설계의 기본 요소 - 표현 모델 (Service)

    2021.03.16 - [Domain Driven Design] - 2부 모델 주도 설계의 기본 요소 - 표현 모델 (Entity, Value Object) 2부 모델 주도 설계의 기본 요소 - 표현 모델 (Entity, Value Object) 2021.03.15 - [Domain Driven..

    sungman.tistory.com

     

    댓글

Designed by Tistory.