Skip to content

Latest commit

 

History

History
298 lines (145 loc) · 14.9 KB

File metadata and controls

298 lines (145 loc) · 14.9 KB

정리

아키텍처는 시스템 전체를 구성하는 것이 아닌 비즈니스 하위 도메인별로 달라질 수 있다.

비즈니스 로직과 아키텍처 패턴

소프트웨어에서 가장 중요한 요소는 비즈니스 로직이지만, 코드베이스는 비즈니스 로직 외에 다양한 요구사항을 구현하기 위해 많은 책임을 담당한다.

코드베이스가 처리해야 할 다양한 관심사로 인해 비즈니스 로직이 흩어지기 쉬워 유지보수가 어려워질 수도 있다.

아키텍처 패턴은 코드베이스의 다양한 측면에 대한 구성 원칙을 도입하고 명확한 경계를 제시한다.

이를 통해 단기적으로 비즈니스 로직 구현을 지원하고, 장기적으로 유지보수를 도울 수 있다.

계층형 아키텍처

**계층형 아키텍처(Layerd Architecture)**는 가장 일반적인 아키텍처 패턴으로 코드베이스를 수평 계층으로 조직하고, 각 계층은 하나의 관심사를 다룬다.

다음과 같이 프레젠테이션 계층(PL, Presentation Layer), 비즈니스 로직 계층(BLL, Business Logic Layer), 데이터 접근 계층(DAL, Data Access Layer)의 세 가지 계층으로 구성된다.

image

프레젠테이션 계층

프레젠테이션 계층은 사용자와 상호작용을 위한 프로그램의 사용자 인터페이스를 구현한다.

현대 시스템에서 프레젠테이션 계층은 그래픽 인터페이스, 동기식 또는 비동기식 수단과 같은 광범위한 범주를 다룬다.

  • 그래픽 사용자 인터페이스(GUI)
  • 커맨드 라인 인터페이스(CLI)
  • 다른 시스템과 연동하는 프로그래밍 API
  • 메시지 브로커에서 이벤트에 대한 구독
  • 나가는 이벤트를 발행하는 메시지 토픽

프레젠테이션 계층은 프로그램의 퍼블릭 인터페이스 역할을 한다.

image

비즈니스 로직 계층

비즈느시 로직 계층은 비즈니스 의사결정을 구현하고 묶는 것을 담당한다.

액티브 레코드 또는 도메인 모델과 같은 비즈니스 로직 패턴을 이 계층에서 구현한다.

image

데이터 접근 계층

데이터 접근 계층은 영속성 매커니즘에 접근할 수 있게 해준다.

NoSQL과 같이 여러 ㄷ이터베이스를 사용할 수 있고, 클라우드나 메시지 버스와 같이 다양한 매체를 정보 저장용으로 사용할 수도 있다.

또한 외부 정보 제공자와의 연동을 책임지기도 한다.

image

계층 간 커뮤니케이션

각 계층은 탑다운(Top-Down) 커뮤니케이션 모델에 따라 연동해 바로 아래 계층에만 의존하게 되어 구현 관심사의 결합을 낮추고 계층 간에 공유할 지식을 줄인다.

image

변종(variation)

흔히 계층형 아키텍처 패턴을 확장해서 서비스 계층을 추가하기도 한다.

서비스 계층

가용한 오퍼레이션을 구축하고 각 오퍼레이션에서 애플리케이션의 응답을 조정하는 서비스 계층을 애플리케이션의 경계에 정의한다.

서비스 계층은 프레젠테이션 계층과 비즈니스 로직 계층 사이의 중간 역할을 한다.

image

아키텍처 패턴의 컨텍스트에서 서비스 계층은 논리적 경계이며 프레젠테이션 계층과 하부의 비즈니스 로직의 결합을 제거하기 위해 사용된다.

조율 로직을 서비스 계층으로 분리하면 다음과 같은 장점이 있다.

  • 동일한 서비스 계층을 여러 퍼블릭 인터페이스에서 재사용할 수 있다.
  • 모든 관련 메서드를 한곳에 모으면 모듈화가 개선된다.
  • 프레젠테이션 계층과 비즈니스 로직 계층의 결합도를 낮춘다.
  • 비즈니스 기능을 테스트하기 쉬워진다.

서비스 계층은 트랜잭션 스크립트 패턴을 사용하는 경우 필요하지 않고, 액티브 레코드 패턴을 사용할 때 외부 조율을 해야할 경우 사용된다.

이 경우 서비스 계층은 트랜잭션 스크립트 패턴을 구현하고 실제 동작하는 액티브 레코드는 비즈니스 로직 계층에 둔다.

용어

  • 프레젠테이션 계층 = 사용자 인터페이스 계층
  • 서비스 계층 = 애플리케이션 계층
  • 비즈니스 로직 계층 = 도메인 계층 = 모델 계층
  • 데이터 접근 계층 = 인프라스트럭처 계층

