개발 머신이 죽고 나서 정리한 개발자 백업 체크리스트 7가지

개발 머신 고장 이후 살아남은 자산과 사라진 작업을 비교한 개발자 백업 체크리스트 도식

개발자 백업은 평소에는 아무 일도 하지 않다가, 장비가 죽는 날 하루 만에 몇 주치 작업을 결정합니다. 15년 된 개발 머신이 에어컨 없는 작업실에서 과열로 멈췄고, 우분투가 설치된 SSD는 부팅조차 되지 않았습니다. 그날 살아남은 것과 사라진 것을 정리해 보니, 백업은 습관이 아니라 순서의 문제였습니다.

개발 머신 고장 이후 살아남은 자산과 사라진 작업을 비교한 개발자 백업 체크리스트 도식
백업해 둔 자산만 살아남고, 그 PC에만 있던 작업은 디스크와 함께 사라진다

백업이 중요하다는 말은 누구나 합니다. 저도 알고 있었습니다. 그런데 실제로 무엇을, 어디에, 얼마나 자주 백업해야 하는지는 사고가 난 뒤에야 구체적으로 알게 되었습니다. 이 글은 원론적인 백업 안내가 아니라, 개발 머신 한 대가 죽으면서 제가 실제로 겪은 일과 그 과정에서 확인한 항목들을 정리한 기록입니다.

15년 된 개발 머신이 결국 멈췄습니다

제 개발 머신은 15년쯤 된 데스크톱입니다. 여름이면 에어컨이 들어오지 않는 작업실에서 하루 종일 켜져 있었고, 몇 번은 과열로 다운되기도 했습니다. 그때마다 퇴근하고 달려가 전원을 다시 넣으면 그럭저럭 돌아왔습니다. 그래서 이번에도 같은 일이라고 생각했습니다.

이번에는 달랐습니다. 우분투가 설치된 SSD가 인식되지 않았고, 부팅 자체가 되지 않았습니다. 데이터라도 꺼내 볼 생각으로 외장 케이스를 주문해 두었지만, 다른 PC에 연결해 봐야 알 수 있는 일이고 가능성이 높다고 보지는 않습니다. 컨트롤러가 죽은 SSD는 데이터가 남아 있어도 접근할 방법이 마땅치 않습니다.

여기까지는 장비 문제였습니다. 진짜 문제는 그다음에 시작되었습니다.

문제는 PC가 아니라 마지막 push 시점이었습니다

하필 같은 시기에, 그 PC에서 작업하던 Local AI Client 앱에 ANR 리포트가 쏟아지기 시작했습니다. 크래시 기록이 쌓이는 속도만큼 리뷰 평점이 내려갔고, 사용자가 떠나는 것이 숫자로 보였습니다. 급하게 수정해서 배포해야 하는 상황인데, 정작 코드가 있던 컴퓨터가 죽어 있었습니다.

다른 PC에서 저장소를 클론했습니다. 그런데 마지막 push 기록이 한참 전이었습니다. 커밋은 꾸준히 하고 있었지만, 원격 저장소에 올리는 일은 “나중에 몰아서” 하고 있었던 겁니다. 그 사이에 작업한 내용은 전부 사망한 SSD 안에 있었습니다.

과열로 인한 개발 머신 고장부터 ANR 폭증과 재작업까지 6단계를 정리한 타임라인
손실은 장비가 죽는 순간이 아니라 백업이 비어 있던 구간에서 발생한다

다행히 키스토어는 예전에 따로 백업해 둔 것이 있었습니다. 그 파일을 찾아 부랴부랴 배치하고, 저장소에 남아 있는 앱 버전을 확인한 뒤, 그 이후에 했던 작업을 다시 진행하고 있습니다. 급한 마음으로 이미 한 번 만들었던 코드를 다시 쓰고 있으면 정말 돌아버릴 것 같습니다.

정리하면, 장비가 죽어서 잃은 것은 없었습니다. 잃은 것은 마지막 push 이후에 만든 모든 것이었습니다. 백업의 공백이 곧 손실의 크기였습니다.

스키마 버전 하나에 사용자 데이터가 걸려 있었습니다

코드를 복구했다고 바로 배포할 수는 없었습니다. 앱에는 로컬 데이터베이스가 있고, Room을 쓰고 있습니다. 만약 사라진 구간에서 DB 스키마 버전을 올렸다면, 스키마 버전이 낮은 옛 코드를 그대로 배포하는 순간 이미 설치된 사용자들의 데이터가 어떻게 될지 알 수 없습니다. 마이그레이션 경로가 어긋나면 앱이 죽거나, 최악의 경우 데이터가 초기화됩니다.

