ㄷㄷㄷ: Domain Driven Design과 적용 사례공유 / if(kakao)2022
카카오엔터테인먼트 테크 블로그 포스트
DDD란?
각각 기능적인 문제의 영역을 정의하는 도메인과 그 도메인을 사용하는 비즈니스 로직을 중심으로 설계하는 것을 DDD라고 한다.
특징
- 데이터 중심이 아닌 도메인의 모델과 로직에 집중
- 유비쿼터스 언어, 보편적 언어 사용(동일한 표현과 단어로 구성된 단일화된 언어 체계 사용. 즉, 쉽게 이야기하면 업무 용어를 통일하여 개발단 뿐만 아니라 기획, 사업단까지 단일화된 커뮤니케이션이 가능하도록 함)
- 소프트웨어 엔티티와 도메인 간 개념 일치 (분석 모델과 설계가 다다르고 이것과 코드가 다른 구조가 아닌 함께 움직이는 모델 지향)
왜 DDD인가?
- 반복적인 설계 수정과 테스트 자동화로 쌓아나가는 TDD
- 비즈니스와의 협업을 중시하면서 테스트 자동화를 가져가는 BDD
- 예시로 든 레거시 사이트에는 이미 큰 틀과 검증된 플로우가 존재. 완전히 뒤집어 엎는 것보다 필요한 기능을 구별하고 필터링하여 개선하는 점진적 향상 선택
DDD 적용에 필요했던 것들
- DDD에서 중요한 개념 3가지
- Bounded Context : 범위를 구분해놓은 하위 도메인 개념
- 각 영역을 분류하여 영역 간 의존성을 줄이기 위해 일종의 경계를 구성한다. 이는 MSA 상 각각의 서비스로 나뉜다. 데이터 조회를 위해서는 서로 API를 사용하여 통신하게 하면서 각 도메인을 철저히 분리.
- Context Map : Bounded Context 간 관계도. 전체적인 흐름 예상 가능.
- Aggregate : 데이터 변경 단위, 일종의 라이프사이클이 같은 도메인을 한 데 모은 것.
- Context Map을 기반으로 서비스를 구현 시, 해당 서비스가 갖고 있는 많은 객체들을 그대로 사용하는 것은 의미가 없다. 따라서 각 도메인 영역을 대표하는 도메인 객체 집합을 설계한 것이 Aggregate이다.
- 특징
- 데이터 변경 단위
- Aggregate에 대한 접근은 Root Entity를 통해서만 가능하다.
- 이를 통해 개별 객체 간 상호작용보다는 객체들 사이의 관계를 좀 더 넓은 시야로 바라볼 수 있다.
- 제약사항을 하나의 맥락으로 관리할 수 있고 Aggregate 간 관계를 파악함으로써 비즈니스 로직에 집중할 수 있다.
- Bounded Context : 범위를 구분해놓은 하위 도메인 개념
DDD의 대표적인 아키텍처
- Layered Architecture
- User Interface : I/O 관련 통신 변환 등을 담당하는 계층
- Application : 도메인 객체를 직접 사용하면서 어떻게 사용할지 정의하는 usecase를 구현하는 계층
- Domain : 비즈니스 룰 등의 도메인과 관련된 직접적인 기능을 포함하고 객체를 이루는 계층
- Infrastructure : Repository 나 Persistence, 메시지 전송과 같은 기술적 기능 제공 계층
- Clean Architecture
- External Interface : 데이터베이스나 웹 프론트엔드 프레임워크를 기반으로 한 UI
- Interface Adapter : 데이터베이스나 파일 시스템과 같은 외부 소스에 저장하거나 내부의 Use Case를 위해 양방향으로 데이터 변환 을 수행하는 커뮤니케이터
- Use Case : 핵심 비즈니스 로직이나 애플리케이션 로직으로 구성
- Entity : 엔티티 또는 도메인으로 구성된, 내부 유효성 검사 혹은 모든 도메인에 적용되는 일반 논리를 가진 계층
- Hexagonal Architecture
- 클린 아키텍처와 비슷한 개념을 사용하지만 port 라는 개념을 명시하고 있음. 그래서 포트와 어댑터, 포트 앤 어댑터 아키텍처라고도 한다.
- Port : 데이터를 알맞게 변환해주는 커뮤니케이터 역할
- Adapter : Port를 통해 도메인 로직에 접근
- 게임을 예시로 들어 설명하자면, 조이스틱이라는 인터페이스를 통해 받아오는 인풋과 사운드나 디스플레이로 출력되는 아웃풋이 있다. 이 때 인풋을 위한 조이스틱과 아웃풋을 위한 스피커, 디스플레이는 포트에만 알맞게 꽂으면 어느 회사 것이든 사용할 수 있다. 헥사고날 아키텍처에서도 마찬가지로, 각 포트에 맞는 어댑터에서 알맞게 구현해주면 어떤 유틸리티든 가져다 쓸 수 있다.
- 비즈니스 로직이 표현 로직이나 데이터 접근 로직에 의존하지 않는 것이 핵심이다.
Hexagonal Architecture를 선택한 이유
- Layered Architecture는 비즈니스 로직이 커지면서 애플리케이션 레이어가 오염될 가능성이 있음.
- Clean Architecture와 유사하지만 포트 앤 어댑터라는 비교적 더 명확한 아키텍처를 가짐.
실제 적용 시 고려한 점
- CRUD 중 Read 를 LoadProductPort로 따로 빼고 그 외 나머지는 SaveProductPort로 분리함. 이는 CQRS 패턴을 따른 것인데, 추후에 조회 성능 작업을 위해 아마존 SQS나 RabbitMQ 등을 사용하여 Event Driven 형식으로 바꿀 계획이었다고 함.
- DB에 저장된 데이터를 도메인에 맞게 매핑해주는 작업이 필요하므로 Mapper를 구현해야 했음. JPA를 사용했기 때문에 JpaEntity <-> DomainEntity 간 변환이 필요했음.
단점
- 아키텍처 구현에서 생성되는 생각보다 많은 코드
- 매퍼 클래스와 같이 도메인이 사용하기 위해 별도로 구현해야 하는 코드들이 추가로 필요
- 각 도메인에 대한 높은 이해도 필요
장점
- 보편적 언어 사용에 따른 빠른 커뮤니케이션
- 개발단에서 사용했던 데이터 중심의 명칭과, ui나 앱 등 기획과 사업단에서 사용하던 명칭을 통일하여 이해도를 높임
- 도메인 간 관계가 복잡한 경우 큰 틀에서 정리 가능(aggregate)
- 도메인 분리에 따른 유지보수 편의성
- 새로운 기능 및 요구 사항에 대한 유연성
- 개발자 측면에서의 장점
- aggregate 사용으로 인한 도메인 캡슐화 자동 적용
- 하위 분류 도메인에 접근하기 위해서는 루트 엔티티를 통해야만 한다.
- Loose coupling, High cohesion
- use case 나 port 등 사용
- 도메인 로직과 서비스 로직을 필요한 곳에 모아서 사용
- 도메인 로직의 분리로 비즈니스 로직에 집중
- 코드 가독성 향상
- aggregate 사용으로 인한 도메인 캡슐화 자동 적용
사이드 프로젝트 적용을 위해 DDD에 대해 알아보면서 실무에서는 어떤 방식으로 적용하는지 궁금했다. 그러던 중 레거시 프로젝트를 MSA로 전환하는 과정에서 DDD를 적용한 레퍼런스를 카카오 블로그와 컨퍼런스 영상으로 보게 되었다.
해당 내용을 통해 어떤 상황에서 어떤 이유로 DDD를 선택했는지, 또 어떻게 설계하고 적용했는지에 대한 과정을 나름 면밀히 볼 수 있었다.
막상 DDD를 적용한 설계를 해봐야겠다라고 생각했을 때 감이 잘 잡히지 않아 시작부터 어려운 지점이 있었는데 설계에 대한 궁금증도 어느정도 해소되고 개념적인 부분에서도 감이 좀 더 잡히는 것 같다.
'Conference' 카테고리의 다른 글
무엇을 테스트할 것인가? 어떻게 테스트할 것인가? (0) | 2024.07.26 |
---|