Semina

[우아콘2021] 도메인 원정대

Jordy-torvalds 2022. 3. 24. 01:22
반응형

[우아콘2021] 도메인 원정대

여는 글

우아콘2021에서 박재성님이 발표하신 도메인 원정대를 정독해 보았다. 이전에는 다소 모호하고 명확히 이해하지 못했던 도메인 주도 설계와 관련된 주요 개념들에 대해 제대로 이해하게 되는 계기가 된 것 같다. 전체적으로 주요 강연 내용을 담되, 강연자이신 박재성님께 질문 드린 내용과 개인적으로 관련해서 공부하며 알게된 사실을 담아보았다. 

이 글의 출처인 도메인 원정대 영상

무엇이 문제인가?

물류 센터 관리자는 재고가 없을 때 
품목을 주문할 수 있도록 재고 보고서를 인쇄할 수 있어야 한다.

위 글을 보면 단번에 재고 보고서 인쇄 기능을 구현하기 위해 poi 라이브러리를 공부하려 할지도 모르겠다.

하지만, 위 문제는 재고가 없을 때 자동으로 주문이 되도록 하는 것이 옳은 문제 해결 법일지 모른다. 재고가 없는 상황을 해결하는 것이 핵심이기 때문이다.

프로그래머는 프로그램을 개발하는 사람을 넘어 문제를 해결할 수 있는 사람이어야 한다.

도메인이란?

도메인은 소프트웨어로 해결하고자 하는 문제 영역(Problem space) 이다.

도메인은 소프트웨어를 사용하는 사용자의 활동이나 관심사와 관련되어 있다.

소프트웨어 산업은 다른 산업 내에서 발생하는 다양한 비즈니스 문제를 해결한다.

소프트웨어는 사람의 욕망과 욕구를 해결하려고 만든 창조물 입니다.
사람들의 욕망과 욕구가 개발자에게 전달됐을 때 우리는 그것을 도메인이라고 부릅니다.
- 조영호 -

도메인 모델이란?

모델이란?

모델은 목적을 위해 현실 세계에 존재하는 것을 가공하고 편집하여 우리에게 정보를 제공한다.

특정 다이어그램이 아니라 다이어그램으로 전달하려는 아이디어이자 목적가진 의사소통 수단이다.

이 의사소통 수단은 회의, 기획, 디자인, 개발에 사용되어야 한다.

모델을 통해 구성원들이 일관된 생각을 갖게 된다!

도메인 모델을 사용하면 이해관계자가 동일하게 도메인을 이해하고 생각할 수 있다!

도메인에 대한 생각은 사람마다 다를 수 있어 이걸 일관되게 유지하는 것이 필요하다.

예를 들어, 강의라는 도메인은 수강생에게는 교육자료이지만 매출 관리자에게는 상품에 일종이다. 그래서 관점에 따라 하나의 단어가 여러 방법으로 해석될 수 있다.

 

이벤트 스토밍

복잡한 비즈니스 도메인을 빠르게 탐색하고 학습할 수 있는 워크숍

도메인 전문가와 개발자를 학습과정에 참여시키기 위한 빠른 설계

코드를 없애고 모든 사람을 동일한 수준으로 만드는 시각적 접근 방법

이벤트 스토밍과 관련해서 박재성님이 발표하신 영상도 있으니 아래 영상을 보자!

그렇게 배운 내용을 기반으로 Miro란 사이트에서 직접 이벤트 스토밍을 해보자! 소규모 프로젝트에서도 충분히 할 있다.

 

The Visual Collaboration Platform for Every Team | Miro

Scalable, secure, cross-device and enterprise-ready team collaboration whiteboard for distributed teams. Join 30M+ users from around the world.

miro.com

 

바운디드 컨텍스트

해결 영역(Solution Space)이라고도 할 수 있다.

관심사를 분리하고 격리하여 문제 해결에 집중할 범위를 정한다.

같은 피자지만, 해결 영역에 따라 달라지게 된다.

같은 피자라도 상황에 따라 관심사가 달라질 수 있다. 음식일 때는 이름과 가격, 도우, 토핑 등에 관심을 갖지만, 음식물 쓰레기일 때는 무게, 음식물 쓰레기 여부가 중요하다.

 

애그리거트

시스템이 기대하는 책임을 수행하며 일관성을 유지하는 단위

