티스토리 뷰
개요
# 참고
IMPLEMENTING DOMAIN DRIVEN DESIGN (도메인 주도 설계 구현) - 반 버논 지음
# 개요
DDD에 대한 기술서적을 읽고 DDD가 무엇인지 이해하고 어떻게 코드에 적용시킬 수 있는지 고민해 보려고 한다.
# 13장의 로드맵
- 분산 컴퓨팅 환경에서 시스템을 성공적으로 통합하는 방버ㅓㅂ
- 레스트풀 리소스를 사용한 통합 방식
- 메시징을 사용해 통합하는 방법
- 여러 바운디드 컨텍스트에 걸쳐서 정보를 복제하려고 할 때 겪을 수 있는 어려움
- 설계 접근법의 성숙도를 높이는 법
13장. 바운디드 컨텍스트의 통합
중요한 프로젝트라면 언제나 다수의 바운디드 컨텍스트가 있으며, 그 바운디드 컨텍스트 중 둘 이상은 반드시 통합해야 한다. 컨텍스트 맵을 사용해 바운디드 컨텍스트 사이에 존재하는 일반적인 관계를 논의했고, 그 관계를 DDD의 원리에 따라 관리하는 몇 가지 방법들을 살펴봤다.
컨텍스트 맵에는 두 가지 주요 형태가 있다. 그 형태 중 하나는 모든 둘 이상의 바운디드 컨텍스트 사이에 존재하는 관계의 종류를 표현하기 위해 사용하는 간단한 그림이다. 두번째 형태는 이런 과계를 실제로 구현하는 코드이다. 이번 장에서는 다룰 내용은 두번째 형태를 다룰 예정이다.
13-1 통합의 기본
두 바운디드 컨텍스트를 통합해야 할 때, 코드로 이를 수행하는 상당히 단순한 몇가지 방법이 있다.
# API
이 단순한 방법중 하나로, 하나의 바운디드 컨텍슽트가 애플리케이션 프로그램이 인터페이스(API)를 사용하는 방법이 있다. 이 API는 SOAP를 사용하거나 단순히 HTTP를 통해 XML 요청을 보내고 응답을 받도록 할 수도 있다. 사실 원격으로 접근이 가능한 API를 만드는 데는 몇가지 방법이 더 있다. 이는 통합의 가장 인기 있는 방법 중 하나이며 프로시저 호출 스타일을 지원하기 때문에 프로시저나 메소드를 호출하는데 익숙한 프로그래머들이 이해하기 쉽다.
# 메시징 메커니즘
바운디드 컨텍스트를 통합하는 두 번재 단순한 방법은 메시징 메커니즘을 사용하는 것이다. 상호작용해야 하는 각 시스템은 메시지 큐나 Pub-Sub 메커니즘을 사용한다. 물론 메시징 게이트웨이를 API로 생각할 수도 있지만, 대신 이를 단순한 서비스 인터페이스로 간주한다면 수용 범위를 좀 더 광범위하게 넓힐 수 있따. 메시징을 이용할 때 사용할 수 있는 많은 수의 통합 기업이 있다.
# Restful HTTP
바운디드 컨텍스트를 통합하는 세 번째 방법은 레스트풀 HTTP를 사용하는 것이다. 일부에선 이를 원격 프로시저 호출 접근법의 한 종류로 생각하기도 하지만, 사실은 그렇지 않다. 한 시스템에서 다른 시스템으로 요청한다는 점에선 비슷한 속성이 있긴 하지만, 이 요청은 매겨번수를 포함한 프로시저를 사용해 만들어지지 않는다. REST는 구분된 URI를 사용해 고유하게 식별된 리소스를 교환하고 수정하는 수단이다. 레스트풀 HTTP는 주로 GET, PUT, POST, DELETE 등의 메소드를 제공한다. 단지 CRUD 오퍼레이션을 지원하는 듯 보일지도 모르지만, 네 가지 범주 중 하나로 오퍼레이션의 명시적 의도를 분류할 수 있다. 예를 들면 GET은 다양한 쿼리 오퍼레이션을 분류하는데 쓰이고, PUT은 애그리게잇상에 실행하는 커맨드 오퍼레이션을 캡슐화해준다.
바운디드 컨텍스트를 통합하는 세 가지 일반적인 방법에 대해 강조했지만, 실제로 13장에선 2가지만 다룬다.
- 메시징 메커니즘
- 레스트풀 HTTP
주로 메시징 메커니즘으로 통합하는데 집중하지만, 레스트풀 HTTP를 어떻게 사용하는지도 함께 살펴본다. RPC를 사용하는 예제는 설명하지 않는데, 자율적인 애플리케이션의 지원이 목표라면, RPC는 탄력성이 좀 떨어진다. 보통 PRC 기반의 API를 지원하는 실패한 시스템에선 의존적 시스템이 수행하는 오퍼레이션의 성공을 방해한다.
13-2. 분산 시스템은 근본적으로 다르다
분산 경험이 미숙한 사람들은 보통 모든 원격 호출이 인프로세스 호출처럼 쉽다고 생각하기 때문이다. 이런 가정은 단 하나의 시스템이나 그 컴포넌트가 단지 일시적으로라도 사용이 불가능해질 때 많은 수의 시스템에 걸쳐서 연쇄적인 실패를 야기할 수 있다. 분산 시스템 내에서 작업하는 모든 개발자는 다믕과 같은 분산 컴퓨팅의 원칙을 따르는지에 따라 성공 여부가 결정된다.
- 네트워크는 신뢰할 수 없다.
- 언제나 지연이 있을수 있고, 많을 수 있다.
- 네트워크가 안전하다고 가정하지 말라
13-3. 시스템 경계에 걸친 정보 교환
우리의 시스템이 외래 시스템으로부터 서비스를 제공받아야 할 필요가 있는 대부분의 경우는 정보적 데이터를 해당 서비스로 전달해야 한다. 우리가 사용하는 이런 서비스는 종종 응답도 제공해야 한다. 그러므로 우리는 시스템 사이에 정보적 데이터를 전달할 신뢰할 만한 수단이 필요하다. 이 데이터는 별도의 시스템들 사이에 정보적 데이터를 전달할 신뢰할 만한 수단이 필요하다. 이 데이터는 별도의 시스템들 사이에서 모든 관련자들이 쉽게 사용될 수 있는 구조로 교환돼야 한다.
# 직렬화, 역직렬화
시스템 사이의 정보를 교환하는 데 사용할 구조를 생성하는 몇 가지 방법이 있다. 첫번째 방법은 단순한 기술적 구현으로 프로그래밍 언어 기능에 의존해 객체를 이진 포맷으로 직렬화하고 컨슈머 측에서 이를 다시 역질렬화하는 방법이 있다. 이는 모든 시스템이 같은 언어 기능을 지원하고 직렬화가 서로 다른 하드웨어 아키텍처 사이에서 호환 가능하며 교환 가능해야만 잘 작동한다. 또한 모든 시스템에 걸쳐 사용되는 객체의 인터페이스와 클래스를 특정 객체 타입을 사용하는 각 시스템으로 배포해야 한다.
# 표준 중간 포맷 (XML, JSON)
교환 가능한 정보 구조를 만드는 또 하나의 접근법으로 몇가지 표준 중간 포맷을 사용하는 방법이 있다. 몇가지 사용 가능한 옵션으로 XML과 JSON이나 프로토콜 버퍼 등의 특수 포맷이 있다. 이런 접근법은 풍부함, 간결함, 타입 변화의 성능, 여러 객체 버전의 유연한 지원, 사용의 용이성 등을 비롯한 각각의 장단점을 가진다. 이런 중간 포맷의 접근법을 따르더라도, 모든 인터페이스와 객체의 클래스를 여러 시스템에 걸쳐 배포하거나, 도구를 사용해 중간 포맷의 데이터를 여러분의 타입 안전 객체에 담길 원할 수도 있다. 이는 데이터를 소비할 시스템에서도 데이터를 만들 시스템과 동일한 방식으로 객체를 사용할 수 있따는 장점이 있다.
13-4. 레스트풀 리소스를 사용한 통합
풍부한 레스트풀 리소스를 URI를 통해 바운디드 컨텍스트가 제공한다면, 이는 오픈 호스트 서비스의 한 종류다. 오픈 서비스의 집합으로서 동작하는 리소스와, 그에 결합된 HTTP 메소드를 쉽게 생각해볼 수 있따. HTTP와 REST는 서브시스템과 통합해야 하는 모든 이들이 원하는 바를 달성할 수 있도록 확실한 오픈 프로토콜을 형성한다. 사실상 무한한 수의 리소스가 생성될 수 있다는 사실은 프로토콜이 필요에 따라 새로운 통합 요구사항을 처리할 수 있도록 해준다. 이는 클라이언트가 여러분의 바운디드 컨텍스트와 통합하도록 해주는 유용한 방법이다.
그렇다고 해도 레스트풀 서비스 제공자는 리소스에 동작이 실행될 때마다 직접적으로 상호작용해야 하기 때문에, 이 스타일은 클라이언트에게 완전한 자율성을 허요하진 않는다. 만약 어떤 이유로든 REST 기반의 바운디드 컨텍스트의 사용이 불가능해지면, 의존성을 갖는 클라이언트의 바운디드 컨텍스트는 가동이 중지도니 동안 필요한 동작을 수행할 수 없게 된다.
하지만 레스트풀 리소스의 의존성이 컨슈머 자율성에 방해가 덜 되도록 어느 정도는 이를 개선할 수 있다. 레스트풀이 통합의 유일한 수단이더라도 시스템에서 타이머나 메시징을 사용하면 일시적인 분리의 환상을 만들어낼 수있다. 원격 시스템이 사용 불가능하다면 타이머의 임계 값을 좀 더 뒤로 미룰 수 있고, 메시징을 사용할 땐 브로커가 부정 수신 확인을 알아채고 재전달할 수 있다. 이는 시스템이 느슨하게 결합되도록 만드는 짐을 지우지만, 이는 자율성을 얻기 위해 치러야 하는 값이다.
설계의 대부분은 통합하는 바운디드 컨텍스트로 하여금 사용자와 그룹 ID를 포함한 리소스를 GET하도록 허용하고, 그 ID의 종류에 따른 역할에 기반해 보안 권한을 표시하도록 했다. 이는 간단한 레스트풀 HTTP 설계이다.
# 레스트풀 리소스의 구현
사우스오베이션 팀은 오픈 호스트 서비스를 제공할지 고민하면서, 단순히 그들의 도메인 모델을 레스트풀의 링크된 리소스의 집합으로 드러내는 방안을 생각했다. 이는 HTTP클라이언트로 하여금 고유 테넌트 리소스를 GET해서 그에 해당하는 사용자와 그룹과 역할을 탐색하게 한다는 뜻이다.
Q. 이런 방안이 좋은 생각일까?
A. 이런 방식이 자연스러워 보이고 최상의 유연성을 갖도록 해줄 거라 생각하였다. 그리고 자신의 고유한 바운디드 컨텍스트 안에서 단순히 결정만 내리면 된다..
어떤 DDD 컨텍스트 매핑 패턴이 이 설계 접근법을 가장 잘 묘사할까? 현실에서 이는 오픈 호스트 서비스가 아니라 공유된 모델의 크기에 따라 공유된 커널이나 순응주의자에 해당하게 된다. 공유된 커널을 발행하거나 순응주의자 관계를 수용함은 컨슈머 측에서 이를 사용하는 도메인 모델과 밀접하게 결합된 통합을 하게 된다. 이런 종류의 관계는 가능하면 피해야 하는데, 이는 DDD의 가장 근본적인 목표와 상반되는 경향이 있기 때문이다.
13-5. 메시징을 사용한 통합
메시지 기반의 접근법을 사용한 통합은 한 시스템이 의존적인 시스템으로부터 좀 더 높은 수준의 자율성을 달성할 수 있도록 해준다. 메시징 인프라가 기능적으로 유지되는 한, 메시지는 한 시스템을 사용할 수 없는 상황에서도 전달 될 수 있다.
DDD를 활용해 시스템을 자율성 있게 만드는 한 가지 방법은 도메인 이벤트의 사용이다. 한 시스템에 뭔가 중요한 일이 발생하면 이와 관련된 이벤트를 만든다. 각 시스템 안에는 이런 이벤트가 서너 개 이상 있을 수 있고, 이런 각각의 이벤트를 기록하기 위해 고유한 종류의 이벤트를 생성한다. 이벤트가 발생하면 메시징 메커니즘을 통해 이행 당사자들에게 발행된다.
13-6. 메시징이나 시스템을 활용할 수 없을때
복잡한 소프트웨어 시스템을 개발하는데 있어서 어떤 접근법이라 해도 만병통치약이 될 수는 없다. 모든 접근법에는 나름의 쟁점과 단점이 있다. 메시징 시스템의 한 가지 문제점은 일정 기간 동안 사용이 불가능할 수 있다는 점이다.
메시징 메커니즘이 일정 기간 동안 오프라인이라면, 알림 발행자는 메시지를 보내기 위해 이를 사용할 수 없다. 발행하는 클라이언트가 상황을 가지할 수 있기 때문에, 메시징 시스템이 다시 사용 가능할 때까지 알림 발송 시도를 잠시 미루는 편이 최선일 수 있다. 어떤 하나의 발송만 성공해도 사용 가능한 상태가 됐음이 분명해지지만, 그 전까지 모든 기능이 잘 작동할 때보다.발송 시도를 줄이도록 하자. 재시도 사이에 일정 시간 동안 지연을 추가하는 편이 좋다. 만약 시스템이 이벤트 저장소를 포함하고 있다면, 이벤트는 동작 중인 시스템 내의 큐에 계속해서 추가되며, 메시징이 다시 가능해졌을 때 이를 발송할 수 있다.
메시징 인프라가 잠시 동작하지 않을 땐 리스너가 새로운 이벤트 전달 알림을 수신하지 못한다 그렇다면 메시징 메커니즘이 다시 사용 가능해졌을 땐 클라이언트 리스너가 자동으로 재활성돼야 할까?, 아니면 컨슈머 쪽 클라이언트 매커니즘의 구독 신청이 필요할까? 만약 컨슈머의 자동 회복이 지원되지 않는다면, 컨슈머가 재등록되도록 확실히 해야 한다. 그렇지 않으면 바운디드 컨텍스트와 그에 의존하는 바운디드 컨텍스트가 서로 계속해서 상호 교류하는 데 필요한 알림을 수신하지 못한다. 이는 절대 피해야할 결과적 일관성 중 하나이다.
메시지 기반 문제의 원인이 언제나 메시징 메커니즘인 것은 아니다. 바운디드 컨텍스트가 다소 오랜 기간 동안 사용이 불가능해 진다. 이 바운 디드컨텍스트가 다시 사용 가능해진다. 이 바운디드 컨텍스트가 다시 사용 가능해지면 해당 컨텍스트가 구독하는 지속적 메시지 익스체이지/큐가 전달되지 않은 여러 메시지를 수집한다. 바운디드 컨텍스트가 다시 시작되고 해당 컨슈머를 등록하면, 가능한 알림을 수신하고 처리하기 위해 상당한 시간이 필요할 수 있다. 또한 이중노드를 포함하도록 개발해 노드 하나를 잃더라도 시스템 전체가 사용 불가능해지지 않도록 노력해야 한다.
'
'DDD' 카테고리의 다른 글
14장. 애플리케이션 / IDDD (도메인 주도 설계 구현) (0) | 2022.03.17 |
---|---|
12장. 리파지토리 / IDDD (도메인 주도 설계 구현) (0) | 2022.03.17 |
11장. 팩토리 / IDDD (도메인 주도 설계 구현) (0) | 2022.03.16 |
10장. 애그리게잇 / IDDD (도메인 주도 설계 구현) (0) | 2022.03.16 |
9장. 모듈(패키지) / IDDD (도메인 주도 설계 구현) (0) | 2022.03.16 |