그래서 배포 전에 대조부터 했습니다. Play Console에서 현재 프로덕션 라이브 버전을 내려받아, 깃에서 복구한 소스와 DB 스키마 버전 및 마이그레이션 범위를 비교했습니다. 다행히 두 쪽이 동일해서 한숨 돌렸습니다.

Play Console 프로덕션 배포본과 깃에서 복구한 소스의 Room 스키마 버전을 대조하는 절차
복구한 소스를 배포하기 전에 사용자 데이터베이스의 스키마 버전부터 대조한다

이 경험에서 배운 것은 단순합니다. 복구한 코드가 “돌아간다”는 것과 “배포해도 된다”는 것은 다릅니다. 사용자 기기에 이미 존재하는 데이터베이스는 우리가 백업하지 못한 자산이고, 되돌릴 수도 없습니다. Room의 마이그레이션 처리 방식은 Android 공식 문서에 정리되어 있으니, 복구 상황이 아니더라도 스키마 JSON을 저장소에 커밋해 두는 설정은 미리 켜 두는 편이 좋습니다.

개발자 백업은 복구 가능성으로 순서를 정합니다

모든 파일을 똑같이 정성껏 지킬 수는 없습니다. 그러면 결국 아무것도 지키지 못합니다. 기준을 하나만 세우면 됩니다. 잃었을 때 되돌릴 수 있는가입니다.

복구 가능성에 따라 개발자 백업 항목을 1등급부터 3등급까지 나눈 우선순위 표
잃었을 때 되돌릴 수 있는지에 따라 백업의 순서와 방법이 달라진다
  • 1등급 · 되돌릴 수 없는 것: 업로드 키스토어, 스키마와 마이그레이션 이력, 서버에만 있는 사용자 데이터. 사라지면 돈으로도 시간으로도 복구되지 않습니다.
  • 2등급 · 되살릴 수 있지만 비용이 큰 것: 소스 코드, 백엔드 코드, 디자인 원본, 스토어 자산. 다시 만들 수는 있지만 그 시간이 곧 손해입니다.
  • 3등급 · 다시 발급하면 되는 것: 서드파티 API 키, 토큰, 개발용 인증서. 값 자체보다 어디서 발급했고 어떤 계정에 묶여 있는지가 중요합니다.

이 순서대로 보면, 가장 먼저 챙겨야 할 것은 용량이 큰 프로젝트 폴더가 아니라 수백 KB짜리 키스토어 파일입니다.

반드시 백업해야 할 7가지

1. 키스토어와 서명 자격 증명

이번 사고에서 저를 살린 것이 이것 하나였습니다. 업로드 키스토어를 잃으면 코드가 멀쩡해도 같은 앱으로 업데이트를 올릴 수 없습니다. 백업해야 할 것은 .jks 파일 하나가 아니라 세트입니다.

  • 키스토어 파일과 키 별칭(alias)
  • 키스토어 비밀번호와 키 비밀번호(서로 다를 수 있습니다)
  • keystore.properties처럼 경로와 값을 담은 설정 파일
  • 키 지문(SHA-1, SHA-256) — 지도, 로그인 같은 외부 SDK 등록에 필요합니다

보관 위치는 반드시 저장소 바깥이어야 합니다. 이 부분은 키스토어 생성과 앱 서명을 다룬 글에서 폴더 구조까지 정리해 두었습니다. Play 앱 서명을 사용 중이라면 업로드 키를 잃어버렸을 때 업로드 키 재설정을 요청할 수 있지만, 심사와 대기 시간이 걸립니다. ANR이 쏟아지는 상황에서 며칠을 기다릴 수 있는 사람은 없습니다.

2. 소스 코드 — 백업의 단위는 커밋이 아니라 push

이번에 가장 크게 데인 항목입니다. 커밋은 백업이 아닙니다. .git 디렉터리도 결국 같은 디스크 안에 있습니다. 디스크가 죽으면 커밋 이력도 함께 죽습니다.

원격 저장소와 로컬 저장소의 커밋을 비교해 push하지 않은 구간이 사라지는 것을 보여주는 그림
커밋은 로컬 디스크 안의 기록이고, push를 해야 다른 장치에 사본이 생긴다

그래서 기준을 바꿨습니다. “기능이 끝나면 push”가 아니라 “작업을 멈추면 push”입니다. 커밋 메시지가 마음에 들지 않아도, 브랜치가 지저분해도 일단 올립니다. 정리는 나중에 할 수 있지만 사라진 코드는 정리할 수도 없습니다.

  • 작업용 브랜치도 원격에 올려 둡니다. 로컬 전용 브랜치와 stash는 디스크와 운명을 같이합니다.
  • GitHub 같은 외부 서비스와 Gitea 같은 자체 호스팅을 함께 쓴다면, 원격을 두 개 등록해 같은 브랜치를 양쪽에 올려 둘 수 있습니다.
  • 자체 호스팅 Gitea가 그 개발 머신 위에서 돌고 있다면 그것은 백업이 아닙니다. 서버와 작업 PC가 같은 전원, 같은 방, 같은 디스크를 쓰고 있는지 확인해야 합니다.
  • 릴리스한 버전마다 태그를 붙여 둡니다. 이번처럼 “지금 배포된 버전이 어느 커밋인지” 찾아야 할 때 태그 하나가 시간을 크게 줄여 줍니다.

