Intro

함수는 시스템의 상태를 바꾸는지에 따라서 크게 두 가지로 나뉜다. 1) Command 2) Query. 이 두 가지 분류법에 대해서 하나의 함수가 두 가지 경우를 모두 담당하는 것은 좋지 않다.


Command vs. Query

  • Query

    주어진 쿼리에 대한 결과값을 반환하고 시스템의 상태를 변화시키지는 않는다.

    다른 값을 바꾸지 않고 오직 질문에만 대답한다.

    부작용에서 자유롭다. (read-only)

    list = [1, 2, 3, 4, 5];
    
    print(max(1));
    
    5
  • Command

    값을 반환하지 않아도 시스템의 상태를 변화시킨다. (영구적)

    부작용이 생길 여기자 있다. (mutator, modifier)

    list = [1, 2, 3, 4, 5];
    list.reverse();
    
    print(list)
    
    [5, 4, 3, 2, 1]

이렇게 함수를 두 가지로 나누는 것은 유용하다. 현재 사용하는 함수가 상태를 바꾸지 않는 query 라면 신뢰를 가지고 사용할 수 있다. 하지만 상태를 바꾸는 command라면 함수간 순서에 주의를 기울이고 부작용이 생길 여지를 인지하고 있어야 한다.


CQS - Command Query Separation

Betrand Meyer라는 프랑스 학자는 하나의 함수가 command 이거나 query 이어야 한다고 주장한다. 이러한 프로그램 원칙을 CQS라고 하며 한 함수에서는 둘은 분명히 구분해야 한다고 말했다.

하지만 스택의 pop() 연산 같은 경우는 위 두가지를 모두 담당하기도 한다. 이러한 예외 상황은 융통성 있게 허용하는 것이 전반적으로 더 효율적일 수 있다.

위 개념은 현재 진행중인 프로젝트에서 다음과 같은 코드에 대한 크루의 코드리뷰로 접하게 되었다.

Post newPost = post.update(updatedContent);

위와 같은 경우 CQS를 준수하지 않은 것이므로 둘 중 하나를 담당하도록 구현로직을 바꾸고 필요하면 재조회하는 방향으로 리팩토링 했다.



[참고자료]