출시 직전 저장 데이터가 꼬일 때 게임 세이브 설계법
저장 데이터가 문제를 일으키는 순간부터 좁히기
재현 조건을 먼저 기록합니다
출시 직전 QA 빌드에서 저장 데이터가 꼬이면, 대부분은 저장 코드 한 줄만의 문제가 아닙니다. 게임 프로그래밍에서 세이브 시스템은 플레이 상태, 파일 입출력, 버전 관리, 플랫폼 동기화가 한 번에 만나는 지점입니다. 그래서 증상을 바로 고치려 하기보다 언제, 어떤 상태에서, 어떤 파일이 만들어졌는지부터 좁혀야 합니다.
예를 들어 튜토리얼 직후에는 정상인데 보스전 직전 자동 저장만 깨진다면, 문제는 전체 직렬화가 아니라 전투 상태 또는 임시 버프 데이터일 가능성이 큽니다. 반대로 PC에서는 정상이고 휴대용 기기에서만 실패한다면 경로 권한, 저장 타이밍, 클라우드 동기화 충돌을 함께 봐야 합니다. 개발자 포트폴리오에 넣을 프로젝트라도 이 흐름을 갖추면 코드의 신뢰도가 확 올라갑니다.
- 언제 저장되는가: 수동 저장, 자동 저장, 체크포인트 저장, 종료 시 저장을 구분합니다.
- 무엇을 저장하는가: 플레이어 위치, 인벤토리, 퀘스트 플래그, 난수 시드, 월드 오브젝트 상태를 목록화합니다.
- 어디에 저장되는가: 로컬 파일, 플랫폼 클라우드, 자체 서버 저장소 중 실제 경로를 확인합니다.
- 어떻게 실패하는가: 저장 중 강제 종료, 디스크 부족, 네트워크 끊김, 이전 버전 로드 실패를 따로 재현합니다.
팁: 저장 버그 리포트에는 스크린샷보다 세이브 파일, 빌드 번호, 플레이 단계, 직전 입력이 더 중요합니다. 이 네 가지가 있으면 원인을 찾는 시간이 크게 줄어듭니다.
게임 업계 행사나 기술 발표를 따라보면 세이브, 툴, 런타임 안정성 같은 주제는 겉보기보다 훨씬 실무적입니다. 관련 맥락을 넓히고 싶다면 GDC의 의미와 배경을 참고해, 개발자가 왜 실패 사례와 제작 과정을 공유하는지 함께 읽어두면 좋습니다.
세이브 파일 포맷을 고르기 전에 보는 기준
JSON, 바이너리, 데이터베이스의 자리가 다릅니다
저장 포맷은 취향으로 고르는 영역이 아닙니다. 디버깅을 자주 해야 하는 인디 개발 초기라면 사람이 읽을 수 있는 JSON이나 YAML 계열이 편하고, 데이터 크기와 로딩 속도가 중요해지는 시점에는 바이너리 포맷이나 압축을 검토하게 됩니다. 다만 빠른 포맷이 항상 좋은 선택은 아닙니다. 고장 났을 때 열어볼 수 없고, 버전이 바뀔 때 변환 로직이 약하면 속도 이득보다 유지보수 비용이 커집니다.
math 라이브러리를 직접 쓰는 게임이라면 벡터, 행렬, 쿼터니언 같은 타입도 저장 정책을 정해야 합니다. 화면에서는 같은 회전처럼 보여도 내부 표현이 정규화되지 않으면 로드 후 물리나 애니메이션이 미세하게 흔들릴 수 있습니다. 좌표, 회전, 스케일은 문자열로 대충 저장하기보다 소수점 자리, 단위, 축 기준을 명시해야 합니다.
| 포맷 | 어울리는 상황 | 주의할 점 |
|---|---|---|
| JSON | 초기 개발, 툴 연동, 사람이 직접 확인하는 QA | 파일 크기와 파싱 비용, 타입 누락에 주의 |
| 바이너리 | 대용량 월드, 빠른 로딩, 상용 빌드 최적화 | 디버깅 도구와 버전 변환기가 필요 |
| SQLite 등 내장 DB | 아이템, 기록, 로그처럼 검색이 잦은 데이터 | 트랜잭션 설계와 파일 잠금 정책 확인 |
- 사람이 읽어야 하는 단계인지 먼저 판단합니다. 개발 중에는 가시성이 성능보다 중요할 때가 많습니다.
- 파일 크기 증가 속도를 측정합니다. 한 슬롯이 200KB인지 20MB인지에 따라 전략이 달라집니다.
- 부분 저장이 필요한지 확인합니다. 오픈월드처럼 변경 영역이 넓으면 전체 덤프보다 청크 단위 저장이 낫습니다.
- 치트와 변조 가능성을 따집니다. 싱글 플레이와 경쟁형 멀티플레이는 요구 수준이 다릅니다.
포맷을 정할 때는 구매 전 확인사항처럼 따져보는 태도가 좋습니다. 나중에 바꿀 수 있다는 말은 반쯤만 맞습니다. 저장 파일은 사용자의 플레이 시간과 직접 연결되므로, 포맷 변경은 코드 리팩터링보다 더 조심스럽게 진행해야 합니다.
버전 마이그레이션은 나중이 아니라 첫날에 둡니다
스키마 번호와 변환 함수를 함께 둡니다
세이브 시스템에서 가장 흔한 착각은 첫 출시 전까지는 버전 관리가 필요 없다는 생각입니다. 하지만 게임은 개발 중에도 이미 여러 버전의 데이터가 생깁니다. 어제 만든 테스트 세이브, 오늘 받은 QA 세이브, 데모 빌드에서 생성된 사용자 세이브가 서로 다른 구조를 가질 수 있습니다. developer 관점에서는 이 파일들을 모두 현재 코드가 어떻게 해석할지 정해야 합니다.
좋은 방식은 세이브 루트에 스키마 버전을 넣고, 로드 시 낮은 버전부터 현재 버전까지 순서대로 변환하는 것입니다. 예를 들어 v2에서 인벤토리 슬롯 이름이 바뀌고 v3에서 퀘스트 상태가 분리됐다면, v1 파일은 v2 변환을 거친 뒤 v3 변환을 거쳐야 합니다. 중간 단계를 생략하면 일부 필드가 조용히 사라지는 문제가 생깁니다.
기획 변경도 저장 구조에 영향을 줍니다
세이브 파일은 프로그래머 혼자 지키는 성이 아닙니다. 기획자가 퀘스트 실패 조건을 추가하거나 아이템 등급 체계를 바꾸면 저장 구조도 바뀝니다. 역할의 정의가 궁금하다면 기획자에 대한 설명을 참고해도 좋습니다. 핵심은 직군 이름이 아니라, 변경 요청이 데이터에 남기는 흔적을 팀이 함께 이해하는 것입니다.
- 세이브 헤더에 버전 번호를 둡니다. 빌드 번호와 데이터 스키마 번호는 분리하는 편이 안전합니다.
- 변환 함수는 삭제하지 않습니다. 오래된 파일을 지원해야 한다면 v1_to_v2 같은 단계별 변환을 보관합니다.
- 실패 정책을 정합니다. 복구 가능한 누락은 기본값을 넣고, 복구 불가능한 손상은 사용자에게 명확히 안내합니다.
- 샘플 세이브 묶음을 테스트 자산으로 관리합니다. 오래된 파일을 매번 사람이 찾지 않게 해야 합니다.
전문가 조언: 마이그레이션 코드는 보기 좋게 짧은 코드보다 의도가 드러나는 코드가 낫습니다. 왜 기본값을 0이 아니라 1로 넣는지 주석을 남기면, 다음 변경 때 같은 실수를 피할 수 있습니다.
마이그레이션을 처음부터 준비하면 업데이트가 두렵지 않습니다. 특히 포트폴리오 프로젝트를 공개 저장소에 올릴 때는 샘플 세이브와 변환 테스트가 좋은 신호가 됩니다. 단순히 실행되는 게임이 아니라, 시간이 지나도 데이터를 다룰 줄 아는 개발자라는 메시지를 주기 때문입니다.
플랫폼 저장소와 비용을 계약서처럼 읽기
로컬, 클라우드, 서버 저장의 기준을 나눕니다
세이브 저장 위치는 기술 선택이면서 운영 선택입니다. 로컬 파일은 구현이 단순하고 비용 부담이 작지만, 기기 교체나 삭제에 약합니다. 플랫폼 클라우드 저장은 사용자 경험이 좋지만 동기화 충돌, 저장 용량 제한, 오프라인 상태를 고려해야 합니다. 자체 서버 저장은 보안과 제어력이 높지만 인증, 백업, 장애 대응, 개인정보 처리까지 개발 범위가 넓어집니다.
여기서 말하는 비용은 서버 요금만 뜻하지 않습니다. QA 시간, 고객 문의 대응, 데이터 복구 도구 제작, 플랫폼 심사 대응까지 모두 비용입니다. 작은 게임이라도 저장 실패 한 번이 리뷰와 환불로 이어질 수 있습니다. 프로젝트 예산을 기능별로 배분하는 감각이 필요하다면 계획예산 제도의 개념처럼 목표와 자원을 연결해 보는 관점이 도움이 됩니다.
도입 전 확인할 질문
- 오프라인 플레이가 가능한가: 가능하다면 로컬 저장과 서버 저장의 병합 규칙이 필요합니다.
- 여러 기기에서 동시에 플레이할 수 있는가: 마지막 저장 우선인지, 플레이 시간이 긴 저장 우선인지 정해야 합니다.
- 저장 용량이 커질 수 있는가: 월드 상태, 리플레이, 사용자 제작 콘텐츠는 예상보다 빨리 커집니다.
- 복구 요청을 받을 준비가 됐는가: 사용자가 보낸 파일을 열어볼 내부 도구가 있어야 합니다.
- 민감한 정보가 포함되는가: 계정 식별자나 결제 관련 상태는 저장 위치와 암호화 정책을 별도로 검토합니다.
실무에서는 처음부터 거대한 백엔드를 붙이기보다 저장 데이터의 성격을 분리하는 편이 현실적입니다. 진행도와 설정값은 로컬 또는 플랫폼 저장으로 처리하고, 랭킹이나 거래처럼 신뢰가 필요한 정보만 서버에 둡니다. 이렇게 나누면 비용은 낮추고, 보안이 필요한 영역에는 집중할 수 있습니다.
테스트 슬롯은 실제 플레이어처럼 굴려야 합니다
정상 경로보다 비정상 경로가 더 많은 정보를 줍니다
세이브 테스트는 새 게임을 시작하고 저장 버튼을 누르는 것으로 끝나지 않습니다. 실제 플레이어는 메뉴를 빠르게 닫고, 저장 중 전원을 끄고, 이전 패치의 파일을 들고 돌아오며, 가끔은 파일을 직접 복사합니다. 그래서 테스트 슬롯은 깔끔한 해피 패스보다 지저분한 현실을 닮아야 합니다.
특히 자동 저장이 있는 게임은 저장 타이밍을 세밀하게 봐야 합니다. 전투 승리 직후, 컷신 시작 전, 상점 구매 후, 맵 이동 중 어느 순간에 저장하는지에 따라 복구 지점이 달라집니다. 저장이 너무 잦으면 성능과 디스크 수명에 부담이 생기고, 너무 드물면 손실 체감이 커집니다. 결국 세이브는 UX와 엔진 구조가 만나는 기능입니다.
- 새 게임 슬롯: 첫 실행, 튜토리얼, 초기 설정 저장이 정상인지 확인합니다.
- 중반 진행 슬롯: 퀘스트 분기, 인벤토리 확장, 맵 해금 상태를 포함합니다.
- 엔딩 직전 슬롯: 많은 플래그가 켜진 상태에서 로딩 시간이 늘어나지 않는지 봅니다.
- 손상 파일 슬롯: 일부 필드 삭제, 잘린 파일, 잘못된 타입을 넣어 복구 로직을 검증합니다.
- 이전 버전 슬롯: 공개 빌드마다 대표 세이브를 보관해 업데이트 호환성을 확인합니다.
테스트 자동화도 추천합니다. 저장 후 바로 로드하고, 로드한 상태를 다시 저장한 뒤 핵심 필드가 유지되는지 비교하는 회귀 테스트를 만들 수 있습니다. 수치가 중요한 게임이라면 HP, 위치, 경험치, 장비 효과처럼 플레이 결과에 영향을 주는 값을 우선 비교하세요. 모든 값을 완벽히 비교하려는 욕심보다 사용자가 체감하는 상태를 먼저 지키는 편이 낫습니다.
출시 직전 세이브를 망치는 작은 습관들
성공 로그만 믿고 복구 경로를 빼먹습니다
첫 번째 실수는 저장 성공 로그만 보고 안심하는 것입니다. 파일 쓰기가 성공해도 실제 내용이 비어 있거나, 임시 파일 교체 과정에서 기존 파일을 덮어썼거나, 클라우드 업로드 직전에 앱이 종료될 수 있습니다. 저장은 성공과 실패의 둘 중 하나가 아니라 부분 성공이라는 애매한 상태를 자주 만납니다.
두 번째 실수는 모든 데이터를 한 번에 저장하려는 습관입니다. 설정값, 진행도, 월드 상태, 임시 전투 상태를 한 파일에 몰아넣으면 작은 오류가 전체 로드 실패로 번집니다. 가능하면 데이터의 수명과 중요도를 기준으로 파일을 나누세요. 그래픽 옵션이 깨졌다고 40시간 플레이 기록까지 잃어버리면 안 됩니다.
테스트 데이터가 너무 예쁘면 위험합니다
- 기본값에 기대는 코드: 필드가 없을 때 우연히 0으로 동작하는 코드는 다음 업데이트에서 쉽게 깨집니다.
- 에디터 전용 경로: 개발 환경의 절대 경로가 빌드에 남아 있으면 사용자 PC에서 저장이 실패합니다.
- 동시 저장 무시: 자동 저장과 수동 저장이 겹칠 때 파일 잠금이나 큐 처리가 없으면 데이터가 잘립니다.
- 압축만 믿는 설계: 압축 파일은 작지만, 손상되면 일부만 읽어 복구하기 어려울 수 있습니다.
- 암호화와 검증 혼동: 암호화는 내용을 숨기는 장치이고, 무결성 검사는 변조나 손상을 감지하는 장치입니다.
세 번째 실수는 세이브 시스템을 마지막 주에 붙이는 것입니다. 저장은 게임의 모든 시스템을 지나가는 혈관 같은 기능이라, 늦게 붙일수록 예외가 늘어납니다. 다음 빌드부터는 기능을 하나 추가할 때마다 이 상태는 저장해야 하는가, 로드 후에도 같은가, 이전 버전 파일은 어떻게 되는가를 함께 묻는 편이 좋습니다. 그 질문이 쌓이면 출시 직전의 불안은 훨씬 작아집니다.

- 다음글최적화보다 계측, 게임 프로그래밍 병목을 먼저 본다 26.09.24
등록된 댓글이 없습니다.
