---
title: "불변성은 값의 변화를 금지해 어떤 문제를 줄일까"
author: "Lee"
published_at: "2026-10-24T12:44:03.741Z"
updated_at: "2026-09-30T10:13:35.414Z"
tags: ["컴퓨터공학","프로그래밍언어"]
canonical_url: "https://ariser.io/@writer_a1cd615ab19e/%EB%B6%88%EB%B3%80%EC%84%B1%EC%9D%80-%EA%B0%92%EC%9D%98-%EB%B3%80%ED%99%94%EB%A5%BC-%EA%B8%88%EC%A7%80%ED%95%B4-%EC%96%B4%EB%96%A4-%EB%AC%B8%EC%A0%9C%EB%A5%BC-%EC%A4%84%EC%9D%BC%EA%B9%8C"
ai_assisted: false
---

# 불변성은 값의 변화를 금지해 어떤 문제를 줄일까

[원문](https://ariser.io/@writer_a1cd615ab19e/%EB%B6%88%EB%B3%80%EC%84%B1%EC%9D%80-%EA%B0%92%EC%9D%98-%EB%B3%80%ED%99%94%EB%A5%BC-%EA%B8%88%EC%A7%80%ED%95%B4-%EC%96%B4%EB%96%A4-%EB%AC%B8%EC%A0%9C%EB%A5%BC-%EC%A4%84%EC%9D%BC%EA%B9%8C)

어떤 값을 전달했는데 다른 코드가 그 값을 바꾸면 호출자는 이전 가정을 잃을 수 있다. 불변성은 객체가 만들어진 뒤 관찰 가능한 상태가 바뀌지 않는 성질이다. 여러 위치에서 같은 값을 참조해도 누군가의 갱신 때문에 뜻이 달라지지 않아 추론하기 쉽다. 그러나 변수에 다시 대입할 수 없는 것과 변수가 가리키는 객체를 바꿀 수 없는 것은 별개의 문제다.

![이전 루트와 새 루트가 바뀌지 않은 가지를 공유하고, 변경한 잎은 7과 9의 별도 노드로 유지되는 구조](/api/v1/media/5fb8aa7d-f099-4446-a058-003f8495b191)

*불변 자료구조는 이전 값을 유지하면서 새 버전을 만들고 변하지 않은 부분을 공유할 수 있다.*

## 이름을 고정하는 것과 객체를 고정하는 것

일부 언어의 상수 바인딩은 변수 이름이 다른 객체를 가리키게 만드는 재대입을 금지한다. 그래도 그 객체의 필드나 배열 원소는 바뀔 수 있다. 따라서 `const` 같은 키워드가 보인다고 전체 자료구조가 깊이 불변이라고 결론 낼 수 없다. 언어가 어떤 수준의 변경을 금지하는지 확인해야 한다. 참조 자체, 객체의 직접 필드, 연결된 모든 객체는 서로 다른 범위다.

Python에서 튜플은 원소 참조의 나열을 바꿀 수 없는 객체지만 튜플 안에 들어 있는 리스트는 수정될 수 있다. `t = ([1],)`을 만든 뒤 `t[0].append(2)`를 하면 안쪽 리스트가 바뀐다. [Python 데이터 모델](https://docs.python.org/3/reference/datamodel.html)은 불변 컨테이너의 불변성과 내부에 참조된 가변 객체의 상태를 구분한다. 얕은 불변성이 깊은 불변성까지 뜻하지 않는 사례다.

## 변경 대신 새로운 버전을 만든다

불변 리스트에 값을 추가한다는 API는 기존 리스트를 수정하기보다 새 결과를 반환할 수 있다. 새 값을 사용하려면 반환된 참조를 이어 받아야 한다. 매번 모든 데이터를 복사하면 비용이 크기 때문에 지속적 자료구조는 바뀌지 않은 부분을 공유하기도 한다. 이전 버전에 접근할 수 있게 유지하면서 새 버전을 만드는 구조다. 여기서 지속적이라는 말은 반드시 디스크에 저장한다는 뜻은 아니다.

트리의 잎 하나를 바꾸는 경우를 생각해 보자. 기존 루트에서 그 잎까지 이어지는 경로의 노드만 새로 만들고, 영향 없는 가지는 이전 버전과 공유할 수 있다. 균형 잡힌 트리라면 경로 길이는 대체로 전체 원소 수보다 훨씬 짧다. 공유하는 노드가 불변이어야 이전 버전의 의미도 보존된다. 단순히 얕은 복사를 했다고 이런 조건이 자동으로 충족되지는 않는다.

## 공유 상태에 대한 질문이 줄어든다

깊이 불변인 값을 여러 스레드가 읽는다면 누가 동시에 그 값을 수정할지 고민할 필요가 줄어든다. 스냅샷, 실행 취소 기록, 캐시 키, 설정 데이터에 적합한 이유다. 다만 불변 객체를 전달하는 참조를 안전하게 공개하거나 현재 버전의 포인터를 갱신하는 일은 별도 동기화가 필요할 수 있다. 불변성 하나가 프로그램 전체의 모든 경쟁 상태를 없애지는 않는다.

해시 기반 자료구조에서도 내용이 안정적이라는 점이 중요하다. 키를 넣은 뒤 해시나 비교 기준이 바뀌면 찾기 어려워질 수 있다. 언어는 이를 막기 위해 일부 가변 객체를 키로 허용하지 않기도 한다. 다만 불변이라고 무조건 해시가 가능하거나 해시 값이 서로 다른 것은 아니다. 내부 원소의 성질과 언어의 해시 계약을 함께 확인해야 한다.

불변성에는 새 객체 생성과 버전 보관, 메모리 회수의 비용이 있다. 대규모 배열을 한 번만 처리하는 작업에서는 제한된 범위의 가변 갱신이 더 효율적일 수 있다. 반대로 상태 공유와 변경 이력이 복잡한 작업에서는 추론과 복구의 이점이 크다. 값을 얼마나 자주 바꾸고 누가 공유하며 이전 버전이 필요한지 살펴보면, 불변성을 적용할 위치를 구체적으로 결정할 수 있다.

### 참고 자료

- [Python Language Reference — Data model](https://docs.python.org/3/reference/datamodel.html)
