도메인 주도 설계 첫걸음 - 8장 : 아키텍처 패턴 (계층형 /CQRS / 포트와 어댑터)
책/도메인 주도 설계 첫걸음

도메인 주도 설계 첫걸음 - 8장 : 아키텍처 패턴 (계층형 /CQRS / 포트와 어댑터)

728x90
반응형

8. 아키텍처 패턴

  • 코드베이스가 처리해야 할 다양한 관심사로 인해 비즈니스 로직이 다양한 구성요소에 흩어지기 쉬움
    • 사용자 인터페이스 / DB에 의해 구현 혹은 다양한 구성요소에 중복
  • 관심사 구현 시, 엄격히 구성하지 않는다면 코드베이스의 변경에 대한 제약

 

 

계층형 아키텍처

고전적 아키텍처 : PL(Presentation layer) + BLL(Business logic) + DAL(Data access)

 

프로젠테이션 계층

  • 사용자와 상호작용 하기 위한 인터페이스 구현
  • ex) GUI/CLI/연동 API/메시지 브로커 이벤트 구독/이벤트 발행
  • 프로그램의 퍼블릭 인터페이스

비즈니스 로직 계층

  • 소프트웨어의 중심
  • 액티브 레코드 또는 도메인 모델과 같은 비즈니스 로직 패턴 적용
  • 엔티티 / 규칙 / 프로세스

데이터 접근 계층

  • 영속성 메커니즘 접근 가능케 함
  • 프로그램 기능 구현 시 필요한 다양한 외부 정보 제공자와 연동
  • DB / Message Bus / 오브젝트 스토리지

계층 간 커뮤니케이션

  • 계층은 톱다운 커뮤니케이션 모델 따라연동
  • 각 계층은 아래 계층에만 의존(결합도 낮추고, 공유할 지식 줄일 수 있음)

서비스 계층

  • 정의 : 가용한 오퍼레이션 구축, 각 오퍼레이션에서 애플리케이션의 응답 조정
  • ex) 상황에 따른 적절한 액션 - 에러 발생시, 적절한 응답 생성
  • 아키텍처 패턴의 컨텍스트에서 서비스 계층은 논리적 경계
  • 하부 계층을 조율하는 데 필요한 것들을 감싸, 퍼블릭 인터페이스의 메서드에 상응하는 인터페이스 노출
    • 각 모든 메서드는 시스템의 퍼블릭 인터페이스
interface CampaignManageMentService
{
  OperationResult CreateCampaign(CampaignDetails details);
  OperationResult Publish(CampaignId id, PublishingSchedule schedule);
  ...
}
  • 장점 :
    • 동일한 서비스 계층을 여러 퍼블릭 인터페이스에 재사용 가능
    • 모든 관련 메서드를 한 곳에 모으면 모듈화 개선
    • PL 과 BLL의 결합도 낮춤
    • 테스트 용이
  • 사용할 때:
    • 액티브 레코드 패턴을 사용하는 경우와 같이 비즈니스 로직 패턴에서 외부 조율이 필요할 경우
    • 이와 반대로, 비즈니스 로직이 tx 스크립트로 구현된 경우 이미 일련의 메서드가 노출되기 때문에 이것이 바로 서비스 계층 역할을 하는 셈

용어

  • PL = 사용자 인터페이스 계층
  • Service = 애플리케이션 계층
  • BLL = 도메인 계층 = 모델 계층
  • DAL = 인프라스트럭처 계층

계층형 아키텍처가 필요한 경우

  • 비즈니스 로직이 트랜잭션 스크립트 / 액티브 레코드 패턴을 사용하여 구현된 시스템
  • 반면 도메인 모델을 구현하는데 계층형 적용은 어려움
    • 도메인 모델에서 비즈니스 앤티티(애그리게이트/VO)가 하부의 infra에 대해 의존성이 없어야함

 

포트와 어댑터 (헥사고날)

  • PL + DAL = 결국 외부 구성요소와 연동 (인프라스트럭처 계층 통합 가능)
  • 핵심 목적 : 인프라스트럭처 구성요소로부터 시스템 비즈니스 로직간의 분리

DIP

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

  • but 전통적인 계층형 아키텍처 : 비즈니스 로직 계층이 infra에 의존하는 꼴
    • 비즈니스 로직 계층 <- 인프라스트럭처 계층
  • 해결 방법 : 둘 간의 의존성 반대로 / 중간에 애플리케이션 계층 추가
    • 애플리케이션 계층 : 시스템이 노출하는 모든 오퍼레이션 설명 / 이를 실행할 떄 시스템의 비즈니스 로직 조율

인프라 구성요소 연동

  • 포트 :application 입장에서 consumer, 또는 application에서 나가거나/들어오는 인터페이스
    • 비즈니스 로직 계층에서 정의
  • 어댑터 : 클라이언트에 제공해야 할 인터페이스를 따르면서도 내부 구현은 서버의 인터페이스로 위임
    • 인프라스트럭처 계층에서 구현
