Jupyter의 hidden state vs marimo의 결정론적 실행
Jupyter를 오래 사용한 사람이라면 한 번쯤 이런 상황을 겪었을 겁니다. 분명히 코드를 고쳤는데 결과가 바뀌지 않거나, 노트북을 처음부터 다시 실행하면 중간에 에러가 납니다. 이 문제의 원인이 hidden state입니다.
Jupyter의 hidden state 문제
Jupyter는 REPL(Read-Eval-Print Loop) 방식으로 동작합니다. 셀을 실행하면 그 결과가 커널의 메모리에 남습니다. 셀을 삭제해도 그 셀이 만든 변수는 커널이 살아 있는 동안 메모리에 계속 존재합니다.
아래 시나리오를 따라가 봅니다.
1단계: Cell 1을 작성하고 실행합니다.
# Cell 1data = [1, 2, 3, 4, 5]mean = sum(data) / len(data)mean # 3.0
2단계: 분석 방향이 바뀌어 Cell 1을 삭제하고 새 Cell 2를 작성합니다.
# Cell 2 (Cell 1 삭제 후 새로 작성)result = mean * 2 # mean이 없어야 하는데...result # 6.0 — 이전 실행의 mean이 메모리에 남아 있어 동작함
Cell 1을 삭제했는데도 mean이 살아 있습니다. Jupyter 커널이 mean = 3.0을 메모리에 보존하고 있기 때문입니다. Cell 2는 실제로는 존재하지 않아야 할 mean에 의존하는 코드인데, 오류 없이 실행됩니다.
3단계: 이 노트북을 동료에게 넘기거나 내일 처음부터 다시 실행합니다.
NameError: name 'mean' is not defined
당연히 에러가 납니다. mean을 만들던 셀이 없으니까요. 오늘 실행할 때는 됐는데 내일 안 되는 상황, 이것이 hidden state의 전형적인 증상입니다.
왜 "hidden"인가
"숨겨진(hidden)"이라고 부르는 이유는 이 상태가 노트북 파일에 드러나지 않기 때문입니다. 파일을 열어봐도 삭제된 셀의 흔적은 없습니다. 커널 메모리 안에만 존재합니다. 코드를 읽어서는 파악할 수 없는 상태이니 "숨겨졌다"는 표현이 정확합니다.
Jupyter 사용자들이 해결책으로 쓰는 것이 "커널 재시작 후 전체 실행"입니다. 커널을 재시작하면 메모리가 초기화되고 hidden state가 사라집니다. 하지만 매번 전체를 재실행해야 하는 것은 불편하고, 재실행 과정에서 오래 걸리는 셀을 기다려야 하는 문제도 있습니다.
marimo의 접근: 셀 삭제 시 변수도 제거
marimo는 hidden state 문제를 근본적으로 다르게 처리합니다. 셀을 삭제하면 그 셀이 정의하던 변수가 메모리에서 즉시 제거됩니다. 흔적을 남기지 않습니다.
위의 시나리오를 marimo에서 따라가 봅니다.
1단계: Cell 1을 작성하고 실행합니다. mean이 정의됩니다.
# Cell 1data = [1, 2, 3, 4, 5]mean = sum(data) / len(data)mean # 3.0
2단계: Cell 1을 삭제합니다. marimo는 즉시 data와 mean을 네임스페이스에서 제거합니다.
3단계: Cell 2를 작성합니다.
# Cell 2result = mean * 2 # NameError — mean은 없음
Cell 1을 삭제하는 즉시 mean이 사라지므로, Cell 2는 바로 에러를 냅니다. 이 에러는 숨겨지지 않습니다. 지금 여기에서, 즉각적으로 알 수 있습니다.
결정론적 실행이란
"결정론적(deterministic)"이란 같은 코드에 같은 입력이면 항상 같은 결과가 나온다는 뜻입니다. marimo에서는 노트북 파일의 코드 상태가 실행 결과를 완전히 결정합니다.
- 오늘 실행한 결과와 내일 실행한 결과가 같습니다.
- 새 컴퓨터에서 실행해도 같습니다.
- 동료의 컴퓨터에서 실행해도 같습니다.
이것이 재현성(reproducibility)입니다. 연구 노트북이나 데이터 분석에서 재현성은 매우 중요합니다. marimo는 hidden state를 구조적으로 차단함으로써 재현성을 보장합니다.
Jupyter에서 marimo로 전환할 때 체감하는 차이
Jupyter에 익숙한 상태에서 marimo로 처음 옮기면, 셀을 삭제하는 순간 관련 코드가 즉시 에러를 내는 경험을 하게 됩니다. 처음에는 번거롭게 느껴질 수 있습니다. 하지만 그 에러는 지금 현재 코드가 불완전한 상태라는 정확한 신호입니다. Jupyter에서처럼 에러 없이 동작하다가 나중에 재실행할 때 터지는 상황이 발생하지 않습니다.
"실행 순서에 따라 결과가 달라지는 노트북"을 marimo에서는 만들 수 없습니다. DAG가 실행 순서를 고정하고, 셀 삭제 시 변수 제거가 hidden state를 차단합니다. 이 두 가지가 marimo에서 결정론적 실행을 가능하게 하는 핵심 메커니즘입니다.
정리
- Jupyter의 hidden state는 삭제된 셀의 변수가 커널 메모리에 잔류하는 문제입니다.
- 이로 인해 코드와 실행 결과가 일치하지 않고, 재실행 시 에러가 발생합니다.
- marimo는 셀을 삭제하면 그 셀이 정의한 변수를 즉시 제거합니다.
- 같은 코드와 입력은 항상 같은 결과를 냅니다(결정론적 실행).
- 이것이 marimo가 재현 가능한 노트북을 보장하는 방식입니다.