저장소를 처음 준비하는 단계라면 프로젝트와 원격 저장소를 준비하는 글에서 초기 설정을 함께 보시면 좋습니다.

3. 서드파티 API 키와 계정 접근 정보

API 키는 대부분 재발급이 됩니다. 그래서 위험도가 낮아 보이지만, 실제로 발목을 잡는 것은 키 값이 아니라 기억입니다. 어느 서비스를 썼는지, 어떤 계정으로 가입했는지, 어떤 요금제였는지, 어디에 어떤 이름으로 등록했는지가 그 PC의 브라우저와 설정 파일에만 남아 있으면 곤란해집니다.

  • 사용 중인 서드파티 서비스 목록과 각각의 가입 계정
  • 키를 발급한 콘솔 주소와 재발급 경로
  • 키에 걸어 둔 제한(패키지명, SHA-1 지문, 허용 도메인, IP)
  • 결제 수단이 연결된 서비스와 갱신 주기

키 값 자체는 비밀번호 관리자에 넣고, “무엇을 쓰고 있는지”는 문서로 남깁니다. 이 목록은 사고가 났을 때뿐 아니라 개인정보처리방침을 쓸 때도 그대로 쓰입니다. 반대로 키를 저장소에 커밋하는 방식은 백업이 아니라 유출입니다.

4. 백엔드와 프록시 소스, 그리고 배포 설정

앱이 외부 API를 직접 부르지 않고 프록시 서버를 거치도록 만들었다면, 그 서버 코드는 앱만큼 중요합니다. 프록시가 죽으면 앱은 설치되어 있어도 아무 일도 하지 못합니다.

  • 서버 애플리케이션 소스를 앱과는 별도 저장소로 두고 함께 push합니다.
  • compose.yaml, 웹서버 설정, 인증서 발급 방식 같은 배포 구성 파일도 저장소에 넣습니다.
  • 환경 변수는 값 대신 .env.example처럼 키 이름과 설명만 남깁니다. 실제 값은 비밀번호 관리자에 둡니다.
  • DB를 직접 운영한다면 정기 덤프를 서버 바깥으로 옮깁니다. 서버 안에만 있는 덤프는 서버가 죽으면 함께 사라집니다.

관리형 백엔드를 쓰는 경우에도 마찬가지입니다. 테이블 정의, 보안 정책, 함수 코드는 콘솔 화면에만 두지 말고 파일로 내보내 저장소에 넣어 두는 편이 안전합니다. 구성 방식은 Supabase 앱 백엔드 글에서 다룬 데이터 흐름을 참고하실 수 있습니다.

5. DB 스키마와 마이그레이션 이력

앞에서 이야기한, 이번에 가장 아찔했던 항목입니다. 사용자 기기의 데이터는 우리가 백업할 수 없습니다. 그래서 우리가 지켜야 하는 것은 데이터가 아니라 데이터를 안전하게 옮기는 경로입니다.

  • Room 스키마 JSON을 내보내도록 설정하고, 생성된 파일을 저장소에 커밋합니다.
  • 마이그레이션 코드는 지우지 않고 계속 쌓아 둡니다. 오래된 버전에서 올라오는 사용자가 남아 있습니다.
  • 릴리스한 버전과 스키마 버전을 함께 기록해 둡니다. 복구 상황에서 대조표 역할을 합니다.
  • 파괴적 마이그레이션 설정을 편의로 켜 두지 않습니다. 사고가 아니라 설계로 데이터를 지웁니다.

6. 앱 리소스와 스토어 운영 자산

코드만 있으면 앱을 다시 만들 수 있을 것 같지만, 막상 릴리스를 하려면 코드가 아닌 파일들이 계속 필요합니다. 이 자산들은 대부분 “어딘가에 있겠지” 상태로 방치되어 있습니다.

  • 아이콘과 그래픽의 원본 파일(내보낸 PNG 말고 편집 가능한 원본)
  • 스토어 등록 정보: 설명 문구, 스크린샷, 피처 그래픽, 카테고리, 태그
  • 난독화 매핑 파일 — 버전별로 보관하지 않으면 지금 쏟아지는 크래시 로그를 읽을 수 없습니다
  • 개인정보처리방침과 이용약관 페이지의 원본 파일과 공개 주소
  • 릴리스 노트, 테스터 목록, 폰트 라이선스처럼 다시 모으기 번거로운 자료