일관성은 항상 참이어야 하는 속성을 유지함으로써 달성된다.

명령을 수행하기 위해 함께 조회하고 업데이트해야 하는 최소 단위

비즈니스 규칙이란 단어로 대체 가능

애그리거트에 속한 엔티티들은 동일한 생애주기를 가짐

엔티티란?
고유한 식별자를 가지는 객체.
명사로 독립체란 뜻을 가진다.

애그리거트 루트란?

애그리거트 내에서 대표적인 엔티티. 버전을 통해 비관적 잠금이나 낙관적 잠금을 사용할 수 있다.

 

잠금

비관적 잠금

한 번에 한 명의 사용자만 처리할 수 잇또록 데이터베이스의 레코드를 독점한다.

성능이 저하되고 교착 상태가 발생할 수 있다.

 

낙관적 잠금

애그리거트에서 무엇이든 변경하면 버전 증가가 발생해야 한다.

OPTIMISTIC_FORCE_INCREMENT를 사용하거나 버전을 수동으로 증가시킨다.

 

애그리거트 시나리오

하나의 애그리거트에 속한 강의와 수강생이 있다고 해보자. 위 사진 처럼 수강 신청, 강의 정보 수정, 수강생 정보 수정이 거의 동시에 발생할 경우 낙관적 락을 사용하는 강의는 변경에 있어 잠기게 되고 결과적으로 일부 요청이 이로 인해 실패하게된다. 버전을 변경할 수 있는 것은 한 번에 하나의 트랜잭션만 가능하기 때문이다.

위와 같은 동시성, 성능 문제를 어떻게 하면 해결할 수 있을까?

동시성, 성능 문제의 해결을 위해서는 우선 도메인의 특성을 이해하는게 중요하다.

위 사진과 같은 도메인 지식과 개발자가 가진 고민을 미루어 볼 때 아래와 같은 구조로 변경된다.

위와 같이 애그리거트를 나누게 될 경우 강의와 수강생 간에는 변경으로 인한 영향이 전파되지 않으며 독립적으로 작업을 할 수 있다. 다시 말해 수강생 정보가 바뀐다고 강의 어그리거트가 잠기지 않게 되고, 강의 어그리거트가 변경된다고 수강생이 잠기지 않는다.

참고로, 강의 엔티티의 버전은 강의 어그리거트에 속한 엔티티와 VO에 변경이 발생할 때 증가하게 된다. 강의 정보 수정과 강의 신청은 여전히 낙관적인 락으로 인해 변경에 있어서는 동시에 이뤄지지 못하게 된다. 하지만 강의의 오버 부킹을 막아야 한다는 요구사항이 있어서 필요한 락이라고 볼 수 있다.

강의 수강생은 VO로 불변인 객체인 것을 알 수 있는데, 이를 JPA로 구현하려면 @ElementCollection을 써야한다. 이 애너테이션이 적용된 객체는 불변이여서 일부 엘리먼트만 변경이 되어도 그 변경의 여파가 크다. 좀더 세부적으로 말하자면 10명의 강의 수강생이 있다고 했을 때 이 중 하나만 삭제된어도 모든 연관된 강의 수강생 정보가 삭제되었다가 나머지 9명의 강의 수강생 정보가 다시 삽입이 되게 된다. 그래서 도메인의 특성상 변경이 잦고 이것이 성능 이슈를 불러 올 경우, Entity로 바꿔서 @OneToMany 와 같은 관계를 맺어주되 불변식을 유지하기 위해 불변이란 특성은 유지 하도록 하는게 좋다.

강의 수강 신청을 받고 수강생에 대한 생성도 필요한데, 이는 선택지가 두 가지 이다. 이전 처럼 동기로 생성을 할 경우 성능 상에 아쉬운 점이 있을 수 있는데 이를 배치나 이벤트 방식으로 처리할 경우 수강을 받는 시점과 다른 시점에 생성하는 거도 가능하다.

하나였던 강의와 수강생을 나누었을 때와 나누지 않았을 때 어떤 트레이드 오프가 있을까?

애그리거트 크기에 따른 트레이드 오프

위 사진과 같이 애그리거트의 크기의 크고 작음에 따라 얻는 것과 잃는 것이 명확하다. 그래서 구현되는 도메인의 특성과 요구사항에 따라 적절히 조정하는 것이 필요하다.

반응형