02.DDD 설계
Last updated
Last updated
마이크로서비스 설계에서 도메인 주도 설계 활용
전략적 설계
를 이용한 마이크로서비스 식별
마이크로서비스을 어떤 기준으로 분리할 것인가?
Bounded Context, Ubiquitous Language
서비스 간은 어떻게 연계할 것인가?
Context Mapping
어떤 이벤트에 의해 마이크로서비스는 서로 반응하는가?
Domain Event
참고 도서.
전술적 설계
와 미이크로서비스 내부 설계
마이크로서비스 내부는 어떻게 설계 할 것인가?
Domain Model
참고 도서.
구축해야 하는 소프트웨어와 시스템을 위해서는 문제를 이해
Problem
: 그 조직의 비즈니스 전략과 소프트웨어를 통해서 얻고자 하는 가치
Business Domain
: 기업의 주요 활동 영역, 회사가 제공하는 서비스
Sub domain
: 비즈니스 활동의 세분화된 영역, 제공하는 서비스 단위
ex. 회원, 고객, 상품, 주문, 배송..
Problem -> Business -> Domain -> Sub Domain
시스템에서 사용하는 모든 개념들이 비즈니스 도메인을 표현해야 한다.
.
핵심(Core)
회사만의 차별성. 복잡성이 높지만 경쟁력 제공
핵심 인재 할당과 진보된 엔지니어링 기술 적용
ex) 우버의 손님 매칭 서비스, 구글의 검색 순위 알고리즘 ..
일반(Generic)
모든 회사가 같은 방식으로 수행하는 비지니스 활동
복잡하고 구현하기 어려우나 주로 오픈 소스를 사용하고, 경쟁력을 제공하지는 않음
ex) 인증, 권한 부여 ..
지원(Supporting)
회사 비지니스 지원 활동
간단한 기능으로 경쟁우위 제공하지 않음
ex) CRUD, ETL
도메인 지식(멘탈 모델)을 코드로 구현하기 위해 여러 변환 과정을 거치는 대신 그대로 코드로 표현
도메인을 코드로 설명하기 위한 단일화된 체계
기술 용어 대신 유비쿼터스 언어를 사용
유비쿼터스 언어: 동의어와 같이 모호하지 않고, 정확하고 일관성있는 언어
ex. 정책 -> 규제 규칙 / 보험계약, 사용자 -> 방문자, 비회원, 회원
특정 도메인을 개념적으로 표현한 것
효과적인 모델은 그 목적을 달성하는 데 필요한 세부사항만 포함(목적에 필요한 정보만 제공)
ex. 지하철 노선도
모델은 본질적으로 추상화의 결과. 모델로 실세계의 복잡성을 관리
도메인 모델링: 유비쿼터스 언어로 비즈니스 도메인 모델 구축
BC는 유비쿼터스 언어(모델)의 일관성이 유지되는 경계
유비쿼터스 언어를 여러 개의 작은 언어로 나눈 다음, 각 언어를 적용할 수 있는 명시적인 bounded Context에 할당
유비쿼터스 언어의 용어, 원칙, 비지니스 규칙은 해당 바운디드 컨텍스트 내에서만 일관성
BC는 컴포넌트 개발의 수명주기를 분리할 필요가 있거나 기능이 독립적으로 확장되어야 할 경우 세분화될 수 있음
각 BC의 수명 주기는 독립적
Sub Domain 과의 차이
하위 도메인은 비지니스 전략에 의해 정의되는 반면 바운디드 컨텍스트는 소프트웨어 엔지니어에 의해 설계
하위 도메인은 발견, 바운디드 컨텍스트는 설계
BC는 독립적으로 발전할 수 있지만 서로 상호작용을 해야 한다.
각 BC는 접점이 있는데 이것이 contract
BC의 연동/통합 : 각 바운디드 컨텍스트에서 작업하는 팀간의 관계를 의미
협력형 패턴
파트너십
공유 영역
공급자, 소비자 패턴
Supplier(Upstream) - Customer(Downstream)
순응주의자(Conformist) 패턴: 힘의 균형은 상류에 존재
충돌방지계층(ACL, Anti-Corruption Layer) 패턴: 하류가 이에 순응하지 않은 경우
OHS(Open Host Service) 패턴: 힘이 사용자 측에 있을 경우 제공자는 사용자를 보호하고 가능한 최고의 서비스를 제공
분리형 노선
Separated Way
커뮤니케이션의 어려움
협력과 연동보다 특정 기능을 중복으로 두는 것이 더 저렴한 경우
간단한 비지니스 로직 구현(절차 지향 스크립트), 데이터베이스 직접 접근
단순하고 이해하기 쉬운 장점
비즈니스 로직이 복잡할수록 트랜잭션 간 로직이 중복되기 쉽고, 중복 코드가 동기화되지 않으면 일 관성 없는 동작 발생
코어 하위 도메인에는 적용하지 않는 것을 권장
대안으로 Active Record, Domain Model 패턴의 등장
Anemic Domain Model(빈약한 도메인 모델)
복잡한 자료 구조를 표현
자료 구조 외에도 CRUD, ORM 연계 등 데이터 접근 로직 구현
사용자 입력의 유효성을 검사하는 CRUD 작업 같은 간단한 비즈니즈 로직
본질적으로는 DB 접근을 최적화하는 Transaction Script Pattern 유형
Entity 에 약간의 비즈니스 로직을 포함해도 되지만, 대부분의 비지니스 로직과 흐름은 응용 서비스의 행위에 의해 처리
비즈니스 로직은 단순하지만 복잡한 자료 구조인 지원 하위 도메인, 일반 하위 도메인에 적합
전술적 도메인 주도 설계(Tactical Domain-Driven Design) 패턴 - 에반스
행위(behavior) + 자료구조(data)를 통해 비지니스 로직 구현
POJO(Plain Old Java Object)로 구성
복잡한 인프라, 기술적 관심사는 피하고 비즈니스 로직으로만 구성
응용 서비스에서는 대부분 업무 흐름 제어만 하며, 주요 비지니스 로직은 도메인 모델에 위임하여 처리
도메인 모델 패턴 적용 시 도메인 모델이 점점 복잡하고 비대해짐(Big ball of mud)
도메인 주도의 Aggregate 단위로 복잡성을 구분하여 관리하는 패턴
대부분 한개의 Entity(Aggregate Root)와 여러 개의 VO로 구성
여러 개의 VO로 구성된 엔티티 예시
VO 예시
VO는 고유의 식별자를 가지지 않고, 개념적으로 완전한 하나를 표현
상태를 변경할 수 없고, 단순히 값만을 갖는 읽기 전용 불변(immutable) 객체
객체 변경 시 객체 자체를 완전히 교체
분산되기 쉬운 비즈니스 로직을 한 곳에 묶어주고 안전한 코드 작성
대부분의 경우에 적용 가능
다른 객체(엔티티, VO)의 속성을 표현하는 요소로 사용
명료성 향상, 명확한 의도 전달, 유효성 검사, 비즈니스 로직 표현, 유비쿼터스 언어를 사용한 비즈니스 도메인 개념 표현에 대한 이점
도메인의 고유 개념 표현
다른 객체와 구별할 수 있는 식별자(고유 식별자)를 갖는 객체
주문에서 배송지 정보가 변경되어도 주문번호는 변경되지 않음
자신의 생명주기를 가짐
관련 객체를 하나로 묶은 군집
데이터의 일관성을 보호하고, 데이터 변경 시 Aggregate 단위로 처리
Aggregate Root(Entity)를 통해 Aggregate 내의 다른 Entity 및 VO 접근
데이터 변경의 단위, 트랜잭션 단위가 되는 연관된 객체 묶음
설계 시 고려사항
하나의 Transaction에서는 하나의 Aggregate만 수정
Transaction 일관성과 성공 보장
하나의 일을 잘 수행할 수 있도록 작게 설계
성능 향상과 확장에 용이
한 Aggregate에서 다른 Aggregate의 참조는 식별자(id)를 통해서만 참조
하나의 Transaction 내에서 여러 Aggregate 수정 방지
하나의 Transaction에서 여러 개의 Aggregate이 갱신되어야 하는 경우, 다른 Aggregate 갱신은 비동기 통신을 활용해서 결과적 일관성을 맞춰야 함
비지니스 도메인에서 일어난 이벤트를 설명하는 메시지('과거형'
으로 명명)
Aggregate의 퍼블릭 인터페이스의 일부, Aggregate는 자신의 Domain Event를 발행
특정 엔티티/VO에 속하지 않는 도메인 로직 또는 복수의 Aggregate 관련 비지니스 로직 제공
어떤 계산이나 분석을 위해 다양한 시스템 구성요소의 호출을 조율
상태가 없는 객체(stateless object)
도메인 모델의 영속성을 처리
도메인 모델을 사용하기 위해 Repository를 통해 도메인 객체를 조회한 후 도메인 객체의 기능 실행
도메인 객체(Aggregate)에 대한 생명주기, 즉 영속성 관리(등록, 조회, 수정, 삭제 시 Aggregate의 일관성 유지)
Spring Data JPA Repository Interface
마이크로서비스 내부 구조 정의
전술적 패턴
은 비즈니스 로직을 모델링하고 구현하는 다양한 방법
시스템을 구성하기 위해서는 비즈니스 로직 외에도 여러 기능들이 필요
사용자와 상호작용(입/출력)
다양한 저장소에 상태 저장
외부 시스템과 연동
이런 필요에 이해 비즈니스 로직이 다른 구성요소에 흩어지기 쉬움
아키텍처 패턴은 코드의 구성 원칙을 도입하고 이들 사이의 명확한 경계를 제시
고전적이고, 가장 대중적인 아키텍쳐
3 계층으로 구성
1 계층: 프리젠테이션(MVC 컨트롤러에 속함)
2 계층: 비즈니스 로직(가장 중요한 계층)
3 계층: 데이터 액세스
근접 레이어에만 접근 가능하고, Top-down 순방향으로 의존
레이어드 아키텍처는 비즈니스 로직과 데이터 접근 계층 간에 의존성이 존재
비즈니스 로직 구현이 트랜잭션 스크립트, 엑티브 레코드인 경우 적합한 아키텍처
하지만, 결국 데이터 액세스 계층에 비지니스 로직이 점점 몰리게 된다
중요한 것(잘 변하지 않는 것, 비즈니스 로직)이 덜 중요한 것(가변적인 것, 기술)에 의존하여 변화에 대응할 수 없는 비유연성을 내포하는 문제가 발생
위 문제를 해결하기 위한 의존성 역전의 원칙(DIP)의 등장
비즈니스 로직을 구현하는 상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안된다.
인터페이스 활용: 비즈니스 로직은 데이터 엑세스 계층의 인터페이스를 정의
비즈니스 로직은 인터페이스에 의존하고 데이터 액세스 계층은 인터페이스를 구현
port and adapter pattern
외부 영역: 프레젠테이션, 데이터 접근
내부 영역: 응용, 비즈니스 로직
외부 영역의 어댑터가 다양하게 변경됨으로 가변성을 수용
비즈니스 로직 구현을 도메인 모델 패턴으로 한 경우 적합
내부 영역과 외부 영역을 분리하여 구성
내부 영역 구성
응용 서비스 클래스(유스케이스 흐름 처리)
POJO 중심의 도메인 모델(비즈니스 로직)
데이터 처리 I/F (Repository)
외부 영역 구성
기술 가변성을 수용한 어댑터 클래스
데이터 처리 구현
API 발행, 통신 구현
이벤트 전송 및 리스너
Command Query Responsibility Segregation
Command Model: 비즈니스 로직 구현, 강력한 일관성
Query Model: 읽기 모델(인메모리 캐시, 일반 파일, materialized view, 읽기 전용)
모델별 저장소 동기화 필요: 동기(동시 쓰기)/비동기식(MessageQueue)
확장 가능, 읽기 성능 향상, 다양한 저장소 활용 가능한 장점
이벤트를 생산하는 모듈과 이벤트에 대응하는 모듈을 분리하고 상호 독립적으로 동작하여 병렬 처리를 촉진
발신자와 수신자를 장소와 시간에서 쉽게 분리 가능
장점
느슨한 결합으로 확장성, 수정 가능성, 내결함성에 많은 이점을 제공
단점
부주의하게 적용 시 모노리스를 분산된 커다란 진흙 덩어리로 만들 수 있음
로컬 복잡성: 개별 마이크로서비스의 복잡성
글로벌 복잡성: 전체 시스템의 복잡성, 서비스 간의 상호작용과 의존성
고려해야 할 장애 상황
네트워크 장애, 서버 장애, 이벤트 순서 꼬임, 이벤트 중복 등
데이터 소실 처리
큐에 전달 안됨, 전달되어도 큐가 다운됨 -> 이벤트 저장소 활용
메시지를 꺼내 처리 전에 장애 발생 -> 클라이언트 확인 응답 모드 활용
데이터 에러로 인해 메시지 저장 실패 -> ACID 트랜잭션 적용
비동기 관련 문제
데이터 처리는 정상이지만 이벤트가 전달되지 않았을 경우 일관성을 맞추기 위해 적용할 수 있는 방법들
데이터 처리와 이벤트 발행을 하나의 트랜잭션으로
Outbox Pattern 적용
서비스가 외부 시스템이나 마이크로서비스와 통신할 때 직접 메시지를 보내는 대신 Outbox라는 데이터베이스 테이블에 이벤트나 메시지를 저장하고, 별도의 프로세스가 이 Outbox 테이블을 폴링하여 저장된 메시지를 읽고 외부 시스템으로 전송하는 방식
아웃박스라는 저장소에 도메인 이벤트를 저장
메시지 릴레이가 아웃박스에 있는 이벤트를 발행
Saga Pattern 적용
마이크로서비스들끼리 이벤트를 주고 받아 특정 마이크로서비스에서의 작업이 실패하면 이전까지의 작업이 완료된 마이크서비스들에게 보상(complemetary) 이벤트를 소싱함으로써 분산 환경에서 원자성(atomicity)을 보장하는 패턴
여러 트랜잭션에 걸쳐 있는 비즈니스 프로세스 처리 문제 해결
분산 트랜잭션의 일관성 보장: 보상 트랜잭션