Spring&IntelliJ

CQS(Command Query Separation)에 대해서

NandaNanda 2023. 12. 28. 23:12

참고: https://velog.io/@yena1025/CQS-Command-Query-Separation

강의도중 아래와 같은 save메서드에서 왜 반환값을 그냥 회원객체로 반환하는것이 좋지 않은지에 대한 설명이 있었다. 결론만 말하면 save의 기능은 저장의 기능이기 때문에 굳이 회원객체를 반환하여 그 객체를 수정할 수 있는 여지가 아예 없도록 CQS패턴을 적용하여 save메서드를 구현하는 게 좋다는 것이다. 아래는 CQS에 대한 소개이다.

 

CQS는 'Command Query Separation', 즉 Command와 Query를 분리하자는 개념을 말한다.

Command는 상태를 변경하는 메서드이며, Query는 상태를 반환하는 메서드를 지칭한다.

 

CQS는 패턴이다

CQS는 디자인 패턴 중에 하나이다.

디자인 패턴이란, 여러 소프트웨어를 개발하던 중에 '특정 패턴으로 개발을 하니 복잡성이 줄어들고 재사용성이 좋아지더라' 하는 것들을 모아 패턴으로 만든 것을 말한다.

즉, CQS를 사용하면 코드의 재사용성 + 유지보수성 + 가독성이 좋아질 것이라는 걸 미리 예측해볼 수 있다.

CQS의 구성과 개념

CQS는 'Command Query Separation', 즉 Command와 Query를 분리하자는 개념을 말한다.

Command는 상태를 변경하는 메서드이며, Query는 상태를 반환하는 메서드를 지칭한다.

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

Command란?

command는 객체의 상태를 변경하는 메서드로, 값을 반환하지 않는다.
자바스크립트로 예를 들면 setter 함수에 해당한다.

예시

아래 Person 객체의 set name이 command 메서드이다.
set name을 이용하여 Person 객체의 _name 상태를 변경하였다.

class Person {
  set name(n) {
    this._name = n;
  }
}
const p = new Person();
p.name = “Lisa”;
console.log(p); // Person {_name: “Lisa”}

Query란?

query는 값을 반환하는 메서드로, 객체의 상태는 변경하지 않는다.
자바스크립트로 예를 들면 getter 함수에 해당한다.

예시

아래 예시의 Person(p) 객체에 setter와 getter 둘 다 name으로 이름지어져 있어서 조금 헷갈릴 수 있지만, 사용하는 방법에서 차이가 난다.

p.name에 값을 대입해 넣으면 상태를 변경하는 setter이고,
p.name의 내용 자체를 출력하면 값을 반환하는 getter가 된다.

class Person {
  set name(n) {
    this._name = n;
  }
  get name() {
    return this._name;
  }
}
const p = new Person();

p.name = “Lisa”; => setter
console.log(p.name); // “Lisa” => getter

console.log(p); // Person {_name: “Lisa”}

CQS의 슬로건

하나의 메서드가 command이면서 동시에 query일 수는 없다

즉, 아래처럼 구현을 해서는 안 된다.

class Person {
  set name(n) {
    this._name = n;
  }
  
  get name() {
    this._name = “Dyann”; // No! (getter가 command와 query의 역할을 동시에 수행)
    return this._name;
  }
}

CQS 패턴의 장점

“읽기(조회)” 로직과 “쓰기(수정)”로직을 분리한다. 이를 통해 성능 최적화, 유지 보수에 도움이 됨은 물론이고 코드의 가독성도 높여준다.

CQS 패턴의 단점

개발을 하다보면 하나의 메소드에 불가피하게 “읽기”와 “쓰기”를 동시에 해야 하는 경우가 생긴다. 이때 CQS 패턴을 유지한다는 명목으로 오히려 간단한 코드를 복잡하게 구현해야 할 수도 있다.

왜 insert는 아이디만 반환해? 원래 함수의 목적이 save이므로.객체를 반환하는것은 부적합. update는 왜 아무 것도 반환하지 않아? 데이터 변경이 목적인 함수이므로. 왜 조회는 내부 변경이 없는 메서드여야지 좋아? 함수의 목적이 값의 반환에 있는 함수이므로. 즉, 함수를 크게 값을 반환하는 함수와 값을 변경하는 함수로 나누고 둘중 어느 하나에만 집중하라는 것이 CQS임