복사되었습니다.

자가 위임, 자가 캡슐화 - 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

    Python에서 decimal의 precision 문제와 수의 표현 범위

    Python의 기본 자료형인 float은 정밀한 수를 담거나 연산할 때 한계가 있다. 좀 더 정밀한 수를 다루기 위해서 decimal이라는 자료형을 사용하는데, 여전히 일부 연산에서는 precision 관련 오류가 발생한다. 어떤 문제가 있는지 살펴보자.

    Validation 코드는 어디에 작성해야 할까? - The 3 types of validation logics

    개발자들은 다양한 validation 코드들을 작성하는데 많은 시간을 소비한다. 이곳저곳에 덕지덕지 붙어있는 validation 코드들을 바라보면, 과연 이 코드들이 여기에 있어도 되는 것인지 의문이 생긴다. 다양한 종류의 validation 코드들을 어디에 작성해야 하는지 정리해보자.

    Python으로 kubernetes 환경에 app 배포하기 - Kubernetes deployment with python

    Kubectl 명령어를 통해 kubernetes 환경에 다양한 구성요소들을 배포할 수 있지만, python으로 템플릿 코드를 짜두면 개발자들도 편리하게 배포를 자동화할 수 있다. Jinja2와 kubernetes 패키지를 통해 사용자 요청에 따라 kubernetes 환경에 pod들을 띄우는 기능을 만들어보자.

    Font Size