모든 프로그램을 데이터와 상태 전이로 보면 설계가 더 선명해진다

“모든 프로그램은 데이터베이스다”라는 말은 엄밀한 정의라기보다 사고 실험에 가깝다. 실제로 모든 프로그램이 관계형 데이터베이스 관리 시스템은 아니다. 하지만 프로그램을 설계할 때 무엇을 저장하고, 어떻게 읽고, 언제 바꾸고, 어떤 상태를 허용할 것인가로 바라보면 구조가 훨씬 또렷해지는 경우가 많다.
데이터베이스 문서를 읽어 보면 이 감각이 더 잘 보인다. PostgreSQL은 트랜잭션을 통해 여러 변경이 모두 성공하거나 모두 취소돼야 한다고 설명하고, 외래 키 같은 제약은 존재해서는 안 되는 관계를 막아 준다. 많은 애플리케이션 코드도 형태만 다를 뿐 비슷한 문제를 다룬다.
프로그램의 핵심은 결국 저장, 조회, 갱신, 삭제의 조합이다
게임을 예로 들어도 비슷하다. 플레이어의 위치, 체력, 인벤토리, 퀘스트 상태는 모두 데이터다. 문서 편집기라면 본문, 스타일, 커서 위치가 데이터다. 협업 도구라면 작업 카드, 담당자, 상태 값이 데이터다.
겉으로는 전혀 다른 소프트웨어처럼 보여도, 내부에서는 보통 다음 질문을 반복한다.
- 어떤 정보를 저장할 것인가
- 필요한 정보를 얼마나 빠르게 찾을 수 있는가
- 여러 변경을 함께 묶어야 하는가
- 잘못된 상태를 구조적으로 막을 수 있는가
이 질문은 데이터베이스 설계 질문과 거의 닮아 있다.
성능 문제도 종종 ‘어떻게 읽는가’에서 터진다
프로그램이 느려질 때 사람들은 알고리즘만 떠올리기 쉽다. 물론 중요하다. 하지만 실무에서는 무엇을 얼마나 자주 찾는가, 같은 데이터를 몇 번이나 중복 계산하는가, 필요 없는 범위를 계속 순회하는가 같은 조회 패턴이 성능을 크게 좌우할 때가 많다.
그래서 자료구조를 고를 때도 단순히 저장 형태만 볼 일이 아니다.
- 목록을 자주 순회하는가
- 키로 즉시 찾는가
- 범위 검색이 많은가
- 공간 정보처럼 위치 기반 조회가 필요한가
프로그램을 데이터 문제로 보면 이런 질문이 먼저 보인다. 그러면 객체 이름보다 접근 패턴이 먼저 보이기 시작한다.
무결성과 상태 전이는 데이터 저장만큼 중요하다
데이터베이스의 외래 키와 제약 조건은 “있으면 좋은 장식”이 아니다. 시스템이 허용하면 안 되는 상태를 구조적으로 막기 위한 장치다. 애플리케이션도 마찬가지다.
예를 들어 주문은 결제 완료 전에 배송 완료가 되면 안 되고, 게임 캐릭터는 동시에 서 있고 점프하고 쓰러진 상태일 수 없다. 이런 문제를 if 문으로만 계속 막다 보면 언젠가 예외가 새어 나온다.
그래서 상태 전이 관점이 중요하다. 게임 프로그래밍 패턴의 상태 패턴 글이 보여 주듯, 복잡한 분기와 가변 상태는 버그가 잘 생기는 영역이다. 유효한 상태를 명시하고, 어떤 입력이 어떤 상태 변화를 일으키는지 분명히 하면 설계가 훨씬 읽기 쉬워진다.
이 관점의 장점은 기술 스택을 가리지 않는다는 점이다
관계형 데이터베이스를 쓰든, 메모리 객체를 쓰든, 이벤트 스트림을 쓰든 핵심 질문은 크게 다르지 않다.
- 이 데이터의 단일한 진실은 어디에 있는가
- 계산된 값을 저장할 것인가, 필요할 때 다시 만들 것인가
- 두 변경은 함께 성공해야 하는가
- 어떤 상태 조합을 금지해야 하는가
이 질문이 선명하면 프레임워크가 바뀌어도 설계가 덜 흔들린다. 반대로 이 질문이 흐리면 언어와 패턴을 많이 알아도 구조는 쉽게 꼬인다.
핵심 정리
모든 프로그램이 문자 그대로 데이터베이스는 아니다. 하지만 저장, 조회, 갱신, 삭제, 무결성, 상태 전이의 관점으로 프로그램을 바라보면 설계의 핵심이 훨씬 선명해진다.
좋은 코드는 종종 화려한 추상화보다도 “무엇을 저장하는가”, “무엇이 유효한 상태인가”, “어떤 변경이 함께 움직여야 하는가”를 분명하게 정리한 코드에 가깝다. 데이터를 어떻게 다루는지가 결국 프로그램의 성격을 결정한다.