명령-질의 분리 원칙(command-query separation principle)은 함수를 호출할 때 본의 아니게 발생한 외부 효과로 예상치 못한 결과가 나오는 일을 방지하는 데 기초가 되는 원칙이다. 함수는 그 성격에 따라 크게 두 가지로 분류할 수 있다. 하나는 어떤 동작을 수행하는 명령(command)이고, 다른 하나는 답을 구하는 질의(query)다. 이러한 두 역할은 한데 섞으면 안 된다. 예를 들어 다음 코드를 살펴보자.
function getFirstName() {
var firstName = document.querySelector("#firstName").value;
firstName = firstName.toLowerCase();
setCookie("firstName", firstName);
if (firstName === null) {
return "";
}
return firstName;
}
var activeFirstName = getFirstName();
실전에서 사용하는 코드는 대체로 이보다 훨씬 복잡해서 외부 효과가 발생하는 부분을 찾기가 상당히 힘든데 반해 이 코드는 금방 원인을 찾을 정도로 단순하다. 그래도 예상치 못한 외부 효과가 어떤 결과를 초래하는지에 대해 개략적으로 이해하기 위한 예제로는 충분하다.
함수 이름을 보면 사람 이름을 리턴한다는 것을 알 수 있다. 그런데 정작 이 함수에서 가장 먼저 하는 일은 이름을 소문자로 변환하는 것이다. 함수 이름은 질문에 답하는 질의형 함수인 것처럼 지었지만, 실제로 하는 일는 명령형 함수처럼 데이터의 상태를 변환하고 있다. 이는 함수 이름에 명확히 드러나지 않은 외부 효과에 해당한다.
더 심각한 부분은 소문자로 변환한 이름을 사용자에게 물어보지도 않고 쿠키로 설정하는 것인데, 자칫하면 기존에 사용하던 다른 값을 덮어 쓸 위험이 있다. 질의형 함수는 절대로 데이터를 덮어 쓰는 작업을 수행해선 안 된다.
질의형 함수를 작성할 때는 요청한 값을 리턴하기만 하고, 데이터에 상태를 바꾸는 일은 하지 않는다. 반대로 데이터의 상태를 변경하는 함수는 값을 리턴하는 일도 하지 말아야 한다. 코드를 최대한 명확하게 작성하려면 함수에서 값을 리턴하는 작업과 데이터의 상태를 변경하는 작업을 한 함수에서 동시에 처리해서는 안 된다. 이러한 원칙에 따라 코드를 다음과 같이 개선할 수 있다.
function getFirstName() {
var firstName = document.querySelector("#firstName").value;
if (firstName === null) {
return "";
}
return firstName;
}
setCookie("firstName", getFirstName().toLowerCase());
예제 코드가 굉장히 간단하지만 명령-질의 분리 원칙을 따라 코드를 작성하면 수행할 작업을 명확히 드러내고 에러 발생 가능성도 줄일 수 있다는 것을 이해하는 데는 충분하다. 함수와 코드 베이스가 커질수록 이러한 분리 원칙은 더욱 중요하다. 사용할 함수가 무슨 일을 하는지 알아내기 위해 매번 함수의 정의 부분을 뒤져야 한다면 그리 효율적인 방식은 아닐 것이다.
'Programming > Thoery' 카테고리의 다른 글
매개변수(parameter)과 인자(argument)의 구분 (0) | 2023.03.16 |
---|