ANR과 크래시가 쏟아지는 상황에서 매핑 파일이 없으면 스택 트레이스가 난독화된 채로 보입니다. 원인을 찾는 시간이 몇 배로 늘어납니다. 릴리스할 때마다 AAB, 매핑 파일, 태그를 한 폴더에 묶어 두는 습관 하나로 해결됩니다.

7. 개발 환경과 작업 맥락

마지막은 사고를 겪고 나서야 목록에 추가한 항목입니다. 새 PC에 소스와 키스토어를 다 옮겨 놓고도, 예전처럼 일하기까지는 시간이 더 걸렸습니다. 사라진 것이 코드만이 아니었기 때문입니다.

  • 셸 설정과 별칭, 에디터·IDE 설정, 자주 쓰는 스크립트
  • AI 코딩 도구에 준 지침 파일(CLAUDE.md, AGENTS.md)과 프롬프트 모음
  • ROADMAP과 작업 메모 — “다음에 뭘 하려고 했는지”가 여기 들어 있습니다
  • SSH 키와 서버 접속 정보, 각 서비스의 2단계 인증 백업 코드

특히 2단계 인증 복구 코드를 그 PC에만 저장해 두었다면, 장비가 죽는 순간 계정에 못 들어가는 일까지 겹칩니다. 백업을 꺼내려면 계정에 로그인해야 하는데, 로그인 수단이 그 안에 있는 구조는 피해야 합니다.

작업 맥락 문서는 저장소에 함께 넣어 두면 코드와 같은 주기로 자동 백업됩니다. AI 코딩 도구를 쓰고 있다면 이 문서들이 곧 생산성이므로, 코드만큼의 우선순위를 줄 만합니다.

3-2-1 규칙과, 한 번은 해 봐야 하는 복구 리허설

항목을 정했다면 남은 것은 어디에 몇 벌을 둘지입니다. 오래된 3-2-1 규칙이 여전히 쓸모 있습니다. 사본 3벌, 서로 다른 매체 2가지, 그중 1벌은 다른 장소에 둡니다. 제 경우 외장 디스크를 같은 책상 위에 두고 있었는데, 과열이든 정전이든 도난이든 그 방에서 일어나는 사고는 두 사본을 한꺼번에 가져갑니다.

3-2-1 백업 규칙과 새 PC에서 진행하는 복구 리허설 4단계를 정리한 도식
사본을 만드는 일까지가 절반이고, 복구해 보는 일까지가 백업이다

그리고 사본을 만드는 것보다 중요한 마지막 단계가 있습니다. 복구를 실제로 해 보는 일입니다. 저는 키스토어를 백업해 두었지만, 그 키스토어로 새 환경에서 릴리스 빌드를 만들어 본 적은 없었습니다. 다행히 잘 동작했을 뿐입니다.

  1. 새 PC 한 대만 있다고 가정하고 원격 저장소에서 클론합니다.
  2. 백업해 둔 키스토어와 비밀 값을 배치합니다.
  3. 서명된 릴리스 빌드가 끝까지 만들어지는지 확인합니다.
  4. 현재 배포본과 서명 지문, DB 스키마 버전이 같은지 대조합니다.

반년에 한 번, 한 시간이면 충분합니다. 이 리허설을 통과하지 못하는 백업은 아직 백업이 아니라 그냥 파일 모음입니다.

마무리

지금도 저는 사라진 구간을 다시 만들고 있습니다. 리뷰 평점은 이미 떨어졌고, 그 시간은 돌아오지 않습니다. 그런데 돌아보면 이 사고에서 잃은 것과 지킨 것의 차이는 기술이 아니었습니다. 키스토어는 예전에 한 번 따로 복사해 두었기 때문에 살았고, 소스는 push를 미뤘기 때문에 잃었습니다. 그 정도의 차이입니다.

15년 된 장비를 에어컨 없는 방에서 돌린 것은 분명 무리였습니다. 하지만 장비는 언젠가 죽습니다. 새 PC를 사도 마찬가지고, 클라우드에 올려도 계정이 잠기는 날이 있습니다. 그래서 백업은 장비를 믿지 않기로 하는 결정에 가깝습니다.

오늘 당장 할 수 있는 일은 세 가지입니다. 키스토어 세트를 저장소 바깥의 안전한 곳에 한 벌 더 복사하고, 지금 작업 중인 브랜치를 원격에 push하고, 쓰고 있는 서드파티 서비스 목록을 문서 하나에 적어 두는 것입니다. 전부 합쳐 30분이면 됩니다. 저는 그 30분을 아끼려다 몇 주를 다시 쓰고 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다