# 가변 변수에 대한 John Carmack의 견해

> Clean Markdown view of GeekNews topic #24067. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24067](https://news.hada.io/topic?id=24067)
- GeekNews Markdown: [https://news.hada.io/topic/24067.md](https://news.hada.io/topic/24067.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-01T09:41:00+09:00
- Updated: 2025-11-01T09:41:00+09:00
- Original source: [twitter.com/id_aa_carmack](https://twitter.com/id_aa_carmack/status/1983593511703474196)
- Points: 3
- Comments: 1

## Topic Body

- **John Carmack**이 **가변 변수(mutable variable)** 사용에 대한 개인적 견해를 공유  
- **파이썬을 사용하면서 ‘단일 할당(single assignment)’ 원칙을 소홀히 하게 되었다**며, 이를 스스로 경계해야 한다고 언급  
- **루프의 반복 계산을 제외하고는 변수 재할당이나 갱신을 피해야 함**을 강조  
- 중간 계산 단계들이 모두 남아 있으면 **디버깅 시 도움이 되며**, 코드 블록을 이동할 때 **의도치 않게 이전 값이 사용되는 문제를 방지**할 수 있음  
- **C/C++에서는 거의 모든 변수를 초기화 시점에 const로 선언하는 것이 좋은 습관**이라고 설명  
- 마지막으로 “**mutable이 키워드였으면 좋겠다**”라며, 불변성이 기본값이 되길 바란다고 강조

## Comments



### Comment 45730

- Author: neo
- Created: 2025-11-01T09:41:00+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45767725) 
- 2년간 **Clojure**를 사용한 후, 불변성이 주는 **명료함**을 다른 개발자에게 설명하기가 정말 어렵다는 걸 느꼈음  
  상태 변화를 통해 효과를 일으키는 사고방식에 익숙한 사람들은 직접 경험해보기 전에는 이해하기 힘듦
  - 변수 변경은 암묵적인 **순서 의존성**을 만들어냄  
    예를 들어 `x = 7; x = x + 3; x = x / 2`처럼 작성하면 순서를 바꿔도 오류는 없지만 결과가 달라짐  
    반면 `x1`, `x2`처럼 새 변수를 쓰면 잘못된 순서에서 오류가 발생해 문제를 명확히 드러냄  
    결국 단일 할당(single assignment)은 이런 의존성을 **명시적으로 표현**하는 방식임
  - 나도 **Scheme**에서 비슷한 경험을 했음  
    함수형 언어를 써본 적 없는 동료들에게 함수 중심의 사고가 얼마나 **테스트하기 쉽고 깔끔한지** 설명해도 잘 와닿지 않았음  
    Python은 함수형 스타일을 읽기 좋게 쓰기 어렵고, JS가 오히려 더 낫다고 느낌  
    결국 **호기심 많은 개발자**만이 Clojure 같은 언어를 시도하게 됨
  - 불변 데이터와 **순수 함수**를 기본으로 하면, 함수는 완전히 **블랙박스**처럼 다룰 수 있음  
    함수는 외부 상태를 몰라도 되고, 외부도 함수 내부를 몰라도 됨  
    프로그램 전체 상태를 몰라도 특정 함수만 독립적으로 테스트하거나 디버깅할 수 있음
  - 불변성과 가변성을 단순히 대립시키는 건 **복잡성을 회피**하는 것임  
    Haskell 커뮤니티가 결국은 타입 시스템 안에서 가변성을 재발명하려는 걸 보면 흥미로움  
    핵심은 부작용을 최소한의 비용으로 **통제**하는 것임
  - Clojure는 내가 배운 언어 중 가장 **영향력 있는 언어**였음  
    Haskell은 타입 시스템 때문에 진입 장벽이 높았고, F#은 너무 **타협적**이라 C# 문법으로 코딩하게 됨  
    Clojure의 **homoiconicity**와 강력한 데이터 구조 덕분에 ‘값으로 일한다’는 개념이 처음으로 명확히 와닿았음  
    직업적으로 쓰진 않겠지만, 함수형 언어나 Lisp 경험이 없는 사람에게는 꼭 추천하고 싶음

- 변수는 기본적으로 불변이고 모든 것이 **표현식(expression)** 이었으면 좋겠음  
  하지만 현실은 Clojure 개발자로서 **Python의 침공**에 시달리는 중임
  - 나도 Python 개발자지만 개인 프로젝트에서만 Clojure를 써봄  
    이제는 **TypeScript의 침공**에 시달리고 있어서 공감됨
  - **Rust**를 배우고 나서, 언어가 순수 함수형이 아니어도 모든 것이 표현식일 수 있다는 걸 깨달았음  
    이 방식은 **변경 범위를 제한**하는 데 정말 유용함
  - Clojure는 언제나 Python보다 **빠름**, 그건 위안이 됨
  - 당신은 단순히 Clojure를 사용하는 사람이지, “Clojure 프로그래머”로 자신을 규정할 필요는 없음  
    언어 간의 **부족 전쟁**에 휘말릴 필요 없음  
    생산성 향상 시대에는 경계가 무의미함  
    [Don’t Call Yourself a Programmer](https://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-programmer/) 글을 추천함

- 변수 재할당은 최소화하려 하지만, 종종 **변수 섀도잉**을 사용함  
  `result = result.process()` 같은 패턴이 간결해서 선호함
  - 추상적인 예시라 그렇겠지만, 대부분의 경우엔 각 단계마다 **명확한 이름**을 붙일 수 있음
  - 이런 패턴은 보안 버그를 유발할 수 있음  
    예를 들어 `process()`가 **검증 함수**라면, 어떤 시점에 처리된 값인지 불분명해질 수 있음  
    따라서 이름으로 상태를 명확히 구분하는 게 좋음
  - 함수형 스타일에서는 이런 중간 변수 없이 **함수 체이닝**으로 해결 가능함  
    예: `result = x |> foo |> bar |> baz` 또는 `(-> x foo bar baz)`
  - “`result.process()`라니, 도대체 어떤 result고 어떤 process인가?”  
    나중에 코드를 읽는 사람은 혼란스러움
  - 이미 결과(result)인데 다시 처리(process)한다는 건 **논리적으로 어색함**

- “변수(variable)”라는 용어 자체가 늘 마음에 걸림  
  불변인데 왜 variable이라 부르는가?
  - 변수는 실행 중에는 변하지 않지만, **호출마다 값이 달라질 수 있음**  
    Rust에서는 `mut`로 명시해야만 변경 가능함  
    반면 C에서는 상수를 만들려면 전처리기를 써야 해서 혼란스러움
  - 함수의 인자 `x`는 호출마다 다른 값을 받으므로, 그 자체로 **변하는 값**임  
    재할당이 없어도 변수라 부를 수 있음
  - 수학에서도 변수는 특정 객체가 아닌 **임의의 값**을 가리키는 기호임  
    프로그래밍이 이 개념을 그대로 가져온 것임
  - 결국 변수는 실행마다 값이 달라질 수 있기 때문에 variable임  
    상수(constant)는 모든 실행에서 동일한 값을 가짐  
    [Variable (mathematics)](https://en.wikipedia.org/wiki/Variable_(mathematics)) 참고
  - ‘변수’가 시간에 따라 변한다기보다 **맥락에 따라 달라진다**는 의미로 쓰이는 것임

- IDE가 변수의 **변경 여부를 시각적으로 표시**해주면 좋겠음  
  예를 들어, 변경된 변수는 살짝 표시만 해주는 식으로
  - IntelliJ에서는 재할당된 변수에 밑줄이 생기고, 마우스를 올리면 ‘Reassigned local variable’이라는 힌트를 보여줌  
    가능한 한 `final`을 많이 쓰면 코드가 **읽기 쉽고 유지보수하기 쉬움**
  - 하지만 자동 추론보다는 **명시적 opt-in**이 낫다고 생각함  
    IDE가 경고를 주고, 정말 필요한 경우에만 변경을 허용하는 게 좋음  
    Rich Hickey의 **set vs list** 이야기처럼, 의미를 명확히 표현하는 구조를 선택해야 함
  - **Swift**는 컴파일러가 변수의 변경 여부를 감지해, 불필요한 변경이면 상수로 바꾸라고 제안함
  - JetBrains IDE에는 변수의 **읽기/쓰기 위치를 찾는 기능**이 이미 있음
  - 이런 기능을 하는 **린터(linter)** 를 만든다면 이름은 “mutalator”가 어울릴 듯함

- 예전에 **스레드 안전성**을 위해 불변성을 엄격히 적용한 프로젝트를 했음  
  덕분에 코드가 읽기 쉬워지고, 무엇이 바뀔 수 있는지 추적하기 쉬워졌음  
  이후로 불변성의 **열렬한 팬**이 됨
  - 그렇다면 **Rust**를 꼭 써보라고 권하고 싶음

- 대규모 **Haskell** 코드베이스에서 일하다가 다시 C로 돌아오니, 불변성이 기본이었으면 좋겠다는 생각이 듦  
  `const`로는 부족함
  - C에서는 사실 직접적인 변경이 아니라 **값 재할당**만 가능함  
    변경하려면 포인터를 써야 하고, C++은 함수 호출만으로도 인자를 바꿀 수 있어서 불투명함
  - Rust의 기본값이 충분히 **안전한 불변성**을 제공하는지 궁금함

- “거의 모든 변수를 const로 선언하는 게 좋다”는 말에 공감함  
  **Rust**가 언급될 만함
  - 관련해서 [John Carmack의 트윗](https://x.com/ID_AA_Carmack/status/1094419108781789184)을 참고할 만함
  - 그리고 **Zig**도 같은 철학을 따름

- 불변이 기본이고, 특정 블록 안에서만 **mutable**을 허용하는 문법을 상상해봄  
  예를 들어 Python의 `with` 블록처럼  
  ```python
  with mutable(x, items):
      x = 3
      items.append(4)
  ```
  블록을 벗어나면 다시 불변으로 돌아가는 식임
  - 이건 사실상 **mutable borrow** 개념임  
    Rust의 **borrow checker**를 보면 이 개념이 얼마나 복잡한지 알 수 있음
  - borrow 체크가 없다면, 블록 밖에서도 **참조가 남아** 변경될 수 있음

- “**State is the enemy**”라는 말이 있음  
  상태가 늘어날수록 테스트해야 할 조건이 기하급수적으로 늘어남  
  불변성은 이런 **상태 폭발**을 막는 방법임
  - 그래서 함수형 프로그래머들은 **Church와 state의 분리**를 믿음  
    [Separation of Church and State](https://wiki.c2.com/?SeparationOfChurchAndState)
