복사되었습니다.

자가 위임, 자가 캡슐화 - 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 FastAPI로 파일 업로드 및 다운로드 가능한 web server 개발하기

    FastAPI를 활용하면 파일을 업로드하거나 다운로드할 수 있는 web server를 매우 간단하게 구현할 수 있다. 예제 코드와 함께 최대한 간단하게 파일 업로드 및 다운로드 API를 구현하고 테스트하는 방법을 알아보자.

    안전하게 무한 루프 탈출하기 - Handling SIGTERM in kubernetes with python

    프로그램의 유형에 따라 명확한 종료 시점 없이 반복적인 작업을 수행해야 하는 경우가 있다. 그런데, 영원한 것은 없지 않나! 언젠가는 종료를 시켜야 한다면, 어떻게 해야 안전하게 무한 루프를 빠져나올 수 있는지 알아보자.

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

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

    Font Size