1. 개요

 

지금부터 EventSourcing과 CQRS가 적용된 프로젝트를 구현하면서 AxonFramework 사용법을 배워봅니다.

이에 앞서 앞으로 진행할 프로젝트에 대한 설계를 통해 구조를 잡아보겠습니다.

 

 

프로그램 요구사항 

 

  • 계정 생성시 소유주, 전화번호, 주소를 입력한다.
  • 계정 생성이 완료되면, 계정 ID가 발급된다.
  • 계좌 생성시, 계정 ID를 입력한다.
  • 계좌 생성이 완료되면 고유한 계좌 번호를 반환한다.
  • 계좌번호를 통해서 입금 가능하다.
  • 계좌번호를 통해서 출금 가능하다.
  • 인출과정에서 잔액이 부족한경우 "잔액이 부족합니다." 메시지를 출력한다.
  • 소유자가 보유한 전체 계좌 개수 및 잔액 조회가 가능하다.

2. 프로그램 설계

 

앞으로 구현할 프로그램은 간단한 은행 입출금 관련 데모입니다. 짧은 요구사항이지만 도메인이 복잡해진다면 계좌 관리(Account)거래(Transacation)는 별도 Bounded Context로 분리할 수 있습니다. 하지만 데모 프로젝트에서는 편의상 두 도메인을 하나의 Bounded Context에 구현하겠습니다.

 


CQRS 

 

AxonFramework는 기본적으로 CQRS 아키텍처를 따르므로, 데모도 마찬가지로 해당 구조를 기반으로 설계했습니다. 즉 Command 와 Query App을 분리하고 각 App별로 DB를 사용하도록 구성했습니다.

 

편의상 두 App의 DB는 Postgresql로 통일하였으며, 각기 다른 스키마 사용을 통해 두 DB를 논리적으로 분리했습니다. Command DB는 AxonFramework에서 내부적으로 사용하는 saga, token, association_value 데이터를 관리합니다.

(※ Read 모델은 MongoDB로 구성하는 등의 Polyglot 구조 변경 가능합니다.)

 

또한 이미 앞선 장을 통해서 EventStore 및 메시지 라우팅을 담당하는 AxonServer를 사용하고 있으므로 이는 고려하지 않겠습니다.

 


다이어그램

 

데모에서 사용되는 구조는 다음과 같습니다. Command 모델은 소유주(holder)와 계좌(accont)로 나뉘어 Aggregation을 만들었습니다. 반면 Query 모델은 소유주의 전체 계좌의 총액을 보여주도록 Materialized View 를 ERD로 표현했습니다.

 

 

Command 

 

Aggregate

 

Query

 

Materialized View
summary


Command, Event 도출

 

이벤트 주도 개발 방법에서 가장 중요한 것은 이벤트 설계입니다. 이때 Event Storming 전략을 사용하여 Command, Event 등을 도출합니다.

(※ Event Storming 단계에서 포스트잇을 사용하는데, 비슷한 느낌을 주기 위해서 이미지를 사용했습니다.)

 

 

계정 생성

계좌 생성

입금

출금


서비스 EndPoint 설계

 

다음은 Controller 매핑되는 API EndPoint를 설계하겠습니다.

참고로 Command App은 8080 , Query App은 9090 Port를 사용했습니다.

 

계정 생성

POST : localhost:8080/holder
{  
    "holderName" : 소유주,
    "tel" : 전화번호,
    "address" : 주소
}

계좌 생성

POST : localhost:8080/account
{
    "holderID" : 계정 ID
}

 

입금

POST : localhost:8080/deposit
{
    "accountID" : 계좌번호,
    "holderID" : 계정 ID,
    "amount":입금액
}

 

출금

POST : localhost:8080/withdrawal
{
    "accountID" : 계좌번호,
    "holderID" : 계정 ID,
    "amount":출금액
}

 

계좌 정보 조회

GET : localhost:9090/account/info/{accountID}

3. 테스트 시나리오

 

마지막으로 실제 App 수행시 진행할 테스트 시나리오를 다음과 같이 작성했습니다.

 

  1. 고객 Kevin이 계정을 생성한다. (소유주 : Kevin, 전화번호 : 02-1234-5678, 주소 : 서울시)
  2. Kevin이 계좌를 개설한다.(소유주 ID : 1번 과정을 통해 생성된 UUID)
  3. Kevin계좌에 1000원을 입금한다(계좌 ID : 2번 과정을 통해 생성된 UUID, 입금액 : 1000)
  4. Kevin 계좌에서 100원을 인출한다(계좌 ID : 2번 과정을 통해 생성된 UUID, 출금액 : 100)
  5. Kevin 계좌에서 200원을 인출한다(계좌 ID : 2번 과정을 통해 생성된 UUID, 출금액 : 200)
  6. Kevin 전체 계좌 잔액 내역을 조회한다.
  7. Kevin 계좌에서 800원을 인출한다(계좌 ID : 2번 과정을 통해 생성된 UUID, 출금액 : 800)
  8. "잔액이 부족합니다." 메시지를 확인한다.

4. 마치며

 

구현할 프로젝트에 대한 기본적인 설계를 마칩니다. 다음 포스팅에서는 프로젝트 생성을 위해 Gradle을 이용한 Multi Project 생성 방법에 대해서 다루겠습니다.

+ Recent posts