복사되었습니다.

자가 위임, 자가 캡슐화 - DDD에서 생성자를 정의하는 방법

Cover Image for 자가 위임, 자가 캡슐화 - DDD에서 생성자를 정의하는 방법

DDD에서는 생성자를 정의할 때 자가 위임(self-delegation)과 자가 캡슐화(self-encapsulation)를 사용할 것을 권장한다. 이 두 가지 개념을 통해 어떻게 생성자를 정의해야 하는지 알아보자.

자가 위임, 자가 캡슐화란 무엇일까?

"자가 캡슐화는 심지어 같은 클래스 내에서부터 모든 데이터로의 액세스가 접근자 메소드를 거쳐가도록 설계하는 방법이다." - Martin Fowler

자가 위임(self-delegation) 자가 캡슐화(self-encapsulation)는 비슷한 맥락에서 사용되는 용어다. 자가 위임은 이름 그대로 객체가 자기 자신에게 작업을 위임하는 것을 의미한다. 그리고 자가 캡슐화는 객체가 자신의 데이터를 직접 접근하지 않고 메서드를 통해 접근하는 것을 의미한다.

두 개념을 종합하면, 객체가 자신의 데이터를 읽거나 변경할 때 자기 자신의 메서드를 통해 작업을 위임하라는 뜻이 된다. 다시 말해서 getter와 setter 메서드를 통해 변수에 접근하라는 것이다. 변수에의 직접 접근을 경계하고 행동적 도메인 모델링을 강조하는 DDD에서 선호하는 방법이다.

DDD에서 getter와 setter를 권장한다는 말이 사실일까?

사실 무분별하게 getter와 setter를 정의하여 사용하는 것은 DDD에서 권장하는 방법은 아니다. 그런데, 이들과 관련된 자가 위임과 자가 캡슐화를 DDD에서 권장한다니, 이게 도대체 무슨 말일까? 모순이 아닌가?

Getter와 setter 사용을 지양하라는 것은 getter와 setter 모두를 public하게 노출하지 말라는 말로 해석할 수 있다. 외부에서 객체의 데이터를 직접 변경할 수 있다는 것은 해당 객체가 무기력한 도메인 모델(anemic domain model)임을 암시하기 때문이다.

따라서, 엄밀히 따지면 DDD에서 권장하는 getter와 setter의 활용은 "private setter를 활용한 생성자 정의"에 국한된다. Setter를 외부에서 접근하지 못하도록 제한하여 자기 자신만 사용할 수 있도록 숨기는 것이다.

자가 위임, 자가 캡슐화를 통한 생성자 구현 방법

from typing import Optional

class Person:
  def __init__(self, name: str, age: int) -> None:
    # self.name = name
    # self.age = age
    self._name: Optional[str] = None
    self._age: Optional[int] = None
    self._set_name(name=name)
    self._set_age(age=age)

  def _set_name(self, name: str) -> None:
    if len(name) > 20:  # guard
      raise ValueError("Name is too long.")
    self._name = name

  def _set_age(self, age: int) -> None:
    if age < 0:  # guard
      raise ValueError("Age can't be lower than 0.")
    self._age = age

위 python 코드 예제를 통해 감을 잡아보자. 생성자에서 private setter를 통해 멤버 변수에 값을 할당하고 있다. 그리고 setter의 장점을 활용하여 다양한 assertion 로직들을 정의한 것을 볼 수 있다. 코드의 특징을 요약하면 다음과 같다.

  • 외부에서 setter를 직접 호출하지 않도록 하여 값 변경 책임을 자신만 갖도록 제한하였다.
  • Assertion 코드를 setter 쪽으로 분산시켜서 생성자 코드가 간결해졌다.
  • Setter의 assertion 코드를 통해 무결성과 일관성을 유지하기 편해졌다.

결론: private setter를 사용해 생성자를 정의하자!

자가 위임과 자가 캡슐화는 DDD에서 객체의 무결성과 일관성을 유지하는 데 중요한 역할을 수행한다. 생성자를 정의할 때 이를 활용하여 데이터 접근을 제어하고, 객체의 내부 상태를 보호할 수 있다. 따라서, 생성자에서 private setter를 통해 변수에 값을 할당하는 습관을 들이자.

Comments

    More Posts

    Aggregate란 무엇인가 도대체! - DDD aggregate의 기초 쉽게 이해하기

    DDD에서는 aggregate라는 용어가 자주 등장한다. DDD의 다양한 개념들을 이해하기 위해서는 aggregate에 대한 이해가 선행되어야 하는데, 보통 DDD 자료들에서는 aggregate에 대한 설명이 중후반부에 등장한다. DDD 초보자도 쉽게 이해할 수 있도록 aggregate를 겉핥기해보자.

    Event와 command의 차이점 쉽게 이해하기 - Events vs commands in EDA

    Event Driven Architecture(EDA)를 시스템에 적용할 때는 거창한 이름 때문에 마치 모든 것을 event로 처리해야 할 것만 같다. 반은 맞고 반은 틀리다. Command라는 개념을 event와 분리하여 생각할 필요가 있다. Event와 command가 도대체 뭐가 다른지 간단히 정리해보자.

    CQRS 개념 초간단 정리 - Understanding CQRS pattern

    개발을 하다보면 CQRS라는 용어를 자주 만나게 된다. 특히 이벤트 기반 아키텍처나 대용량 트래픽 처리와 관련된 주제에서는 항상 빠지지 않고 등장하는 단골 메뉴다. 예제와 함께 CQRS 패턴의 정의, 장단점, 그리고 적용 방법 등을 최대한 간단하게 정리해보자.

    Font Size