DDD 세레나데 3주차 강의 정리

DDD 세레나데 3주차

2주차 복습

  • 유비쿼터스 언어
    • 유비쿼터스 언어는 회의록, 회의, 코드 등에서 나타난다.
    • 유비쿼터스 언어는 Bounded Context에서만 존재 해야 한다.
    • 코드레벨에서는 유비쿼터스 언어가 검증이 되어야 한다.
    • 검증이 되지 않으면 실패할 가능성이 크다.
  • 용어사전
    • 도메인 주도 설계가 성공하기 위해선 용어 사전을 개발자만 참여하는것이 아닌 프로젝트에 참여하는 모두가 관리 해야 한다.
    • 프로젝트가 커질 시 컨텍스트 별로 용어 사전을 정리 해야 한다. (동일한 용어가 다른 의미를 가질 수 있다.)
  • 모델링
    • 모델링은 소리 내어 읽었을때 어색하지 않아야 한다.
  • Bounded Context
    • BC는 서로 다른 관점을 찾는 것이다.
    • 우발적인 중복은 충분한 고민을 해봐야 한다.
    • 하나의 BC는 하나의 팀에서만 관리하는것이 베스트이다.
  • OOP vs DDD
    • oop 에서의 상속으로 풀수 있는 문제 라고 하더라도 ddd 에선 context 간 분리가 더 중요하다.
      그로 인해 context 내부에 중복이 발생 할 수도 있다.
  • 이벤트 스토밍
    • 단순한 조회 같은 행위는 이벤트가 아닐 수도 있다.
    • 조회를 하여 조회 카운트가 상승했다 와 같은 행위가 이벤트이다.
    • 개발자들은 이벤트 스토밍 도중 기획자나 도메인 전문가 들이 설계를 어렵게 하는 부분에 대해 문제를 제기 할 줄 알아야 한다.
  • Aggregate
    • 독립된 라이프 사이클을 가지는 무언가

공통된 단어가 나오면 반드시 context를 나눠야 한다. (최소 context 수) 최대 context 개수는 는 aggregate 개수

도메인 주도 설계는 설게 후 구축이 아닌 설계와 구축이 병렬적으로 진행 되어야 한다.

전술적 설계 - ENTITY 와 VALUE OBJECT

  • Entity는 지속적으로 상태를 관찰해야할 필요가 있을때 만든다.
  • 내부적인 상태가 변하더라도 동일한 객체라고 인식을 해야 할 때 식별자를 만들고 Entity로 만든다.
  • 도메인 모델에 setter 가 있으면 해당 도메인 모델은 완전한 상태가 아니게 된다.
    • 버릇처럼 쓰는 setter 는 남발하면 안된다.
  • 모든 객체는 불변 객체가 가장 좋다.
    • 새로운 타입의 객체를 만들어서 유효성 검사 로직을 옮긴다.
    • 객체 끼리의 책임을 나누는 방법.
    • 분리 된 객체는 만들어지거나 실패하거나 원자성을 보장한다.
    • 값 객체 (value object- 불변 객체)는 동일성과 동등성을 보장해야 한다.
      • 가변 객체는 값이 바뀜에 따라 의미가 달라 질 수 있다.
      • 불변 객체는 값이 바뀜에 따라 새로운 불변 객체를 만들어 내야 한다.
      • 불변 객체는 계속 생성이 되면 메모리 부하가 일어나지 않나 ?
        • -> 컴퓨팅 파워와 GC를 믿어야 한다.
    • 불변 객체
      • 포함 되고 있는 모든 값들을 final 로 만든다.
      • 1 + 1 = 2 가 아닌 new int(2)
      • 리스트 같은 멤버 변수는 final을 사용해도 값이 바뀔수 있어서 의식적인 방어적 복사가 필요하다.

AGGREGATE

  • 엔티티와 ValueObject (관련 객체)가 모여있는 군집.
  • 반장이라는 개념이 있다 (루트 엔티티)
  • Bounded Context > Context > AGGREATE
  • 동일한라이프 사이클을 가진것을 하나의 AGGREGATE로 묶는다.
    • ex) 자동차 인스턴스가 사라지면 내부에 속한 핸들 및 바퀴와 같은 인스턴스도 같이 사라져야 한다.
  • 하나의 Aggregate에 속하면 다른 Aggregate에는 속하지 못한다.
  • 정리 하면 많은 엔티티들을 동일한 라이프 사이클로 묶어둔 군집
  • Aggregate Root
    • 외부에선 해당 aggregate와 대화 하기 위해선 Root에게 요청을 해야 한다.
    • Aggregate Root 도 하나의 엔티티 이기 때문에 내부에 상태를 가지고 있다.
    • 서로 다른 Aggregate와 대화 하기 위해선 반드시 Aggregate Root를 거쳐야 한다.
    • 내부에 어떤 상태를 가지고 있는지 외부에서는 알지 못한다 (캡슐화)
  • 두개 이상의 엔티티가 하나의 Aggretate에 있으면 어떤걸 Root로 할까 ?
    • Aggregate Root 가 될 수 있는 기준은 Global 식별자(외부에서 참조 하고 있는 식별자) 를 가지고 있는것. 따라서 Order가 Root
    • 로컬 식별자 를 가지고 있으면 루트가 될 수 없다.
  • 정리 하면 글로벌 식별자를 가지고 있어야 루트 에그리게잇이 될 수 있다.
  • Aggregate 참조
    • 직접 참조를 허용하면 편리함을 오용한다.
    • ID를 이용한 간접 참조를 권장한다.
      • 복잡도를 낮출 수 있다.
    • 같은 Aggregate 에선 직접 참조 해야 한다.

Repository

  • Repository 는 구현을 위한 도메인 모델.
  • Aggregate 단위로 도메인 객체를 저장하고 조회하는 기능을 정의한다.
  • 리포지토리는 Aggregate(Root)단위로 존재하며 테이블 단위로 존재하는 것이 아니다.
    • 리포지토리는 Aggregate을 위한 컬렉션으로 생각하면 된다.

Service

  • 어플리케이션 서비스와 도메인 서비스는 다르다.
  • 여러 도메인이 가진 로직들을 하나의 서비스에서 처리 하기 위한 레이어.
  • 도메인 서비스라는 것은 엔티티, vo, repository를 만든 상태에서 정책 또는 로직을 특정 애그리게잇의 행위로 지정하기 어려운것들.
  • 객체 지향이 아닌 절차 지향적인 로직들을 도메인 서비스로 분리해서 특별하게 관리 할 수 있다.
  • 도메인 서비스와 어플리케이션 서비스는 상태값을 가지고 있지 않다는것에선 유사하지만 서로 다루는 서비스 영역이 다르다.

Factory

  • 연관된 Aggregate에서 생성 해보자.
    • ex) 좋은 모델링 - LadderGame 이 종료되야 GameResult 생성
      • 사다리게임이 끝나야 게임 결과를 생성한다 라는것은 게임 결과는 게임을 통해서 알수 있다는 비즈니스 로직을 한눈에 알수 있는것이다.