상태
state
· 마지막 업데이트: 2026-07-24 · 30 min read
프로그래밍에서 말하는 상태(state)란 무엇인가?
시스템은 이전 이벤트나 사용자 상호작용을 기억하도록 설계된 경우 스테이트풀(stateful), 즉 상태 저장으로 설명된다. 기억된 정보를 시스템의 상태(state)라고 부른다.state 어떻게 계산기·제어공학·논리회로·오토마톤 이론을 거치며 기술 용어가 되었으며 이후 프로그래밍 언어의 변수와 객체, 웹 애플리케이션의 세션과 UI 모델까지 확장되었을까?
state란 무엇인가
일반 영어에서 state는 어떤 존재가 놓인 방식이나 형편, 즉 “존재의 양식 또는 조건(mode or condition of being)”을 뜻한다. Merriam-Webster의 state 정의도 이 의미를 첫 뜻으로 든다.
물이 액체 상태인지 기체 상태인지, 문이 열림 상태인지 닫힘 상태인지 말할 때의 상태가 여기에 해당한다.
컴퓨팅에서 상태는 더 좁게 다음처럼 쓸 수 있다.
시스템의 상태는 특정 시점에 시스템이 보유한 정보 중, 이후 입력이나 사건에 대한 행동과 결과를 바꿀 수 있는 정보의 집합이다.
예를 들자면 다음과 같다.
다음 C 코드에서 failedAttempts가 로그인 기능의 상태다. LoginState state = {0};로 초기화한 뒤 같은 recordLoginFailure 호출을 반복하면, 이전 실패 횟수에 따라 결과가 달라진다.
잠금 여부는 failedAttempts >= maxLoginFailures로 계산할 수 있으므로 따로 저장하지 않는다.
#include <stdbool.h>
#include <stddef.h>
enum {
maxLoginFailures = 5,
};
typedef struct {
unsigned int failedAttempts;
} LoginState;
LoginState state = {0};
bool recordLoginFailure(LoginState *state) {
if ((state == NULL) ||
(state->failedAttempts >= maxLoginFailures)) {
return false;
}
state->failedAttempts++;
return state->failedAttempts < maxLoginFailures;
}처음 네 번의 실패는 true를 반환하지만, 다섯 번째 실패 뒤에는 계정이 잠겨 false를 반환한다. 이후 호출도 실패 횟수를 더 늘리지 않고 false를 반환한다.
이 차이를 만드는 것은 무엇일까? 현재 호출의 입력만이 아니라, 이전 실패가 남긴 상태다.
엘리베이터의 현재 층·이동 방향·문이 열려 있는지는 다음 버튼 입력에 대한 반응을 바꾼다. 로그인 여부·권한·장바구니·결제 승인 여부도 다음 요청을 허용할지 결정한다. 이런 정보들이 상태다.
상태는 변수 하나와 동의어가 아니며, 하나의 논리적 상태는 여러 변수·테이블·메시지에 나뉘어 있을 수 있고, 반대로 저장된 모든 데이터가 상태인 것도 아니다. 같은 값도 시스템 경계와 쓰임에 따라 단순 입력·기록일 수도, 이후 행동을 결정하는 상태일 수도 있다.
이 글에서 말하고자 하는 “상태”는 값의 저장 위치가 아니라, 시간에 따라 달라지고 미래의 행동에 영향을 주는 정보라는 역할을 가리킨다.
이 말을 쓰는 이유는 같은 현재 입력이라도 과거에 무엇이 있었는지에 따라 시스템이 다르게 행동하는 상황을 설명하기 위해서라고 할 수 있다.상태는 흔히 그 과거를 매번 다시 읽지 않고 현재 보존해 둔 요약이다.
그렇지만은 현재 시각·외부 환경·구성·센서 값처럼 과거 사건의 흔적으로만 볼 수 없는 정보도 시스템 경계에 따라 상태가 될 수 있다.
따라서 “state라는 말을 언제 처음 썼는가?”라는 질문에는 어떤 용례에 따라서 어떻게 언제 사용되었는가?를 추적해야한다.
기계의 상태: 계산을 계속하기 위해 현재 무엇을 기억해야 하는가?
상태기계의 상태: 입력에 따라 다음 행동이 달라지는 유한한 내부 모드
프로그램의 상태: 변수·메모리·환경에 저장되어 다음 실행 결과에 영향을 주는 정보
의미론의 상태: 프로그램 실행 전후를 비교하기 위한 추상적인 저장소의 스냅샷
애플리케이션 상태: 사용자·세션·데이터베이스·브라우저가 나누어 보유하는 현재 정보
이 문서의 결론을 미리 선 요약하자면 다음과 같다.
상태는 주어진 시스템 경계에서 미래의 행동을 결정하는 데 필요한 현재 정보이며, 흔히 과거 입력과 사건이 남긴 영향을 압축한 요약으로 볼 수 있다.
상태가 왜 필요했는가
간단하게 현재의 입력만 보고 출력하는 장치를 생각해보자.
출력 = f(현재 입력)이런 장치를 조합논리(combinational logic)라고 한다. 덧셈기나 논리 게이트처럼 현재 입력만으로 결과를 계산하는데, 하지만 계산기·전화 교환기·엘리베이터·통신 프로토콜은 현재 입력만으로 동작을 결정할 수 없다.
이전에 어떤 숫자를 입력했는가
이미 동전을 넣었는가
통화 연결을 기다리는 중인가
패킷의 몇 번째 조각까지 받았는가
파일을 열었고 아직 닫지 않았는가
이전 사건을 전부 다시 읽지 않으려면, 앞으로 필요한 정보만 현재 위치에 남겨야 한다. 이것이야말로 상태다.
다음 상태 = δ(현재 상태, 입력)
출력 = λ(현재 상태, 입력)상태는 시간의 흐름을 표현하는 장치이며, 과거를 압축한 정보로 쓰이는 경우가 많다.
미래 행동에 필요한 요약이 유한한 개수의 등가 상태 중 하나로 표현될 수 있다면 유한 상태기계로 모델링할 수 있다. 반대로 과거의 세부 내용이나 정수 누적값처럼 가능한 값이 계속 늘어나는 정보가 필요하면 상태 공간도 무한해질 수 있다.
표현 자체가 짧다는 것과 가능한 상태의 개수가 유한하다는 것은 같은 말이 아니다.
이벤트 소싱처럼 과거 사건 전체를 보존하는 설계도 있다.
개인적인 메모: 프로그래밍에서 '상태(State)를 점유한다'는 것은 단순히 메모리의 특정 주소에 값을 기록하는 행위가 아닌 것이다. 이는 "시스템이 미래에 도달할 수 있는 상태 공간(State Space)의 자유도를 비가역적으로 축소하는 과정"이다.
컴퓨터 과학이 점점 발전해나감에 따라 이러한 기본적 최초의 의미들이 퇴색되어 가는것을 안타깝게 느낀다.
1936년: 튜링의 state of mind와 기계의 configuration
앨런 튜링의 1936년 제출 논문 On Computable Numbers, with an Application to the Entscheidungsproblem은 1937년에 출판되었으며, 오늘날의 “튜링 기계”를 정의한 출발점이다.1
튜링은 계산을 수행하는 사람의 행동이 현재 보고 있는 기호와 현재의 마음 상태(state of mind)에 의해 결정된다고 설명했으나, 이후 이 구조를 기계의 m-configuration으로 옮겼다. 여기서 m-configuration은 기계의 내부 제어 상태에 가깝다.
한 순간의 전체 계산 상황(configuration)은 그 내부 상태뿐 아니라 테이프 내용과 헤드의 위치까지 포함한다.
(여기서 테이프는 한때 사용되었던 저장 장치로써의 테이프가 아니라, 사람이 종이위에 계산하는 과정을 단순화한 추상적 작업 공간이다. 무한히 확장 가능한 선형 공간이라는 의미로 필자는 이해하고 있다)
여기서 구분할 지점은 무엇인가?
튜링은 오늘날 교과서에 나오는
state machine이라는 말을 처음 선언한 것이 아니다.그러나 “한 단계의 행동은 현재 입력과 내부 상태에 의해 결정된다”는 계산 모델을 명확하게 제시했다.
오늘날 상태기계에서 말하는 상태와 전체 실행 스냅샷(configuration)을 구분하는 생각도 이 계보에서 나왔다.
혹자는 상태에 대해서 튜링의 공헌에 대해 말하길, 상태라는 이름을 발명한 데 있다기보다, 계산을 현재의 내부 조건과 전이 규칙으로 설명할 수 있다는 틀을 만든 데 있다고들 말한다.
1938년: 스위칭 회로가 논리식으로 표현되다
클로드 섀넌은 1938년 논문 A Symbolic Analysis of Relay and Switching Circuits에서 릴레이·스위치 회로의 동작을 불 대수로 분석했다.2
이 논문은 릴레이·스위칭 회로를 불 대수로 분석하고 합성하는 방법을 보여주었다. 따라서 조합논리와 디지털 회로 설계의 중요한 전사(前史)지만, 오늘날의 순차기계 상태를 직접 정식화한 논문으로 읽으면 안되는 것이, 순차회로의 상태와 전이 모델은 이후 오토마톤 및 Huffman, Mealy, Moore 등의 연구를 거치며 정리되었다.
순차 시스템을 만들려면 다음 두 층을 구분해야 한다.
조합 논리: 현재 입력을 계산
기억 요소: 이전 계산의 결과를 보존상태는 기억 요소에 저장되어 이후의 행동을 결정하는 정보를 추상화한 것이다. 플립플롭·릴레이·레지스터·메모리 셀은 그 상태를 물리적으로 부호화하고 보존하며, 소프트웨어에서는 변수, 힙, 파일, 데이터베이스, 세션 저장소가 그 역할을 한다.
1950년대 중반: Huffman·Mealy·Moore를 거쳐 순차기계 모델이 정리되다
오늘날의 “상태기계”라는 표현과 모델이 널리 정리된 시점은 1950년대 중반이다. 다만 그 이전에도 오토마톤과 순차회로에 관한 연구가 있었고, Huffman·Mealy·Moore는 상태기계를 발명했다기보다 순차회로와 출력 모델을 표준적인 형태로 정리하고 널리 퍼뜨린 인물로 보는 편이 정확할 것이다.
1954년: Huffman의 순차 스위칭 회로 합성
David A. Huffman은 1954년 The Synthesis of Sequential Switching Circuits에서 메모리를 가진 순차회로의 요구사항을 조합회로의 요구사항으로 환원하는 절차를 제시했다. 이 과정에서 순차회로를 정확히 기술하는 flow table과, 중복 요구사항을 찾고 줄이는 방법을 다뤘다.3
Huffman의 작업은 추상적인 상태표를 실제 스위칭 회로로 옮기는 연결 고리였다. 따라서 Mealy와 Moore 직전의 계보에서 상태 할당·축소·회로 합성을 체계적으로 다룬 중요한 단계다.
1955년: Mealy의 순차회로 모델
George H. Mealy는 1955년 A Method for Synthesizing Sequential Circuits를 발표했다. 논문에는 순차회로의 모델, 상태도(state diagram), 상태 축소와 전이 규칙이 등장한다.4
Mealy 모델에서는 출력이 현재 상태와 현재 입력에 의해 결정된다.
다음 상태 = δ(현재 상태, 입력)
출력 = λ(현재 상태, 입력)1956년: Moore의 유한 순차기계
Edward F. Moore는 Automata Studies에 실린 Gedanken-Experiments on Sequential Machines에서 유한한 수의 상태·입력 기호·출력 기호를 가진 순차기계를 다루는데, Moore 모델에서도 다음 상태는 현재 상태와 현재 입력에 의해 결정되지만, 출력은 현재 상태에만 의해 결정된다..5
다음 상태 = δ(현재 상태, 입력)
출력 = λ(현재 상태)(Mealy 모델과 Moore 모델의 각 차이점은 즉 상태 전이 방식은 동일하고, 출력 함수만 다르다. 처음보면 같다고 착각할 수 있다)
Mealy와 Moore는 출력 함수의 의존성이 서로 다른 두 표준적 순차기계 모델이다. Mealy 모델의 출력은 현재 상태와 입력에, Moore 모델의 출력은 현재 상태에만 의존한다. 적절한 상태 분할과 출력 시점 규약을 두면 두 모델을 서로 변환할 수 있지만, 초기 출력이나 출력열의 시간 정렬까지 항상 그대로 일치하는 것은 아니다.
|이 시기를 지나면서 state는 단순한 “현재 상황”이 아니라, 입력과 전이 규칙을 가진 수학적 기계의 내부 위치라는 뜻을 얻었다.
다만 “state machine이라는 표현의 최초 사용자가 Mealy다” 또는 “Moore가 state를 발명했다”고 단정할 수 없는 것이고, 관련 개념은 그 이전의 논리회로·오토마톤 연구와 이어져 있었고, Mealy와 Moore의 논문은 그 개념을 표준적인 모델로 정리하고 널리 퍼뜨린 중요한 문헌이라고 보는 것이 옳다
개인적인 메모:이것 이전에도 언급이 있다고하는데, 내가 찾지 못하였다. 추후에 한 번 다시 찾아봐야할 것이다.
1950년대~1960년대 초: 상태가 고급언어의 변수와 대입문으로 표현되다
하드웨어에서 상태가 기억 회로였다면, 고급 프로그래밍 언어에서는 변수와 대입문이 상태를 표현하는 기본 도구가 되었다. ALGOL 60은 이 흐름을 언어 명세에서 명확하게 보여주는 사례다.
ALGOL 60 보고서는 변수를 하나의 값을 가리키는 지정(designation)으로 설명하고, 대입문에 의해 그 값이 변경될 수 있다고 명시한다. own 변수는 블록을 다시 들어갈 때 이전 값을 유지하는 변수로 정의된다.6
x := x + 1이 문장은 단순히 숫자를 계산하는 식이 아니지만, 실행 전의 저장소가 x = 3인지 x = 4인지에 따라 실행 후 상태가 달라진다.
σ = { x ↦ 3 }
x := x + 1
σ' = { x ↦ 4 }여기서 σ와 σ'는 ALGOL 보고서의 원래 표기가 아니라, 이를 설명하기 위해 쓴 현대적인 프로그램 의미론의 저장 상태(store state) 표기이다.
프로그램은 입력을 받아 출력만 만드는 것이 아니라, 저장소를 한 상태에서 다른 상태로 바꾸는 과정이 되는 것이다.
Lisp는 다른 방향을 보여주었다
John McCarthy의 1960년 Lisp 논문은 함수 적용과 재귀적 기호식 계산을 중심 표현으로 부각하였다.7
이 흐름은 “모든 계산을 명령어와 대입의 연속으로 표현해야 하는가?”라는 질문을 후세대에 남겼다.
그러나 초기 Lisp 자체는 순수 함수형 언어가 아니었다. LISP 1.5 Programmer's Manual에는 PROG, 변수, 저장 공간, SET, SETQ 같은 명령적 요소가 등장한다.8
중요한 변화는 상태를 부정한 것이 아니라, 다음 두 계산 스타일을 분리해 생각하게 만든 것이다.
명령형 계산: 저장 상태를 직접 바꾼다
함수형 계산: 값과 함수를 조합하고, 상태 변화는 경계에 둔다이후의 함수형 프로그래밍 전통은 컴퓨터의 물리적 상태를 없애기보다, 상태 변화를 명시적인 인자·반환값과 효과 타입·모나드 같은 경계로 드러내거나 제한하는 방향으로 발전하였다.
액터 모델은 함수형 프로그래밍의 하위 개념이라기보다, 변경 가능한 상태를 각 액터 안에 격리하고 메시지로만 영향을 주고받도록 한 동시성 모델이다. 외부 저장소 역시 상태의 소유자와 수명을 시스템 경계 밖에서 명시하게 한다.
1960년: 제어공학의 상태공간 표현
제어공학에서도 시스템의 현재 상태와 입력으로 다음 상태와 출력을 계산하는 상태공간 표현이 발전했다. Rudolf E. Kalman의 1960년 논문은 동적 시스템 분석에 state-transition 방법을 사용해 필터링과 예측 문제를 다뤘다.9
이산 시간의 선형 상태공간 모델은 보통 다음처럼 쓴다.
xₜ₊₁ = Aₜxₜ + Bₜuₜ
yₜ = Cₜxₜ여기서 x는 상태 벡터, u는 외부 입력, y는 관측 또는 출력이다.
이 표기는 “현재 상태와 입력이 미래 행동을 결정한다”는 관점을 제어공학의 언어로 정리한 사례이다.
1960년대 후반~1970년대: 상태가 프로그램 의미론의 대상이 되다
변수와 대입문이 실제 언어 기능으로 자리 잡은 뒤, 프로그램이 실행되면서 저장 상태를 바꾼다는 사실을 어떻게 수학적으로 설명하고 증명할 것인가에 대한 질문이 생겼다.
Robert Floyd의 1967년 Assigning Meanings to Programs는 프로그램의 제어 흐름 지점에 명제를 붙이고, 변수 값에 대한 조건이 실행 과정에서 어떻게 유지되는지 설명했다.10
C. A. R. Hoare의 1969년 An Axiomatic Basis for Computer Programming은 대입문·조건문·반복문에 대한 공리와 추론 규칙을 정리했다.11
이때 상태는 단순한 메모리의 현재 내용이 아니라, 프로그램의 정확성을 주장하는 대상이 된다.
{ P } C { Q }
P: 실행 전 상태가 만족해야 하는 조건
C: 상태를 바꾸는 명령
Q: 실행 후 상태가 만족해야 하는 조건이 관점에서는 결정적·순차적 명령형 프로그램을 다음과 같은 부분 상태 변환으로 볼 수 있다.
프로그램 C: 상태 Σ ⇀ 상태 Σ여기서 ⇀는 부분 함수라는 뜻이다.
어떤 입력 상태에서는 프로그램이 종료하지 않아 결과 상태가 없을 수 있다. 이를 명시적으로 표현할 때는 비종료 또는 정의되지 않음을 나타내는 ⊥를 추가해 C : Σ → Σ⊥로 쓸 수 있다.
예외나 실패 종류까지 구분하려면 C : Σ → (Σ + E)⊥처럼 오류 공간 E를 별도로 포함해야 한다. 입출력과 동시성까지 포함하면 더 복잡해지지만, “프로그램은 상태를 변환한다”는 모델은 명령형 언어를 설명하는 기본 골격이 되었다.
동시에 Scott와 Strachey는 1971년 Toward a Mathematical Semantics for Computer Languages에서 프로그램의 의미를 특정 기계의 구현과 독립적인 수학적 대상으로 다루려 했으나12,
상태는 이제 하드웨어 레지스터만이 아니라, 언어의 의미를 정의하는 추상적인 공간이 되었다.
1960년대~1980년대: 동시성과 분산 환경이 상태를 공동의 문제로 만들다
단일 실행 흐름에서 x := x + 1은 현재 저장소와 다음 저장소의 관계로 설명할 수 있다. 하지만 여러 실행 흐름이 같은 가변 값을 읽고 쓸 때는, 각 연산이 끼어드는 순서에 따라 결과가 달라진다. 상태는 이제 값 자체뿐 아니라 누가 언제 읽고 쓸 수 있는가의 문제가 되었다.
다익스트라는 1965년 동시 프로그래밍 제어 문제를 다루었고, 1968년 Cooperating Sequential Processes에서 협력 프로세스와 세마포어 연산을 체계적으로 설명하였다.13세마포어·상호 배제·임계 구역은 공유 가변 상태에 무조건 접근하지 못하게 하는 장치들이다.
이들은 경쟁 상태에 대해서 자동으로 해체하는 방식이 아닌, 상태 접근의 순서와 불변식을 명시적으로 설계하게 만드는 것이다.
네트워크로 나뉜 프로세스에서는 각 노드가 서로 다른 시점의 로컬 상태를 관찰하는데, Lamport의 1978년 논문은 happened-before 관계가 인과성에 따른 부분 순서를 이룬다는 점과, 논리 시계로 인과성과 양립하는 사건 순서를 구성할 수 있음을 보인다.14
a happened-before b ⇒ C(a) < C(b)
C(a) < C(b) ⇏ a happened-before b이러한 논리로 알 수 있는 것은, 스칼라 논리 시계는 인과관계를 완전히 판별하지 못한다. 동시 사건은 같은 시각값을 가질 수도 있고 서로 다른 시각값을 가질 수도 있다. 모든 사건에 전순서를 부여하려면 논리 시각과 프로세스 ID 같은 임의의 동률 해소 규칙을 결합할 수 있지만, 이렇게 얻은 순서에서 동시 사건 사이의 선후관계는 인과적 사실이 아니라 시스템이 선택한 순서다.
이는 일반적인 비동기 분산 시스템에서 모든 노드가 동일한 전역 현재와 사건의 절대적 선후관계를 즉시 공유한다고 전제할 수 없다는 뜻이다.
분산 상태는 단일 메모리 스냅샷이 아니라, 메시지 전달·순서 규칙·복제 및 합의 프로토콜 아래에서 각 노드가 유지하고 조정하는 상태들의 관계가 된다는 것이다.(왜 분산 프로그래밍이 악명높은지 이론적인 배경이다)
데이터베이스 트랜잭션은 이 문제를 상태 전이의 경계로 다뤘다. Gray의 1981년 정리는 트랜잭션을 상태 변환으로 설명하며 원자성, 일관성, 지속성을 핵심 성질로 제시한다.15이후 널리 쓰인 ACID라는 표현에는 격리성까지 포함되며, 이 약어는 Härder와 Reuter의 1983년 논문에서 정리되었다.16 즉 장애와 동시 접근 아래에서 정의한 무결성 제약과 격리 수준에 맞는 상태 전이를 제공하려면, 락이나 MVCC 같은 동시성 제어, commit/abort 경계, 로그와 복구, 그리고 여러 참여자가 있는 경우 원자적 커밋 프로토콜 같은 별도의 계약이 필요하다는 점이다.
이 계보에서 상태는 단순히 메모리에 기록된 값이 아니라, 소유자·전이 순서·관찰 가능성·장애 후 복구까지 함께 정의해야 하는 시스템 자원이 되었다. 이후 분산 상태를 다루는 설계에서는 이벤트 소싱과 최종 일관성 같은 선택지도 널리 사용되었다.
이 각각의 해법 또한 문제 전체의 해법이 아니라, 사건 기록과 복제본 수렴을 다루는 서로 다른 설계 선택지일 뿐이다.
객체지향은 상태와 연산의 소유권을 묶었다
객체지향 프로그래밍의 한 흐름은 상태를 없애지 않고 상태와 상태를 조작하는 연산의 소유권을 묶는 방향으로 발전했다.
절차적 스타일
외부 함수 → 외부 데이터 변경
객체 스타일
객체 → 자신의 상태를 보존하고 메시지에 따라 변경이 관점에서 상태를 가진 객체는 단순한 데이터 구조가 아니며, 자신의 현재 상태를 보존하고, 허용된 메시지에 따라 다음 상태로 이동한다. 불변 객체와 값 객체는 이 설명의 반례가 아니라 상태 변경을 외부에서 새 값의 생성으로 표현하는 다른 설계이다.
따라서 객체지향의 캡슐화는 상태의 표현을 감추고, 상태를 변경할 수 있는 통로를 제한하는 설계 규율이기도 하다.
물론 객체지향은 상태를 모듈·객체의 경계 안에 배치한 여러 설계 중 하나일 뿐이다.
웹은 무상태(Stateless) 지만 상태를 없애진 않았다.
HTTP는 공식적으로 stateless 프로토콜이다. RFC 9110은 각 요청의 의미가 다른 요청이나 연결의 맥락에 의존하지 않고 독립적으로 이해되어야 한다고 설명한다.17
보통 이것때문에 웹 서버가 상태를 가질 수 없다고 생각하지만, 서버가 요청 의미를 이해하기 위해 이전 요청을 반드시 기억해야 하는 프로토콜 규칙을 두지 않는다는 뜻일 뿐이다.
그래서 실제 웹 애플리케이션은 상태를 다른 곳에 두는데 대체로 상태를 두는 장소는 아래와 같다.
쿠키와 세션 저장소
데이터베이스와 캐시
액세스 토큰과 refresh token
브라우저의 DOM, History API, local storage
서버 메모리와 분산 캐시
즉 웹의 “무상태”는 상태의 부재가 아니라 상태의 위치와 책임을 분리하기 위한 설계다.
무상태성은 연결 재사용과 로드 밸런싱을 단순하게 만들 수 있지만, 재시도가 안전한지는 별도의 멱등성(idempotency) 계약에 달려 있다. 사용자 세션과 작업 흐름은 여전히 별도의 저장·식별·만료 정책이 필요하다.
현대의 state management는 상태의 분할 문제다
오늘날 프론트엔드에서 “상태 관리”라고 부르는 작업은 단순히 변수를 하나 저장하는 일이 아닐 것이다. 서로 다른 수명과 소유자를 가진 상태를 분리하고 동기화하는 일이다.
컴포넌트 상태 → 한 화면 안에서만 필요한 값
페이지 상태 → 라우트와 History에 연결된 값
서버 상태 → 원격 API가 소유하는 값
세션 상태 → 로그인·권한·만료와 연결된 값
영속 상태 → DB·파일·local storage에 남는 값
캐시 상태 → 원본에서 파생됐지만 재생성 가능한 값이들을 하나의 전역 객체에 모두 넣으면 상태의 소유자와 수명이 사라진다. 반대로 상태를 지나치게 쪼개면 전이와 동기화가 분산된다.
현대의 Redux, MVVM, 반응형 시스템, 이벤트 소싱, 상태기계 라이브러리는 서로 다른 방식으로 같은 문제를 다룰뿐이다.
상태를 어떻게 다루어야하는가
상태가 있는 코드를 볼 때는 변수 이름도 물론 중요하지만, 다음과 같은 것들이 중요하다.
누가 소유하는가? 객체, 요청, 프로세스, 서버, 데이터베이스 중 어디가 원본인가?
얼마나 오래 사는가? 한 함수, 한 요청, 한 세션, 프로세스, 영구 저장소 중 어느 수명인가?
무엇이 전이시키는가? 명령, 이벤트, 시간, 외부 응답, 다른 스레드인가?
어떤 상태가 유효한가? 모든 값 조합이 허용되는가, 아니면
Paid → Shipped처럼 전이 규칙이 있는가?
상태 버그는 대개 값 하나가 틀린 문제가 아니라 이 네 가지 계약이 섞인 문제다. 상태 패턴은 전이를 객체로 모으고, 타입상태는 전이 규칙을 타입에 싣고, 데이터베이스 transaction은 여러 상태 변경의 경계를 묶는 것이 중요하다.
상태와 데이터는 역할이 다르다
흔히 상태와 데이터를 같다고 말하는 강의가 있지만, 상태와 데이터는 본질적으로 서로 다른 종류라기보다, 시스템 안에서 맡는 역할이 다르다. 어떤 값이 입력·설정·기록으로만 쓰이면 데이터에 가깝고, 현재 값에 따라 이후 행동과 결과가 달라지면 상태로 기능한다.
불변 입력 데이터
같은 입력 → 같은 계산의 재료
상태
현재 값 → 이후 행동과 결과를 바꿈예를 들어서 사용자 이름 = 홍길동이라는 값은 어떤 시스템에서는 단순 입력 데이터일 수 있다. 그러나 UI가 현재 로그인한 사용자를 표시하거나 권한 검사·캐시 키 결정에 사용한다면 같은 값도 해당 시스템 경계 안에서는 상태의 일부로 기능한다.
반대로 변경되지 않는 설정 파일이나 과거 로그는 시스템의 이후 전이를 직접 결정하지 않는 한 상태라기보다 입력 또는 기록 데이터에 가깝다. 로그인 여부, 권한, 장바구니, 결제 승인 여부는 이후 어떤 요청을 허용할지 바꾸므로 애플리케이션 상태가 된다.
status도 상태 전체와 같지 않다. Paid라는 라벨은 관찰 가능한 상태의 일부일 수 있지만, 실제 시스템이 안전하게 동작하려면 결제 승인 ID, 금액, 버전, 만료 시간, 재시도 여부까지 필요할 수 있다. 상태를 한 단어의 enum으로 축약할 때는 무엇이 숨겨지는지 확인해야 한다.
State 시작점을 찾아서: 각 시대의 질문
질문 | 역사적 답 |
|---|---|
| 프로그래밍보다 오래되었으며 단일 발명자가 없다 |
계산 모델에서 현재 내부 조건을 설명한 시기 | 튜링의 1936년 |
순차회로의 Mealy·Moore 상태기계 모델이 표준적 형태로 정착한 시기 | 1950년대 중반이다 |
프로그램의 mutable state가 일상화된 시기 | 1950년대 고급 언어의 변수·대입문과 함께다 |
프로그램 state를 형식적으로 증명한 시기 | Floyd 1967, Hoare 1969, Scott–Strachey 1971 전후다 |
동시성과 분산 환경에서 상태의 순서·일관성이 핵심 문제가 된 시기 | 멀티프로그래밍이 확산한 1960년대 이후이며, Lamport 1978과 데이터베이스 트랜잭션 연구가 중요한 이정표다 |
애플리케이션 state management가 별도 설계 문제로 성장한 시기 | 데이터베이스·대화형 시스템·GUI·분산 시스템의 발전과 함께 1960년대 이후 점진적으로 커졌고, 웹·프론트엔드에서는 특히 1990년대 이후 두드러졌다 |
- 질문
state라는 일반 단어의 시작- 역사적 답
프로그래밍보다 오래되었으며 단일 발명자가 없다
- 질문
계산 모델에서 현재 내부 조건을 설명한 시기
- 역사적 답
튜링의 1936년
state of mind·m-configuration이 중요한 출발점이다
- 질문
순차회로의 Mealy·Moore 상태기계 모델이 표준적 형태로 정착한 시기
- 역사적 답
1950년대 중반이다
- 질문
프로그램의 mutable state가 일상화된 시기
- 역사적 답
1950년대 고급 언어의 변수·대입문과 함께다
- 질문
프로그램 state를 형식적으로 증명한 시기
- 역사적 답
Floyd 1967, Hoare 1969, Scott–Strachey 1971 전후다
- 질문
동시성과 분산 환경에서 상태의 순서·일관성이 핵심 문제가 된 시기
- 역사적 답
멀티프로그래밍이 확산한 1960년대 이후이며, Lamport 1978과 데이터베이스 트랜잭션 연구가 중요한 이정표다
- 질문
애플리케이션 state management가 별도 설계 문제로 성장한 시기
- 역사적 답
데이터베이스·대화형 시스템·GUI·분산 시스템의 발전과 함께 1960년대 이후 점진적으로 커졌고, 웹·프론트엔드에서는 특히 1990년대 이후 두드러졌다
계산과 제어에서의 상태 개념은 기억이 필요한 물리 시스템과 계산 모델에서 구체화되어, 순차회로의 내부 조건과 프로그램의 저장소·의미론을 거쳐, 오늘날에는 여러 시스템이 나누어 소유하는 시간적 계약으로 확장되었다.
각주
- Alan M. Turing, “On Computable Numbers, with an Application to the Entscheidungsproblem,” Proceedings of the London Mathematical Society, 1937, 2nd series, 42(1), 230–265. (권차 42는 서지에 따라 1936–1937로도 표기된다.) DOI · Oxford Academic ↩
- Claude E. Shannon, “A Symbolic Analysis of Relay and Switching Circuits,” Transactions of the American Institute of Electrical Engineers, 1938. IEEE 서지 ↩
- https://doi.org/10.1016/0016-0032(54)90574-8 ↩
- George H. Mealy, “A Method for Synthesizing Sequential Circuits,” Bell System Technical Journal, 1955. DOI ↩
- Edward F. Moore, “Gedanken-Experiments on Sequential Machines,” in Automata Studies, 1956. Chapter PDF ↩
- Peter Naur, ed., “Revised Report on the Algorithmic Language ALGOL 60,” Communications of the ACM 6(1), 1963. Computer History Museum archive ↩
- John McCarthy, “Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I,” Communications of the ACM, 1960. Stanford archive ↩
- John McCarthy et al., LISP 1.5 Programmer's Manual, MIT Press, 1962. Bibliographic record ↩
- https://doi.org/10.1115/1.3662552 ↩
- Robert W. Floyd, “Assigning Meanings to Programs,” 1967. Paper PDF ↩
- C. A. R. Hoare, “An Axiomatic Basis for Computer Programming,” Communications of the ACM, 1969. ACM ↩
- Dana Scott and Christopher Strachey, “Toward a Mathematical Semantics for Computer Languages,” Oxford Programming Research Group, 1971. Oxford archive ↩
- Edsger W. Dijkstra, “Solution of a Problem in Concurrent Programming Control,” Communications of the ACM 8(9), 1965; “Cooperating Sequential Processes,” 1968. 1965 DOI · 1968 manuscript ↩
- Leslie Lamport, “Time, Clocks, and the Ordering of Events in a Distributed System,” Communications of the ACM 21(7), 1978, 558–565. Microsoft Research ↩
- Jim Gray, “The Transaction Concept: Virtues and Limitations,” Tandem Technical Report 81.3, 1981. PDF ↩
- Theo Härder and Andreas Reuter, “Principles of Transaction-Oriented Database Recovery,” ACM Computing Surveys 15(4), 1983, 287–317. DOI · IBM Research ↩
- IETF, RFC 9110: HTTP Semantics, 2022. RFC Editor ↩