도메인 주도 설계란?

도메인 주도 설계
이민석's avatar
May 15, 2024
도메인 주도 설계란?

이 시리즈는 도메인 주도 설계(Domain Driven Design) 방식을 배우고 체득하기 위한 시리즈입니다.

본문

도메인 주도 설계의 정의, 구성요소 그리고 팁들을 간단한 예시와 함께 포함하였다.

  1. 도메인 주도 설계(Domain Driven Design)이란?

  2. 보편적인 의사소통 언어(Ubiquitous Language)란?

  3. 도메인 모델(Domain Model)이란?

  4. 레이어드 아키텍처(Layered Architecture)란?

  5. 문서화 방안

도메인 주도 설계(Domain Driven Design)이란?

도메인 주도 설계는 소프트웨어 개발 방법론 중 하나입니다.

개발자는 기술이 아닌 소프트웨어가 해결하고자 하는 도메인(문제 영역)을 깊게 이해하고 이를 바탕으로 소프트웨어를 설계하는 접근법입니다.

보편적인 의사소통 언어(Ubiquitous Language)란?

비즈니스 조직개발팀이 원활한 의사소통을 하기 위해서는 보편적인 의사소통 언어(Ubiquitous Language)가 필요합니다.

[예시] 카카오 헤어샾

카카오 헤어샾은 개발팀과 비즈니스 조직(특히 기획팀) 과의 의사소통을 통해서 엔티티(Entity)를 정의하였습니다.

예를 들어, 예약(Reservation)의 상태는 다음과 같이 정의되었습니다.

한글

상태

결제 대기

READY

결제 완료

OK

결제 후 취소

CANCELED

취소 신청

WAIT_CANCEL

시술 확정

COMPLETED

노쇼

NO_SHOW

Ubitquitous Language, 카카오 헤어샾의 DDD, 최창규 (BrunchStory)에서 발췌하여

이런 보편 언어들로 정의할 때 고려해야 할 사항은 제한 영역(Bounded Context) 범위 내에서 정의 되어야 한다는 것이다.

  • 제한 영역은 도메인을 명확하게 구분된 영역으로 나누어 각각의 영역이 독립적으로 관리될 수 있도록 하는 개념입니다.

  • 각 제한 영역은 자체적인 모델을 가지고 있어서 다른 제한 영역과 명확한 경계를 가집니다.

이를 통해 복잡한 도메인 문제를 해결하고 팀 간 의사소통을 원활하게 하며, 시스템의 유연성과 확장성을 늘릴 수 있습니다.

[예시] 쇼핑몰

쇼핑몰 사이트를 예로 들면 제품 판매 영역(Sales Context)판매 지원 영역(Support Context)으로 구분할 수 있을 것입니다.

https://cyberx.tistory.com/57

각각의 제한 영역은 모델 개발 소용돌이(Model Exploration Whirlpool) 방식을 차용하여 애자일하게 개발합니다.

  1. 시나리오 발생(Senario)

  2. 모델 정의(Model)

  3. 개발(Develop)

https://www.domainlanguage.com/ddd/whirlpool/

도메인 모델(Domain Model)이란?

도메인 모델은 도메인 주도 설계에서 핵심적인 개념입니다.
이것은 소프트웨어가 해결하고자 하는 문제 영역을 추상화하여 표현한 것입니다.
이것은 비즈니스 로직과 규칙을 포함하며, 도메인 전문가와 개발자가 공통의 이해를 바탕으로 협력할 수 있도록 도와줍니다.

https://cyberx.tistory.com/57

이를 구성하고 있는 요소들은 다음과 같습니다.

국문명

영문명

설명

엔티티

Entity

속성이 아닌 식별성을 기준으로 정의되는 도메인 객체

값 객체

Value Object

식별성이 아닌 속성을 이용해 정의되는 불변 객체

  • Entity와 Value Object를 구별하는 첫 번째 조건은 식별성

  • 모든 것에 식별성을 부여하고 Entity로 관리한다면 복잡성 증가

  • 과거 Java의 DTO(Data Transfer Object) 패턴의 Value Object와는 관계 없음

서비스

Service

동작을 가진 객체

  • 여러 Domain Object 다루는 연산 Service의 동작은 일반적으로 비상태성(Stateless)을 가짐

  • Domain Object에 해당하는 역할을 service Operation으로 만드는 경우에도 도메인 역할을 침범하여 강결합이 발생

모듈

Module

유사 작업 및 개념을 그룹화

  • 응집도가 높은 모듈을 만들면, 모듈 간의 관계가 약결합이됨

  • Java로 구현하는 경우 Package로 구성될 수 있다.

집합체

Aggregate

연관된 Entity와 Value Object의 묶음

  • 일관성(Consistency), 트랜잭션(Transaction) 그리고 분산의 단위로서 사용하여 복잡성을 관리한다.

팩토리

Factory

복잡한 Entity 생성 절차에 캡슐화 할 수 있는 개념

  • 생성하기 복잡한 집합체(Aggregate ) 내의 여러 객체를 동시에 생성

  • 생성 시 집합체(Aggregate)의 일관성 유지

저장소

Repository

도메인 계층(Domain Layer)데이터 인프라스트럭쳐 계층(Data Infrastructure)으로 분리

  • 생성된 결합체(Aggregate)에 대한 영속성(Persistency) 관리

  • CRUD 작업 시 결합체(Aggregate)의 일관성(Consistency) 유지

  • DB 및 데이터의 저장소를 조회하고 저장하는 경우 저장소(Repository)를 활용한다.