계층형 아키텍처를 사용하는 경우

계층형 아키텍처 패턴은 비즈니스 로직과 데이터 접근 계층 간에 의존성이 있어 트랜잭션 스크립트 또는 액티브 레코드 패턴을 사용하여 구현된 시스템에 적합하다.

하지만 도메인 모델 패턴에서는 비즈니스 엔티티가 인프라스트럭처에 대한 의존성이 없어야 하기 때문에 적합하지 않다.

계층과 티어

계층은 논리적 경계고 티어는 물리적 경계이다.

포트와 어댑터

포트와 어댑터(Port & Adapter) 아키텍처는 계층형 아키텍처의 단점을 해결하고 복잡한 비즈니스 로직을 구현하는 데 적합하다.

용어

프레젠테이션 계층과 데이터 접근 계층은 기술적 구현 상세를 다루어 시스템의 비즈니스 로직을 반영하지 못하므로 인프라스트럭처 계층으로 통합했다.

image

의존성 역전 원칙

**의존성 역전 원칙(DIP, Dependency Inversion Principle)**에서 비즈니스 로직을 구현하는 상위 모듈은 하위 모듈에 의존하면 안 된다고 말한다.

전통적인 계층형 아키텍처에서는 비즈니스 로직 계층이 인프라스트럭처 계층에 의존해 DIP를 적용시켜 관계를 반대로 한다.

image

또한 시스템의 퍼블릭 인터페이스를 위해 애플리케이션 계층을 추가해 노출되는 모든 오퍼레이션을 설명하고 시스템의 비즈니스 로직을 조율한다.

다음과 같이 비즈니스 로직이 어떠한 하위 계층에도 의존하지 않는 포트와 어댑터 아키텍처를 나타낼 수 있다.

image

인프라 구성요소의 연동

인프라스트럭처 구성요소를 직접 참조하지 않고 비즈니스 로직 계층은 인프라스트럭처 계층이 구현해야 할 **'포트'**를 정의한다.

추상 포트(Abstract Port)는 인프라스트럭처 계층에서 의존성 주입 또는 부트스트래핑을 통해 구체적인 **'어댑터'**로 나타낸다.

image

변형

포트와 어댑터 아키텍처는 헥사고날(Hexagonal) 아키텍처, 어니언(Onion) 아키텍처, 클린(Clean) 아키텍처로 알려져있다.

동일한 설계 원칙에 기반하고 구성요소와 관계가 동일하더라도 사용하는 용어는 다를 수 있다.

  • 애플리케이션 계층 = 서비스 계층 = 유스케이스 계층
  • 비즈니스 로직 계층 = 도메인 계층 = 핵심 계층

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

모든 기술적 관심사로부터 비즈니스 로직을 분리하는 것이 목적이므로 도메인 모델 패턴을 사용한 비즈니스 로직에 적합하다.

CQRS

CQRS(Command-Query Responsibility Segregation) 패턴은 포트와 어댑터와 동일한 비즈니스 로직과 인프라스트럭처 관심사에 기반하지만 시스템의 데이터를 관리하는 방식이 다르다.

폴리글랏 모델링

대부분의 경우 단일 비즈니스 도메인 모델로 모든 요구사항을 해결하기는 어렵다.

OLTP(Online Transaction Processing)와 OLAP(Online Analytical Processing)에서는 시스템 데이터의 다양한 표현이 필요할 수 있다.

확장성이나 일관성, 질의 모델 간에 균형이 필요하기 때문에 완벽한 데이터베이스는 없다.

대신 **폴리글랏 영속성 모델(Polyglot Persistence Model)**을 통해 여러 데이터베이스를 사용할 수 있다.

CQRS 패턴은 이벤트 소싱 모델의 질의 한계를 극복하기 위해 정의되어 한 번에 하나의 애그리거트 인스턴스에 대한 이벤트를 질의할 수 있다.

하지만 다른 구현 패턴을 사용해도 CQRS 패턴을 유용하게 구현할 수 있다.

구현

커맨드 실행 모델

커맨드 실행 모델(Command Execution Model)은 시스템의 상태를 수정하는 오퍼레이션(시스템 커맨드)을 전담으로 수행하는 단일 모델이다.

시스템의 강력한 일관성을 가진 데이터를 표현하며 비즈니스 엔티티의 일관적 상태를 읽을 수 있고 낙관적 동시성을 지원해야 한다.

읽기 모델(프로젝션)

읽기 모델(Read Model)은 캐시에서 언제든 다시 추출할 수 있는 프로젝션이다.

읽기 모델은 읽기 전용으로 어떤 오퍼레이션도 읽기 모델의 데이터를 직접 수정할 수 없다.

읽기 모델의 프로젝션

읽기 모델이 작동하려면 시스템은 커맨드 실행 모델에서 변경을 모든 읽기 모델로 프로젝션해야 한다.

읽기 모델의 프로젝션은 RDBMS의 **머터리얼라이즈 뷰(Materialized View)**의 개념과 유사하다.

