서비스 함수를 메시지 핸들러로 리팩터리 하기
- 일반적으로 사용하는 서비스 레이어의 함수를 메시지 핸들럴로 변경하여 모든 서비스 계층의 메서드를 이벤트 기반으로 변경하는 것이다.
def add_batch(
event: events.BatchCreated, uow: unit_of_work.AbstractUnitOfWork):
with uow:
product = uow.products.get(sku=event.sku)
...
def allocate(
event: events.AllocationRequired, uow: unit_of_work.AbstractUnitOfWork
) -> str:
line = OrderLine(event.orderid, event.sku, event.qty)
...
def send_out_of_stock_notification(
event: events.OutOfStock, uow: unit_of_work.AbstractUnitOfWork
):
email.send(
'stock@made.com',
f'Out of stock for {event.sku}',
)
...
-
이벤트를 도입하면 애플리케이션이 어떤 유스 케이스를 호출 할 때 기본 타입들의 특정 조합을 기억할 필요가 없다는 장점이 있다.
-
단지 애플리케이션에 입력을 표현하는 단일 이벤트 클래스를 사용하면 된다. 또한 이런 이벤트들은 입력값을 검증할 수 있는 좋은 장소이다.
-
따라서 이벤트로 작성하도록 API를 변경한 모습은 아래 코드와 같다.
@app.route("/allocate", methods=["POST"])
def allocate_endpoint():
try:
event = events.AllocationRequired(
request.json['orderid'], request.json['sku'], request.json['qty']
)
results = messagebus.handle(event, unit_of_work.SqlAlchemyUnitOfWork())
batchref = results.pop(0)
except services.InvalidSku as e:
return {"message": str(e)}, 400
return {"batchref": batchref}, 201
-
JSON 요청에서 기본값으로 서비스 계층을 호출하는 대신에, 이벤트를 인스턴스화 시켜서 메시지 버스에 이벤트를 전달하는 것을 확인할 수 있다.
-
서비스 계층 함수들은 이제 이벤트 핸들러가 되었으며, 서비스 계층 함수 호출과 도메인 모델에서 발생한 내부 이벤트를 처리하기 위한 함수 호출이 동일해졌다.
-
이벤트는 시스템 입력을 잡아내는 데이터구조로 사용이 되며 내부 작업 덩어리를 전달하기 위한 데이터 구조로도 사용된다.
-
이벤트는 시스템 안의 내부 메시지와 입력에 대한 데이터 구조를 정의하는 간단한 데이터 클래스이다.
-
이벤트는 비즈니스 언어로 아주 잘 번역되기 때문에, DDD 관점에서 이벤트는 상당히 강력한 개념이다.
-
핸들러는 이벤트에 반응하는 방법이며, 핸들러는 모델을 호출하거나 또한 핸들러는 다른 이벤트를 만들어 낼 수도 있다.
-
이를 통해서 핸들러가 수행하는 일의 크기를 세밀하게 조절해서 SRP를 유지할 수도 있다.
이벤트 기반 아키텍처 패턴을 채택하는 이유
-
이런 아키텍처 패턴을 채택한 목적은 애플리케이션이 커지는 속도 보다, 복잡도가 증가하는 속도를 느리게 만들기 위해서이다.
-
메시지 버스에 모든 것을 실으면 아키텍처의 복잡도 측면에서는 비용을 지불하지만, 필요한 작업을 수행하기 위해서 더 이상 개념적으로나 아키텍처적으로나 코드를 변경할 필요가 없이 복잡한 요구사항을 거의 다 처리할 수 있다.
-
예제에서 복잡한 유스케이스 (수량 변경, 할당 해제, 새로운 트랜잭션 시작, 외부에 통지)를 추가했지만, 아키텍처 측면에서 보면 이런 내용을 추가해도 아무 복잡도 추가가 없다.
전체 애플리케이션이 메시지 버스인 경우 장/단점
-
애플리케이션 전체가 메시지 버스로 이루어진 경우 장점은 핸들러와 서비스가 같은 객체라서 더 단순하며, 시스템 입력을 처리하기 좋은 데이터 구조이다.
-
단점은 웹이라는 관점에서는 메시지 버스가 조금 예측 하기 어려운 처리 방식이며 작업이 언제 끝나는지 예측하기도 어렵다 그리고 모델 객체와 이벤트 사이에 필드 중복이 있고, 이에 대한 유지보수가 필요하다. 한쪽에 필드를 추가한다면 다른쪽에 속한 객체에 두 개 이상 필드를 추가해야 한다.
참고 문헌
>> Home