CQRS(Command Query Responsibility Segregation)가 뭔데
CQRS는 영어 줄임말 그대로 Command와 Query를 분리한다는 개념입니다. Command가 뭐고, Query는 또 뭐고, 왜 분리해야 할까요?
- Query - 읽는 동작입니다. 읽기만 할 뿐 데이터나 상태를 절대 변경시키면 안 됩니다.
- Command - 변경하는 동작입니다. 보통 내부 상태나 데이터를 구체적으로 어떻게 변경할지는 명시하지 않고 도메인에 맞는 동작을 전해주는 경우가 많습니다.
여기서 Command에 대해 자세히 알아봅시다! Command가 상태를 변경한다고 해도 이를 명시적으로 하면 결국 어떤 동작을 해야 할지 각각의 도메인에 가서 다 확인해야 합니다.
예를들어 배송 시스템이 있다고 하고 유저가 주문을 넣으면 아래 동작들 한다고 가정해 보겠습니다.
- 장바구니에서 주문한 상품들을 삭제
- 주문 내역에 주문한 상품들을 추가하고 상태를 준비중으로 바꿈
- 택배 배송 시스템에 유저가 주문한 상품 발주 데이터를 넣고 상태를 준비중으로 바꿈
- 유저가 시킨 상품의 금액에 따라 포인트를 지급
- 상품 통계 시스템에 유저가 주문한 상품들을 반영하도록 수정
1개의 동작인데 해야하는 데이터 변경과 상태 변경이 너무 많습니다. 만약에 이 상태에서 상품이 배송중일때 유저가 주문을 취소한 경우, 배송완료했는데 상품을 환불한 경우, 상품이 불량인 경우 등을 다 고려해서 저 상태들을 다 조작하고 데이터를 조작해야 한다면… 사람의 머리가 이 복잡성을 감당할 수 있을까요?
이럴때 더 좋은 방법은 Command에 넣을 도메인 이벤트를 미리 정의하는 겁니다. 예를들어 아래와 같은 이벤트를 생각할 수 있겠죠?
- 상품 주문
- 상품 취소
- 상품 반품
- 상품 불량
그리고 Command에는 이 이벤트만 전달해 주고, Command에서 적절하게 내부 상태와 데이터에 따라 처리하는 겁니다. (이 Command 안에는 또 비슷한 구조가 있을 수 있겠죠?)
본질
순수함수, 객체지향, CQRS… 소프트웨어 설계에는 1개의 공통된 본질이 있습니다. 바로 눈에 보이는 복잡성을 줄이는 겁니다. 사람이 1번에 처리할 수 있는 정보의 양은 한정되어 있는데 너무 과도하게 복잡하면 우리는 이것을 제대로 처리할 수 없습니다. CQRS 같은 경우 Query는 상태나 데이터를 변경하지 않는다고 확실을 가지기 때문에 무언가의 상태를 추적할 때 Query 부분은 무시해도 됩니다. 또, Command에서 명시적으로 상태나 데이터를 변경하지 않고 도메인을 전해주니 복잡성을 크게 줄일 수 있습니다.
CQRS의 치명적인 단점
이 모든 장점에도 CQRS에는 치명적인 단점이 있습니다. 바로 규칙을 엄격하게 지키지 않으면 점점 장점들이 줄어들고 오히려 쓸데없이 복잡하고 추상적이게 된다는 겁니다. 새로 온 개발자가 별 생각 없이 Query에 상태나 데이터를 변경하는 코드를 넣었다고 해 봅시다. 그럼 이제 Query에는 상태나 데이터를 변경하지 않는다고 확실할 수 없습니다. 그럼 결국 복잡성을 추상적인 수준에서 바라보지 못 하고 Query 하나하나, Command 하나하나의 동작도 뜯어봐야 하니 이해가 힘들어집니다.
그러니 단순히 CQRS만 도입한다고 끝나는게 아니고, CQRS의 장점을 느끼기 위해서는 CQRS의 필요성에 대한 팀원들의 공감대를 얻고 지속적으로 소통하며 합의를 이끌어 내야 하는 어려운 작업입니다. 하지만 순수 학문과는 달리 엔지니어링의 어려우면서도 매력적인 측면이 이런 부분이 이런 부분이 아닐까 싶습니다.
언제 써야 할까?
CQRS를 쓰는 순간 Application의 전체적인 Architecture의 복잡성은 증가합니다. 그래서 굳이 간단한 Application에 CQRS를 도입할 필요는 전혀 없습니다. (엄격한 의미에서의 CQRS를 말하는 겁니다.)
또, 단순한 CRUD에서도 굳이 복잡성만 증가시킬 필요는 없습니다. 상태 변경이 복잡하고, 다루는 데이터 사이의 관계가 복잡할 때 CQRS는 비로소 빛을 바라는거 같아요.
'👨💻 프로그래밍 > Architecture' 카테고리의 다른 글
도메인 모델 풍부하게 만들기 (1) | 2024.05.04 |
---|---|
핵사고날? 클린 아키텍처? DDD? (0) | 2024.01.28 |
Redis, RabbitMQ, Kafka를 각각 Message Queue로 사용할 때의 장단점 (1) | 2023.09.30 |
🔒 분산 Architecture에서 Redlock으로 Lock 걸기 (0) | 2023.09.28 |
MSA 환경에서 Circuit Breaker를 쓰는 이유, 그럼에도 발생하는 문제 Bulkhead로 해결하기 (0) | 2023.09.24 |