programming/DDD
DDD-Light
yhsim98
2022. 10. 21. 19:12
NHN-DDD-Lite@Spring
CONTENTS
- 복잡성과 위키
- 지식 탐구
- 구현
https://www.youtube.com/watch?v=TdyOH1xZpT8
복잡성과 위키
- 기술은 항상 발전하는데 중요한게 뭘까? 왜 복잡해질까?
- 애플리케이션이 엄청 복잡하기 때문
- 도메인 자체에 대한 복잡성
- 사용하는 기술과 도구에 대한 복잡성
- 위기
- 일정 driven development ㅋㅋㅋㅋ
- 빠르고 간단하게 구축 → 오픈하면 새로운 요구사항 → 복잡성 증가 → 가파른 비용 증가, 급격한 생산성 감소 → 위기 → 차세대 개편(개편하면서도 레거시 의존) + 레거시 의존 → 빠르고 간단하게 구축
- 결국 빠르고 간단하게 맞지 않는 접근법으로 구축하니 문제이다
- 애플리케이션은 시간이 지날수록 복잡해지고 비용이 급격히 증가한다 → 위기
- DDD로 이 위기를 극복하자!!
DDD!!
- 문제가 있고 이해당사자들이 있다
- 문제를 해결하기 위해 애플리케이션을 만드는 것
- 문제와 관련된 도메인 지식들이 있고
- 이런 문제들을 DDD에서는 문제공간이라 한다
- 이런 문제 공간을 DDD에서는 해결 공간으로 만들어야 한다
- 아주 큰 도메인을 서브 도메인으로 분리한 것
- 이렇게 해결 공간을 뽑아내는 것을 DDD 전략적 패턴이라 한다
- 일반 서브 도메인
- 대부분의 도메인에서 필요한 서브 도메인
- 계정, 메일 등등
- 지원 서브 도메인
- 핵심 서브 도메인을 지원하는 서브 도메인
- 제품 조회, 배송 서비스 등등
- 핵심 서브 도메인
- 해결할 도메인 영역 중 가장 핵심이 되고 해결해야할 영역
- 결제, 쿠폰 먹이고 결제하고 기타 등등 복잡하고 어렵다
- DDD 전략 패턴은 핵심 도메인에 적용해야 한다
- 핵심 서브 도메인을 Model-Driven 하게 개발하는 방법을 DDD의 전략적 패턴이라 한다
DDD 전술적 패턴들
- 원래는 DDD 전술적 패턴 중 일부를 적용하는 것을 DDD-Lite 라 한다
- 본 세션에는 DDD 전술적 패턴 전부를 DDD-Lite라 함
지식 탐구: 위키
- 이해당사자들과 얘기하며 도메인을 발전시키고 알아가는 과정을 탐구라고 한다
Dooray! 위키 지식 탐구
- 계정 일반 도메인
- 고객 별 조직/계정 관리
- 테넌트, 조직, 회원이 존재
- 프로젝트 지원 도메인
- 프로젝트 진행 단위
- 하나의 테넌트에 복수 프로젝트가 존재
- 하나의 프로젝트에는 업무, 드라이브, 위키 등이 포함됨
- 위키 핵심 도메인
- 프로젝트 지식을 누구나 쉽게 등록/편집할 수 있는 서비스
- 위키 페이지들의 컨테이너
- 프로젝트와 1:1 관계
- 도메인 간의 관계 파악
- 도메인을 서비스별로 경계
- 엔티티 식별
- 기존 Date Driven 에서는 엔티티의 속성에 집중하게 되었다
- 하지만 DDD-lite 에서 실제 엔티티는 행위, 행동이 중요하고 속성은 그 다음이다
- 도메인의 행위가 도메인을 명확하게 표현할 수 있어야 함
- 중요한 건 행위
- 속성은 행위에 필요하면 생성
- 엔티티간 관계 마저도 행위에 필요하면 맺어주는 것
- 핵심 도메인 위키는 페이지들을 가지고 있다
- 위키의 페이지는 이력관리가 필요하다
- 엔티티를 간단하게 뽑아봤다
- 엔티티는 식별성이 있고, 생명주기가 있고, 행위가 우선한다
- 행위와 그 와 연관되는 속성이 존재한다
- 응집력이 중요
- 식별성은 존재하지 않지만 도메인의 특정 영역을 서술적으로 추상화시킨 것을 값객체라 한다
- 보통 불변으로 구현하기 때문에 부작용이 없고 값객체 자체에 행위를 추가할 수 있다
- 때문에 개념을 추상화시키고 캡슐화시키기 좋다
- 보통 수량, 돈, 주소 등을 값객체로 많이 모델링한다
- 값객체를 나타내는 냄세가 있다
- 보통 접두어가 같다, 접두어가 같으면 거의 값 객체로 표현가능
- 값객체 안에 값객체가 있어도 되고, 엔티티가 있어도 된다
- 위키 페이지에는 참조파일과 멘션이 있어야 한다
- 새로운 영역이 생겼다. 이 영역을 에그리것이라 한다
- 도메인의 불변식을 지키는 단위이자 데이터 변경의 단위이자 트랜잭션의 단위
- 분산 환경에서는 락의 단위
- 페이지는 페이지 유저와 페이지 파일과 항상 함께 다닌다
- 따라서 그룹화해서 페이지 에그리것
- 따라서 그룹화해서 페이지 에그리것
- 위의 내용을 정제한 것
- 페이지 유저는 페이지와 같이 묶이지만,
- 페이지 파일은 페이지와 별개인 유스케이스가 생겼고, PageFile도 에그리것 루트로 바뀜
- 에그리것 루트 : 에그리것 루트를 통해서면 에그리것 엔티티에 접근 가능
- 에그리것 경계를 어떻게 잡느냐가 DDD-Lite에서 가장 중요
- 에그리것에서 중요한 것이 에그리것 하나에 repository 하나여야 한다
- 페이지 유저가 cascade로 결려있고, 영속성 전이가 되서 Page를 통해서만 변경된다
- 에그리것 루트인 Page에 pageUsers에 변경이 일어나면 자동으로 영속성 전이가 일어나서 C던 U던 일어남
- 위키 페이지 내용 수정 유스케이스 발생
- 권한체크, 내용 변경 ....
- 행위가 있으면 이것을 set을 여러 번 호출하는 것이 아니라 행위로써 도메인 모델에 표현되야 한다
- 페이지 변경 내역 추가: 페이지 이력
- 두레이 스트림(알림) 발행
- 검색 변경 발행
- 본문이 변경되면 검색도 변경되야 함
- 등등 핵심 도메인으로서 여러 요구사항이 존재함
- 먼저 페이지 내용 변경 이벤트
- 생산자 - 소비자 모델
- 페이지가 변경되면 이벤트 발생시키고, 소비자가 잡아서 처리?
- 트랜잭션 미포함
- 낮은 결합도
- 페이지 Entity 외 다른 Entity에 의존하는 것들 처리
- 생산자 - 소비자 모델
- 페이지 내용 수정 흐름
- Application service는 트랜잭션과 보안 등을 관리하는 파사드 패턴
- 트랜잭션이나 보안 같은 애플리케이션 적인 관심사는 처리하되
- 절대 도메인 로직은 존재하면 안된다
- 도메인 로직을 로딩해서 위임한다
- 그래서 파사드
- 애플리케이션에 진입하는 changeContent()는 유스케이스의 표현
- 유스케이스 하나가 애플리케이션 하
- pageRepository를 통해 페이지를 조회하고, Page라는 어그리겟 루트로 매소드를 위임
- Page에서는 도메인 로직 처리하고 도메인 이벤트를 등록
- 메시지 큐?
- 물론 Page는 모르게 추상화되어 있다
- 이벤트는 EventProcessor가 받아 다시 구독자에게 바인딩
- 각자 구독하는 애플리케이션이 알아서 가져가서 처리
- 구독은 애플리케이션 서비스의 책임
- pub-sub 할때 sub는 관심사별로 최대한 분리하는 것이 좋은 모델
- 히스토리 변경, 노티 발행, 인덱스 서치 등등
DomainEvent 구현 선택
- Spring-Data
- @DomainEvents
- @AfterDomainEventPublication
- AbstractAggregateRoot
- 등등
- 트리거가 있어야 한다
- Repository#save 라는 메소드를 호출해야 이벤트가 트리거가 되는 문제
- 직접 구현
- ThreadLocal
- ApplicationEventPublisher
- AOP
코드로 한번 보자
- Data-Driven: PageCommandService
- Domain Driven
- 각 서비스 의존성
- Page Data-Driven, Domain-Model
- PageHistoryService
- 이벤트로 호출
- 트랜잭션이 commit 한 다음 호출되기 때문에 새로운 Transaction 생성
- 애플리케이션 서비스으로서 도메인 로직이 없어야 하고, 도메인 서비스에 위임하고 있다
- 도메인 서비스란?
- 무 상태의 도메인을 처리하는 서비스
- 엔티티와 에그리것과 같은 속성과 행위를 가지는 것이 아니라 행위만 가지고 있는 것을 도메인 서비스
- 속성이 없어 무상태??
- PageContentChanged라는 도메인 이벤트 그 자체
- 이벤트에 관한 속성과 어떤 이벤트인지 알려주고만 있다
- 참고로 sub 입장에서는 순서를 보장하지 않기 때문에 발생일시를 꼭 넣어줘야 멱등성 있게 처리할 수 있다
Repository와 Spring
- Repository는 데이터 모델 영역에 있어야 하고 POJO 여야 한다
- 근데 Trade-Off 생각해봐야 함
아키텍처와 모듈
헥사고날 아키텍처
- 헥사고날 아키텍처의 모든 의존성 화살표는 밖에서 안으로 모여든다
- 계층형 아키텍처의 단점은 결국 도메인이 인프라에 의존하게 되어있다
- 도메인 관심사와 기술적 관심사가 섞임
- 똑같이 의존성 방향이 밖에서 안으로 간다
- Adapter(pub-sub)을 통해 의존성 방향을 역전시켰고(DIP) 도메인 모델의 순수성을 지킴
모듈
- 패키지 구조는 이렇게 가는 것을 추천
- 계층형 아키텍처는 구시대 유물, 헥사고날 아키텍처로 가자
결론
도메인이 먼저다!!!
DDD 쓰자 DDD 앞으로는 모두 DDD 쓸거다