image

동기식 프로젝션

**동기식 프로젝션(Synchronous Projection)**은 격차 해소 구독 모델(Catch-Up Subscription Model)을 통해 OLTP 데이터의 변경사항을 가져온다.

  • 프로젝션 엔진이 OLTP 데이터베이스로부터 마지막에 처리했던 체크포인트 이후에 추가되거나 갱신된 레코드를 조회한다.
  • 프로젝션 엔진이 조회된 데이터를 이용해서 시스템의 읽기 모델을 재생성 또는 갱신한다.
  • 프로젝션 엔진은 마지막으로 처리 레코드의 체크포인트를 저장한다. 이 값은 다음 처리 때 추가되거나 갱신된 레코드를 조회하는 데 사용된다.

image

격차 해소 구독이 작동하기 위해서 커맨드 실행 모델이 추가되거나 갱신되는 모든 데이터베이스 레코드를 체크포인트로 관리해야 한다.

저장 메커니즘도 체크포인트 기반으로 레코드를 조회하는 것을 지원해야 한다.

동기식 프로젝션 메서드에서 새로운 프로젝션을 추가하고 기존의 것을 처음부터 다시 생성하는 것은 쉽다.

비동기식 프로젝션

비동기 프로젝션 시나리오에서 커맨드 실행 모델은 모든 커밋된 변경사항을 메시지 버스에 발행한다.

시스템의 프로젝션 엔진은 발행된 메시지를 구독하고 읽기 모델을 갱신하는 데 사용한다.

image

도전과제

비동기식 프로젝션 방식이 확장성과 성능이 좋지만 분산 컴퓨팅 문제가 발생하기 쉽다.

또한 새로운 프로젝션을 추가하거나 이미 존재하는 것을 재생성하는 것이 어려워 가능하면 동기식 프로젝션 방식으로 구현해야 한다.

모델 분리

커맨드는 강한 일관성을 가진 커맨드 실행 모델에서만 동작하고 질의는 읽기 모델과 커맨드 실행 모델을 포함하여 어떤 시스템의 영속 상태를 직접 수정할 수 없다.

커맨드는 우발적 복잡성을 줄이고 좋은 사용자 경험을 위해 데이터를 수정만 하는 것이 아닌 반환도 해야 한다.

하지만 데이터가 궁극적으로 일관성을 갖는 프로젝션의 경우 데이터에 대한 즉각적인 갱신은 기대할 수 없다.

CQRS를 사용해야 하는 경우

CQRS 패턴은 여러 모델, 다양한 종류의 데이터베이스에 저장된 동일한 데이터와 작동하는 애플리케이션에 유용하다.

이 패턴은 당면한 문제에 가장 효과적인 모델을 사용하고 비즈니스 도메인 모델을 지속적으로 개선하는 도메인 주도 설계의 핵심 가치를 지원한다.

또한 이벤트 소싱 도메인 모델에도 적합하다.

범위

계층형 아키텍처, 포트와 어댑터 아키텍처, CQRS는 시스템 전체에 적용하는 구성 원칙이 아니고, 전체 바운디드 컨텍스트를 위한 고수준 아키텍처 패턴도 아니다.

바운디드 컨텍스트에 단일 아키텍처를 강요하면 우발적 복잡성을 유발할 수도 있기 때문에 각 비즈니스 하위 도메인에 적합한 아키텍처를 사용해야 한다.

image

결론

계층형 아키텍처

기술적 관심사에 따라 코드베이스를 분해해 비즈니스 로직과 데이터 접근 구현을 결합시키므로 액티브 레코드 기반 시스템에 적합하다.

포트와 어댑터 아키텍처

비즈니스 로직과 인프라스트럭처의 의존성을 분리시키므로 도메인 모델 패턴을 구현하는 비즈니스 로직에 적합하다.

CQRS

여러 모델에서 동일한 데이터를 표현하므로 이벤트 소싱 도메인 모델과 다양한 영속 모델을 사용하는 시스템에 적합하다.

느낀점

아키텍처는 시스템의 전체적인 구성을 표현하기 위함이 아니라 비즈니스 하위 도메인별로 상황에 적합한 아키텍처를 사용하는 것이다.

하위 도메인마다 복잡성이 다르기 때문에 다음고 같은 상황에 적용하면 좋을 것 같다.

  • 핵심 하위 도메인: 포트와 어댑터 아키텍처 또는 CQRS
  • 일반 하위 도메인: 계층형 아키텍처 또는 CQRS
  • 지원 하위 도메인: 계층형 아키텍처 또는 CQRS

CQRS는 이벤트 소싱 도메인 모델의 한계를 극복하기 위해 정의된 것이기 때문에 이벤트 소싱과 함께 사용하면 더욱 효과적일 것 같다.

읽기 모델의 프로젝션을 해보면 복잡할 수도 있지만 재밌을 것 같다.