[예시] 카카오 헤어샾

카카오 헤어샾은 엔티티, 값 객체, 결합체, 서비스, 저장소, 팩토리 등을 사용하였습니다.

국문명

영문명

설명

엔티티

Entity

식별자(id)가 있는 모델

  • JPA의 @Table과 매핑하여 사용

값 객체

Value Object

식별자(id)가 없는 모델

  • 매장 부가정보, 예약 상태, 디자이너 등급과 같이 사용

서비스

Service

도메인 간의 연산을 처리하는 모델

집합체

Aggregate

생명 주기가 동일한 모델들을 모아놓은 루트 모델(Root Model)

  • 적용하지 못함

  • JPA의 LazyLoading을 사용하니 딱히 Aggregate가 필요하지 않음

    Lazy Loading이란?

    데이터를 바로 가져오지 않고 참조가 발생했을 때 로딩하는 기법이다. 이를 통해 불필요한 데이터베이스 쿼리를 방지하고 성능을 최적화할 수 있다.

팩토리

Factory

엔티티(Entity)와 집합체(Aggregate)를 생성하는 모델

  • JpaRepository 인터페이스를 상속하여 사용

  • 모델 객체를 생성할 때 Factory를 사용

저장소

Repository

레이어드 아키텍처(Layered Architecture)

도메인 모델에서 역할에 따라서 모델을 Entity, Value Object, Service등으로 분리했다.

이를 레이어 별로 분리하면 User Interface, Application, Domain, Infrastructure로 구분할 수 있습니다.

  • User Interface : 사용자의 요청을 하위 레이어로 전달

  • Application : 복잡한 비즈니스 로직을 처리하는 레이어

  • Domain : 도메인에 대한 정보, 객체의 상태, 도메인의 비즈니스 로직 제공

  • Infrastructure : 영속성을 구현하거나 외부와 통신하는 기능을 제공하는 레이어

[예시] 카카오 헤어샾

  • User Interface : Spring MVC의 @Controller

  • Application : @Service 구현

  • Domain : JPA의 @Entity와 Entity를 빌드하는 Factory 구현

  • Infrastructure : 영속성을 구현한 Dao와 외두와 통신하는 @Component

각 레이어는 하위 레이어를 의존하는 단방향 참조 관계를 가집니다.

https://brunch.co.kr/@cg4jins/7

문서화 방안

그렇다면 도메인 주도 개발에서 어떻게 문서화할지 고민해보야아 한다.

가장 일반적인 방법은 시각화된 UML 다이어그램 또는 그와 유사한 다이어그램을 활용하는 것이다. 형식이 중요한 것이 아니라 관련자가 함께 이해할 수 있는 중심 역할을 해주면 된다.

결론

실제로 인터넷에서 도메인 주도 설계에 대해서 많이 나와있는 것 같다.

나도 나만의 이유에 따라서 도메인 주도 설계를 찾게 되었고 공부했지만 뜬구름 잡는 소리처럼 들린다. 실제로 작성이 되어있는 코드를 보고 싶다는 열망이 들었고 다음 사이드 프로젝트를 도메인 주도 설계에 맞춰서 해보면 좋을 것 같다.

개발 변천사

개발을 배우고 여러 프로젝트/서비스를 만들면서 많은 문제점과 불편함을 겪었다.

그리고 자연스럽게 아래의 순서로 개발 방식이 변화하면서 1년 정도 유지되었던 것 같다.

개발을 배우고 여러 서비스를 만들면서 아래와 같은 순서로 개발 방식이 변화했던 것 같다.

  1. 모놀리식 서비스(Monlithic Service)

  2. 레이어드 아키텍처(Layered Architecture) 도입

  3. 엔티티(Entity), 값 객체(Value Object), 서비스(Service), 저장소(Repository) 도입

  4. 표준 예외(Standard Exception)와 에러 던지기(Throwing Exception) 도입

  5. 테스트 코드 도입

다양한 패턴 추가 도입

특히 Node에서 Python으로 주류 스텍이 변경되면서 데코레이터 패턴(Decorator Pattern), 비동기 패턴(Async Pattern), 다양한 프로세스 패턴(Multi Process, Child Process) 등을 경험한 것도 재밌는 경험이었다.

신기술이나 라이브러리를 도입하지 않고 코드 레벨의 해결책을 찾는 과정이 꽤 재밌었다.

마이크로서비스 패턴으로

다만 그 과정에서 구조적인 한계를 느껴서 모놀리식 패턴(Monolithic Pattern)에서 마이크로서비스 패턴(Microservices Pattern)으로 넘어가려고 하고 있다.

분산 컴퓨팅, TPC/XA(Two Phase Commit) Protocol, Saga Pattern 등을 공부하고 이를 프로젝트로 하려고 하던 중에 DDD를 찾게 되었다.

기대되는 점…

이번에 도메인 주도 설계를 공부를 하면서 설레는 점은 오랜만에 실제로 구현부를 만들면서 아래의 변화를 넣어볼 수 있을 것 같다는 점이다.

  1. 코드 | 집합체 패턴(Aggregate Pattern)팩토리 패턴(Factory Pattern) 구현

  2. 계층 | 기존의 서비스 계층(Service Layer)를 어플리케이션 계층(Application)도메인 계층(Domain Layer) 구현]

참고 자료

Share article

Unchaptered