RN 운영 3대 착각
핫 업데이트를 도입하기 전, 저도 비슷하게 생각했던거 같아요.
첫 번째, JS만 바꾸면 괜찮아
이 말은 로컬 개발 환경에서는 맞지만 운영에서는 절반만 맞습니다.
네이티브 모듈이 하나라도 변경되었는데 구버전 바이너리에 새로운 JS를 올리면 어떻게 될까요?
정답은 “기기마다 다르게 망한다”입니다...!
재현도 어렵고, 로그도 애매하고, 슬랙에는 “특정 유저만 크래시” 가 올라옵니다.
그때 깨닫습니다.
JS는 독립적이지 않습니다. 그냥 덜 독립적일 뿐입니다.
두 번째, 자동 업데이트가 제일 편하다
앱 실행 시 자동으로 체크하고 자동으로 반영하면 운영이 편할 것처럼 보입니다.
하지만 실제로는 이렇게 됩니다.
결제 플로우 도중 reload
특정 화면에서 state shape mismatch
“왜 갑자기 앱이 꺼졌다 켜졌지?”라는 리뷰
자동은 편하지만, 언제 터질지 모르는 자동은 편하지 않습니다.
그래서 우리는 자동을 버리고 통제를 선택했습니다.
세 번째, 핫 업데이트는 배포 속도를 빠르게 올려준다
뭐 맞는 말입니다. 하지만 속도도 속도지만 추가적으로 바뀌는 건 운영 책임의 무게입니다.
스토어 심사를 거치면 최소한 한 번의 필터는 통과합니다. 핫 업데이트는 그 필터를 우리가 직접 책임져야 합니다.
즉각적인 버그 업데이트로 빈번하게 쓰다가 하나의 실수로 운영에서 큰버그를 발생시킬 수 있습니다.
속도는 빨라졌지만, 검증 프로세스는 다른 의미로 더 엄격해졌습니다.
겪었던 장애 사례 (각색)
한 번은 인증 관련 로직을 수정한 적이 있습니다. 네이티브 안 건드렸고, JS 수정만 있었습니다.
“이건 핫 업데이트로 충분하겠네.”
배포했습니다.
몇 시간 뒤, 일부 안드로이드 기기에서 로그인 이후 앱이 즉시 종료된다는 cs가 들어왔습니다.
원인은 단순했습니다.
최신 번들에서는 토큰 저장 로직이 변경됨
구버전 바이너리에서는 AsyncStorage 초기화 타이밍이 달랐음
결과는 race condition...
진짜 화가나는건 그런건 QA에서는 한번도 재현되지 않았고, 운영 특정 기기에서만 발생했습니다.
그때 배운 건 이것입니다.
"네이티브 안 건드렸으니까 괜찮아"가 아니라, 안 건드렸어도 충분히 엮일 수 있다는 걸 그때 제대로 배웠습니다. 그 뒤로 바이너리 버전 기반으로 매칭을 강제했습니다. 자유도는 줄었는데 cs 들어올 확률도 같이 줄더라고요.
CodePush와 비교하며 느낀 점
많은 팀이 쓰고 있고 저도 써봤습니다. 설정 간단하고 파이프라인도 잘 되어있고 도입 빠른 건 확실합니다.
하지만 운영 관점에서 느낀 건 조금 달랐습니다.
CodePush는 “잘 만들어진 자동화 도구”입니다. 우리가 필요했던 건 “통제 가능한 운영 구조”였습니다.
자동 sync 기반 구조는 편리하지만, 적용 시점과 정책을 세밀하게 가져가려면 결국 추가 설계가 필요합니다.
그래서 우리는 도구 중심이 아니라 정책 중심으로 아키텍처를 설계했습니다.
CodePush가 별로라는 게 아닙니다. 다만 핫 업데이트는 어떤 도구를 쓰느냐보다 운영을 어떻게 설계하느냐가 먼저라는 걸 느꼈습니다.
그래서 뭐가 남았나면
핫 업데이트 넣고 나서 제일 좋았던 건 배포가 빨라진 게 아니었습니다.
언제 적용할지, 어떤 버전까지 허용할지, 터지면 어떻게 되돌릴지. 이런 판단을 우리가 직접 할 수 있게 된 거였습니다.
핫 업데이트는 결국 배포 도구가 아니라 운영 책임을 팀이 직접 들고 오는 구조더라고요.
덕분에 금요일 밤에 발견된 버그를 토요일 아침에 고칠 수 있게 됐습니다.
물론, 그 토요일 아침이 평화로울 거라는 보장은 없지만요.