namespace App.BusinessLogicLayer
{
  public interface Imessaging
  {
     void Publish(Message payload);
     void Subscribe(MEssage type, Action callback);
   }
 }

namespace App.Infrastructure.Adapters
{
  public class SQSBus : IMessaging { ... } 
 }
  • 포트와 어댑터 아키텍처 = 헥사고날 아키텍처 = 어니언 아키텍처 = 클린 아키텍처로 알려짐
  • 계층형 아키텍처와의 용어 비교
    • 애플리케이션 계층 = 서비스 계층 = 유시케이스 계층
    • 비즈니스 로직 계층 = 도메인 계층 = 핵심 계층

포트와 어댑터를 사용하는 경우

  • 도메인 모델 패턴을 사용하여 구현한 비즈니스 로직에 매우 적합

 

CQRS (Command-query Responsibility segregation) 패턴

  • 포트와 어댑터와 동일한 비즈니스 로직과 인프라스트럭처 관심사에 기반
  • 이 패턴을 통해 여러 영속 모델에 시스템의 데이터 표현 가능

 

폴리글랏(polyglot) 모델링

  • OLTP / OLAP 에서는 시스템 데이터의 다양한 표현이 필요
  • 여러 모델로 작업하는 또 다른 이유 : 다양한 언어를 사용하는 영속성 개념과 관련이 있다.
  • 완벽한 데이터 베이스는 없기 떄문에 확장성이나 일관성 또는 지원하는 질의 모델 간에 균형이 필요하다
  • 폴리글랏 영속 모델 = 완전한 데이터 베이스의 대안 : 다양한 데이터베이스를 사용

CQRS 패턴 = 이벤트 소싱과 밀접한 관련

  • 한 번에 하나의 애그리게이트 인스턴스에 대한 이벤트 질의 가능
  • 프로젝션된 모델을 물리적 데이터베이스에 머터리얼라이즈하여 유연한 질의가 가능하도록 함

머터리얼라이즈 뷰 기능을 활용하여 빈번한 질의 결과를 물리 테이블에 저장하여 성능 개선

 

구현

  1. 커멘드 실행 모델
  • 시스템의 상태 수정 전담
  • 비즈니스 로직 구현 / 규칙 검사 / 불변성 강화
  • 일관적 상태를 읽을 수 있어야 하며 갱신시, 낙관적 동시성 지원
  1. 읽기 모델(프로젝션)
  • 데이터를 보여주고, 정보 제공을 위한 다양한 모델 제공
  • 읽기 전용 (수정 불가)
  • 읽기 모델이 작동하기 위해서는 시스템은 커멘드 실행 모델의 변경 -> 모든 읽기 모델로 프로젝션 해야함
  • 원천 테이블 갱신시, 변경사항은 미리 작성된 뷰에 반영되어야 함

동기식 프로젝션

  • 격차 해소 구독 모델(catch-up subscription model)을 통해 OLTP 데이터 변경사항 가져옴
    • DB로부터 마지막 처리했던 체크포인트 이후 추가 및 갱신 레코드 조회
    • 조회된 데이터를 통해 읽기 모델을 재생성 또는 갱신
    • 마지막 체크포인트 저장
  • 해당 모든 DB는 레코드를 체크포인트로 관리해야 한다.
  • SQL의 rowversion, 혹은 카운터 칼럼

비동기식 프로젝션

  • 커맨드 실행 모델은 모든 커밋된 변경사항을 메시지 버스에 발행
  • 시스템 프로젝션 엔진은 구독 & 읽기 모델 갱신
  • 확장성과 성능의 장점이 있지만, 분산 컴퓨팅 문제가 자주 발생할 것
  • 따라서 동기식 프로젝션 방식 구현이 좋다.

모델 분리

CQRS의 일반적 오해 :

커맨드 실행 메서드는 데이터를 반환해서는 안된다.

  • 대부분의 경우 커맨드는 데이터를 반환해야한다.
    • 유효성 검사 혹은 기술적 문제 등의 실패 이유 파악이 가능

CQRS를 사용해야 하는 경우

  • 다양한 종류의 DB에 저장된 동일한 데이터를 사용할 경우
  • 이벤트 소싱 도메인 모델에 적합
  • 이벤트 소싱 모델에서는 애그리게이트의 상태에 기반한 레코드 조회가 불가능하지만, CQRS에서는 상태를 질의할 수 있는 DB에 상태를 프로젝션 (?) 무슨말이냐

 

 

보면 좋은 것들 :
- https://github.com/xonmin/TIL/blob/master/DesignData-Intensive/chap11.md
- https://www.youtube.com/watch?v=fg5xbs59Lro

 

728x90
반응형