본문 바로가기
취준적인

불변성을 유지하려면 어떻게 해야할까?

by klm hyeon woo 2023. 2. 9.

불변성이란 ?

보통 불변성의 의미는 `상태를 변경하지 않는 것` 이라는 간단한 정의로 설명된다.

 

그러나 대부분 불변성에 대해 설명을 할 때, 함수 외부의 변수에 접근, 재할당을 해서는 안된다, 함수의 인자를 변경하면 안된다와 같이 상태를 변경하는 행위를 금지하는 예시 정도만 설명하고, 상태를 변경한다는 것이 정확히 무엇을 의미하는지는 자세히 설명을 하지 않는다.

(나도 가벼운 예시 정도만 알고, 레퍼런스의 블로그를 통해 자세히 알게 되었다)

 

불변성이 이야기하는 상태의 변경이라는 것은 단순한 변수의 재할당을 이야기하는 것이 아닌, 메모리에 저장된 값을 변경하는 모든 행위를 의미하며, 여기에 변수의 재할당과 같은 행위도 포함되는 것이다.

 

우리는 변수를 통해 메모리에 접근을 하고 있다.

우리는 변수를 재할당하지만 않는다면 불변이라는 개념을 지킬 수 있는걸까?

그렇지 않다, 프로그램이 변수가 가리키고 있는 메모리 공간에 있는 값을 불러오고 사용하는 방법은 그리 단순하지 않기 때문이다.

여기서 값에 의한 호출(Call By Value)참조에 의한 호출(Call By Reference)에 대한 개념이 나오기 때문에 조금 더 알아보자

 

자바스크립트에서는 string, number, boolean과 같이 원시 자료형을 사용하는 변수들은 모두 값에 의한 호출, Call By Value 방식을 사용한다.

 

값에 의한 호출 방식은 인자로 어떤 변수를 넘길 때 해당 변수가 가지고 있는 값을 그대로 복사하여 함수에게 넘겨주는 방식을 의미하기 때문에 기존에 변수가 가리키고 있는 메모리 공간에 있는 값을 함수에 인자로 넘기는 것이 아니라 그 값을 복사하여 새로운 메모리 공간에 저장하고나서 넘겨준다는 뜻이다.

 

반면 값에 의한 호출 방식을 사용하지 않는 Array, Object와 같은 객체들은 조금 상황이 다르다.

원시 자료형은 값에 의한 호출 방식을 사용하지만, Array와 Object와 같은 변수들은 참조에 의한 호출 방식을 사용한다.

 

함수의 인자로 변수를 넘길 때 값을 복사하여 새로운 공간에 저장한 후 넘겨주는 값에 의한 호출 방식과는 다르게, 참조에 의한 호출 방식은 변수가 가리키고 있는 메모리 공간의 주소를 넘기는 방식이다.

 

불변성을 지키면 어떤 점이 좋을까 ?

무분별한 상태의 변경을 막을 수 있다.

상태는 프로그램의 현재 상황을 보여주는 좋은 역할도 하지만, 여기저기서 무분별하게 이 상태를 참조하거나 변경하는 경우, 개발자 조차 현재 프로그램이 어떻게 돌아가는지 파악하기 힘든 슬픈 상황이 발생할 수도 있다.

 

그래서 개발자들은 상태를 변경하는 행위에 특정한 규칙과 제약을 정해서 무분별한 상태 변화를 최대한 피하고 이런 변화를 추적할 수 있는 상황을 선호할 수 밖에 없다.

 

무분별한 상태 변경 때문에 프로그램이 터지게 되는 가장 대표적인 상황은 바로 `전역 변수의 남용`이다. 자바스크립트에서 전역 변수의 사용을 아예 금지하는 컨벤션을 추천하는 것도 바로 이 이유이다.

 

불변성을 유지하며 순수함수를 사용한다는 것은 함수 외부의 상태에 접근하여 이미 메모리에 할당되어 있는 값을 변경하지 않는다는 의미이므로, 이렇게 예측하지 못한 상태의 변경을 방어할 수 있다.

 

상태의 변경을 추적하기가 쉽다.

일반적으로 자바스크립트의 객체의 프로퍼티나 배열의 원소를 변경해야하는 경우, 필연적으로 불변성이 깨질 수 밖에 없다.

 

애초에 배열이나 객체가 처음 나왔을 때, 어딘가에 구조화된 데이터를 저장해놓고 상태를 유지하고 변경해가며 사용하고자 하는 목적을 가지고 있었기 때문이다.

 

객체의 프로퍼티나 배열의 원소를 변경해야하는 경우 `깊은 복사`를 통해 Object.assign 또는 spread 연산자를 통해 새로운 객체 또는 배열을 생성하여 직접 변경을 하지 않고 복사본에 변경을 하는 방법을 채택한다.

 

이렇게 새로운 객체를 생성하게 되면 의도하지 않은 객체의 상태 변화도 방어할 수 있고, 상태 변화를 추적할 수 있게 된다. 

 

객체의 상태를 변화시킬 때, 상태가 변화된 객체를 새로 생성한다면 우리는 이전 상태를 가진 객체와 다음 상태를 가진 객체를 비교하여 객체의 상태가 변화되었음을 알 수 있는 것이다. 이런 원리는 현재 프론트엔드 UI 라이브러리인 리액트에서의 상태 변화를 감지하는데 사용되고 있다. 

 

리액트의 setState와 같은 메소드를 사용하여 상태를 변경했을 때, Object.is 메소드를 사용하여 이전 상태와 다음 상태를 비교하고 두 객체가 같지 않다고 평가되면 상태가 변이되었다고 판단하고 컴포넌트를 다시 렌더링한다.

 

이러한 불변성의 특징들은 참조에 의한 호출을 사용하는 자료형들의 상태 변화를 쉽게 감지할 수 있도록 만들어주기 때문에 개발자가 예상하지 못하는 방향으로 버그가 발생하는 것을 어느 정도 막을 수 있다.

레퍼런스

 

변하지 않는 상태를 유지하는 방법, 불변성(Immutable)

이번 포스팅에서는 순수 함수에 이어 함수형 프로그래밍에서 중요하게 여기는 개념인 에 대한 이야기를 해보려고 한다. 사실 순수 함수를 설명하다보면 불변성에 대한 이야기가 꼭 한번은 나오

evan-moon.github.io

 

댓글