Post
KO

도메인주도 설계 구현

DDD 는 전술적인 패턴이다.

DDD 설계에서는 유비쿼터스 언어를 통하여, 흩어진 용어들을 하나로 합친다.

핵심 비즈니스 도메인의 개념과 용어를 소프트웨어 개발 모델로 포착해야 하는 팀을 위한 패턴이다. 소프트웨어 모델은 명사, 형용사, 동사를 비롯해 한 명 이상의 도메인 전문가가 포함된 개발팀에서 표현하는 풍부한 표현들도 포함 된다.

전략적 모델링

![]()

헥사고날 아키텍처(hexagonal architecture, port&adapter pattern) 등도 설명되어 있고, 이것은 MSA 관련해서도 언급했던 내용이다.

위와 같이 서로 다른 바운디드 컨텍스트 간 통신하는 것을 헥사고날 아키텍처등으로 나타낼 수 있다고 언급하였다.

도메인

문제적 공간 (problem space) 와 해결책 공간을 모두 갖고 있다.

  • 문제적 공간은 핵심 도메인을 만들기 위해 개발하는 전체 도메인의 일부이다.

핵심도메인과 서브도메인이 사용하는 서브도메인 조합.

  • 해결책 공간 하나 이상의 바운디드 컨텍스트들이며 구체적인 소프트웨어 모델의 집합이다.

컨텍스트 마다 모델링한 객체는 서로 다를 수 있다.

ㄴ> 공통으로 다루기 보다는 해당 도메인을 풀어가기 위하여 적합한 의미를 나타내기 위하여 만드는 것으로 생각함.

한개 이상의 외부 개념이 들어오려 한다면 없애 버리자.

ㄴ> 진정한 핵심 도메인의 일부가 아닌 외부 개념은 제외 되어야 한다.

바운디드 컨텍스트 크기를 신중히 생각하자.

(너무 성급하게 최소화 하지 말라.)

바운디드 컨텍스트 안의 문제의 의미와 정의를 벗어난 모델을 무기력증에 빠진 모델로 남겨두지 말자.

아키텍처

최종적인 목표는 올바른 아키텍처와 아키텍처 패턴을 선택해 조합하는 것이다.

리스크 주도 (risk driven)

사용중인 모든 아키텍처의 영향을 정당화하고, 정당화 할 수 없다면 시스템에서 제거해야 한다.

아키텍처는 얼마나 멋진지 판단하기 위한 척도가 아니다. 이어지는 아키텍처 스타일과 패턴은 모든 가능한 위치마다 존재하는 것이 아니다. 프로젝트 실패 리스크를 줄여주는 위치에서만 사용하자.

파이프와 필터 패턴

https://docs.microsoft.com/ko-kr/azure/architecture/patterns/pipes-and-filters

파이프 및 필터 패턴 - Cloud Design Patterns

복잡한 처리를 수행하는 작업을 재사용 가능한 일련의 별도 요소로 분류합니다.

계층 아키텍처

도메인 모델과 비즈니스 로직의 표현을 격리하고(isolate) 인프라의 의존성이나 사용자 인터페이스나 비즈니스로직을 제외한 애플리케이션 로직 등도 모두 제거하라. 복잡한 프로그램은 계층으로 나눠라. 각 계층 내에선 응집력 있고 하위 계층들에만 의존하는 설계를 만들어라.

도메인 모델이 고유한 핵심 문제만 알면 된다.

도메인 이벤트 게시자를 경량으로 유지할 수 있다.

메시징 인프라스트럭처 의존성으로 부터 해방된다.

계층형 아키텍처 형태는 익숙한 형태이다.

의존성 역행의 원리

상위 수준의 모듈은 하위 수준의 모듈에 의존해선 안된다.

둘 모두 반드시 추상화에 의존해야 한다.

추상화는 세부사항에 의존해선 안된다.

세부사항은 추상화에 의존된다.

Restful HTTP 서버 주요 특징

리소스가 핵심이다.

대상이 무엇인지 결정하고 각각 구분된 식별자를 부여한다. 각 URI는 반드시 하나의 리소스를 가리켜야 한다는 점이다.

자술적 메시지를 사용해 무상태로 의사소통을 한다는 계념이다.

