멈재

[JAVA/Spring] 10. CQS 패턴 (Command Query Separation) 본문

JAVA & Spring & JPA

[JAVA/Spring] 10. CQS 패턴 (Command Query Separation)

멈재 2022. 12. 17. 22:22
728x90

여러 디자인 패턴을 들어보긴 했지만, CQS 패턴은 나에게는 다소 생소한 패턴 중 하나이다.

디자인 패턴은 프로그램을 개발하는 과정에서 빈번하게 발생하는 디자인 상의 문제를 정리해서, 상황에 따라 간편하게 적용해서 쓸 수 있는 패턴 형태로 만든 것이다. - 헤드퍼스트 디자인 패턴 中 -

 

시간적 여유가 난다면 가장 먼저 다루고 싶었던 것이 바로 이 CQS 패턴이었다.

김영한 님의 스프링 로드맵에서 가끔 "커맨드와 쿼리를 분리시켜라."는 말을 들었는데, 그것이 바로 이 CQS 패턴을 말한 것이었다.

참고: https://www.inflearn.com/questions/27795/cqrs

 

CQRS - 인프런 | 질문 & 답변

안녕하세요. 정말 좋은 강의 항상 잘 듣고 있습니다. Repository save 메서드는 Member 를 반환하기보다는 id를 반환하는 식으로 구성하셨는데 이게 기본편에서 커맨드와 커리를 분리한기위함이라고

www.inflearn.com

 

CQS 패턴은 소프트웨어 디자인 패턴 중 하나로, 모든 객체의 메소드 작업을 수행하는 Command, 데이터를 반환하는 Query, 이렇게 2개로 구분하는 디자인 패턴이다.

다시 말하면, CQS는 객체의 모든 메서드를 Command와 Query 두 가지로 구분해야 하며, 하나의 메서드는 반드시 Command나 Query 둘 중 하나에만 속해야 한다는 걸 의미한다.

 

 

 

Command란?

Command는 객체의 상태를 변경하는 메서드로 값을 반환하지 않는다.

이 말을 즉슨, 시스템에 어떠한 side effect를 가하는 행위에서는 값을 반환하지 않아야 한다는 것이다.

void decreaseStock() { // OK 
    stock = stock - 1; 
} 
Integer decreaseStock() { // NO 
    return stock = stcok - 1; 
}

 

 

 

Query란?

Query는 객체 내부 상태를 바꾸지 않고 객체의 값을 반환하기만 한다.

이 말은 즉슨, 상태를 변경시키지 않아야 하고, 시스템의 상태를 단지 반환만 해야 한다.

Product getProduct(Long productId) { // OK 
    return products.get(productId); 
} 
void getProduct(Long productId) { // NO 
    Product product = products.get(productId);
    product.updateModifiedAt(); 
    return product; 
}

 

만약 하나의 함수에서 Command와 Query가 모두 동시에 일어나게 된다면, CQS 패턴을 지키지 못한 것이다.

거기다가 SOLID 원칙과 소프트웨어의 3가지 원칙 중 KISS(Keep It Simple, Stupid)가 지켜지지 않은 코드일 것이다.

 

SOLID 원칙이 위배되면 예상치 못한 side effect가 발생하고, 이는 예기치 못한 결과로 이어지기 때문에 CQS 패턴을 지킨다면 SOLID 원칙에 위배되지 않게 코드를 작성하는데 도움을 줄 수 있다.

 

그래서 CQS 패턴을 사용했을 때의 장단점도 알아보자.

 

장점

"읽기"와 "쓰기"를 분리할 수 있다.

즉, 읽기와 쓰기가 동시에 일어나지 않기 때문에 성능 최적화에 용이하고 읽기 편해진다.

 

단점

관리해야 하는 객체가 많아질 수록 Query, Command가 많아지기 때문에 중복 코드가 발생할 수 있고, 이에 따라 유지보수하는데 많은 노력이 들어갈 수 있다.

 

 

정리하면, Command와 Query를 분리함으로써 각 메서드의 의미를 명확하게 해주고, side effect가 발생할 수 있는 코드(Command)와 그렇지 않은 코드(Query)를 분리한다.

 

 

 

참고

https://medium.com/@su_bak/cqs-command-query-separation-pattern-이란-f701eabf8754

https://wonit.tistory.com/628

https://dundung.tistory.com/183

https://velog.io/@stella317/Spring-CQSCommand-Query-Separation