독립적으로 각각 리소스를 엑세스 할 수 있게 해주며, 이런 측면을 바탕으로 대규모 확장성을 달성할 수 있다. ex) Get 메소드는 '안전한' 오퍼레이션에만 사용 되야 한다. 이는 클라이언트가 요청하지 않은 효과를 반영한 행동을 할 수 도 있다. 이는 데이터를 읽기만 한다. 이는 잠재적으로 캐싱될 수 있다. (서버가 적절한 응답 헤더를 사용해 이를 표현 할 경우)

커멘드 쿼리 책임 분리 - CQRS ( Command Query Responsibility Segregation)

모든 메소드는 작업을 수행 하는 커멘드이거나 데이터를 호출자에게 반환하는 쿼리 중 하나여야 하고,

하나의 메소드가 두가지 역할을 모두 할 수 없다.

즉 질문하는 행동이 대답을 바꿔선 안된다.

좀 더 형식적으로 말하자면, 메소드는 오직 참조적으로 투명해서(referentially trasport) 다른 부작용을 일으키지 않을 때만 값을 반환해야 한다.

  1. 메소드가 객체 상태를 수정한다면, 이 메소드는 커멘드이며 값을 반환하면 안된다. 자바와 C#에선 메소드를 void로 선언해야 한다.

  1. 메소드가 값을 반환 한다면, 이 메소드는 쿼리이며 직접적이든 간접적이든 객체 상태를 수정을 야기해선 안된다. 자바와 C#에선 메소드를 반환 값의 타입과 함께 선언해야 한다.

![](/assets/images/posts/221479371433/8af34eadf37c.png?type=w580)

CQRS와 함께, 클라이언트의 커맨드는 커맨드 모델로 한 방향으로 이동한다.

쿼리는 프리젠테이션에 최적화된 별도의 데이터 소스에 대해 실행되고

사용자 인터페이스나 보고로 전달 된다.

데이터베이스 테이블 뷰가 오버헤드의 원인이 되지 않을까? 기본 데이터베이스 부는 지원 테이블에서 업데이트를 수행하고 있을 때 오버헤드가 없다.뷰는 단순히 쿼리에 응답할 뿐이며, 이 때에도 조인을 요구하지 않는다. 오직 구체화된 뷰(Materialize View)만이 데이터 선택에 앞서 뷰의 데이터를 다른 위치로 복사해야하기 때문에 업데이트 오버헤드를 발생시킨다. 쿼리 모델의 업데이터가 최적화되어 수행 될 수 있도록 테이블과 뷰의 설계에 주의하자.

이벤트 구독자 쿼리 모델 업데이트

이벤트 소싱을 사용할 때 수행 되어지는 작업의 동작 방식에 대하여 고민하라.

일반적인 여러 데이터베이스 동기화가 필요하다면 동기식으로 작성하고,

(대신 여러 테이블을 업데이트 할 때에 발생되는 비용에 대해 생각해봐야 한다.)

일반적으로 시스템이 큰 부하에 걸려 있고, 쿼리 모델 업데이트 프로세스가 길다면 비동기적 업데이트를 사용하자.

가장 최근에 변경을 즉시 반영하지 못해서, 결과적으로 일관성을 갖는데 어려움이 있을 수 있다.

지체 시간은 예측이 불가하지만 다른 SLA를 만족시키기 위해선 불가피 하다.

SLA Service Level Agreement

이벤트 주도 아키텍처

이벤트 주도 아키텍처 (EDA, Event Driven Architecture)는 이벤트의 생산, 감지, 소비와 이벤트에 따른 응답 등을 촉질하는 소프트웨어 아키텍처이다.

EDA가 헥사고날을 사용하여 개념을 표시하기엔 괜찮은 방법이다.

*장기 실행 프로세스

병렬처리되어지는 장기 실행 프로세스의 경우 언제 실행되었고 종료 되었는지 알 수 없음으로 이런 상황을 해결하는 첫 단계는 관련 도메인 이벤트에 고유 프로세스 식별자를 부여하는 것이다.

장기 실행 프로세스는 종종 분산 병렬 처리와 관련이 있을 수 있지만, 분산 트랜젝션과는 전혀 상관 없다. 여기선 결과적 일관성(eventual consistency)을 포괄하는 사고 방식이 필요하다.

장기 실행 프로세스를 신중히 설계하기 위한 노력이 필요하고, 인프라나 테스크 자체가 실패하면 반드시 잘 설계된 에러 복구가 이뤄진다고 기대할 수 있어야 한다.

나머지는 추후에

This article is licensed under CC BY 4.0 by the author.