ONEDiary가 먼저 휴대폰에 저장하는 이유
신호가 필요한 일기 앱은 지하철에서 사용을 멈추게 됩니다. 네트워크 호출이 기록을 기다리게 하지 않도록 저장 계층을 어떻게 구성했는지 소개합니다.
대부분의 일기 앱은 계정 화면에서 시작합니다. ONEDiary는 빈 페이지에서 시작합니다. 이것은 엔지니어링보다 먼저 내려진 제품 결정이지만, 저장 계층도 그 결정에 맞게 구성되어야 오래 유지할 수 있습니다. 그래서 이 부분은 가장 먼저 설계했고 가장 적게 바꿨습니다.
원칙: 기록은 네트워크를 기다리지 않는다
저장 계층이 지켜야 할 규칙은 하나입니다. 저장을 누르면 다른 일이 일어나기 전에 기록이 안전하게 보존되어야 합니다. 업로드 대기열에만 넣거나 요청이 진행되는 동안 낙관적으로 그리는 것이 아니라, 기기의 디스크에 로컬 트랜잭션으로 기록하고 그 자리에서 성공 또는 실패를 결정합니다.
이 글의 나머지 내용은 모두 이 원칙에서 나옵니다.
Room이 기준 데이터다
ONEDiary는 기기의 Room 데이터베이스에 기록을 보관합니다. UI는 네트워크에서 읽지 않습니다. 화면은 Kotlin Flow를 통해 Room을 관찰하므로 타임라인, 달력, 검색이 모두 같은 로컬 테이블을 그리고 기록이 저장되는 순간 함께 갱신됩니다.
이 차이는 정확히 짚을 필요가 있습니다. 흔히 오프라인 지원은 서버를 기준으로 두고 기기에는 무효화될 수 있는 캐시를 둔 방식으로 만들어집니다. 피드에는 괜찮은 설계입니다. 하지만 일기에서는 맞지 않습니다. 내가 쓴 내용은 무엇의 캐시가 아니라 원본이고, 사본이 아예 없을 수도 있기 때문입니다.
- 읽기는 언제나 Room에서 옵니다. 연결 상태에 따라 로딩되는 화면이 없습니다.
- 쓰기는 Room에 커밋되고, 별도 계층이 기기 밖으로 보낼 내용이 있는지 결정합니다.
- 충돌은 로컬 데이터를 기준으로 해결하며, 쓰기를 막는 방식으로 해결하지 않습니다.
Firestore는 집이 아니라 미러다
로그인하고 데이터 동기화를 켜면 ONEDiary는 로그인한 기기들이 수렴하도록 기록을 Firestore에 미러링합니다. 문장의 순서가 중요합니다. 로그인은 선택 사항이고, 동기화는 별도의 스위치이며, 미러는 로컬 데이터베이스에서 파생됩니다.
따라서 동기화 계층은 느리거나 실패하거나 재시도할 수 있고, 그 과정이 기록 경험에 드러나지 않아도 됩니다. 업로드 실패는 백그라운드 재시도일 뿐입니다. 기록이 사라지거나 저장 버튼이 막히는 일은 없습니다.
오프라인 모드는 실제로 무엇을 하나
오프라인 모드라는 설정은 동기화 상태를 숨기는 UI 토글처럼 보이기 쉽지만 그렇지 않습니다. 켜면 Firestore 동기화를 멈추고, 대기 중인 변경 내용을 다시 시작할 때까지 기기에 보관합니다.
연결되어 있다는 것과 연결을 사용하고 싶다는 것은 다른 질문이고, 두 번째 답은 사용자만 정할 수 있기 때문에 존재하는 기능입니다. 비싼 로밍 요금, 아직 미러링하고 싶지 않은 기록, 잠시 네트워크를 조용히 두고 싶은 상황 모두 로그아웃하거나 동기화 설정을 잃지 않고 멈출 이유가 됩니다.
다시 끄면 대기 중인 변경 내용이 백그라운드에서 처리됩니다. 그동안 버려지는 내용은 없습니다.
기본값이 설계를 말해 준다
새로 설치한 앱이 가질 수 있는 세 가지 상태를 나열해 보면 설계의 순서가 보입니다.
- 새로 설치한 상태계정 없음, 동기화 없음, AI 접근 없음. 기록하고 읽고 검색하고 사진을 첨부하고 달력을 볼 수 있습니다. 앱은 이 상태로 제공되며 많은 사용자는 계속 이 상태로 사용합니다.
- 로그인 후 데이터 동기화 켜짐로그인한 기기 사이에서 기록이 수렴합니다. 언제든 끄거나 오프라인 모드로 잠시 멈출 수 있습니다.
- AI 접근 허용별도의 명시적인 권한입니다. 허용한 뒤에만 리포트와 일기 채팅이 기록을 읽을 수 있습니다. 동기화를 켜도 AI 접근은 켜지지 않습니다.
이 중 어느 것도 설정이라는 이름을 쓴 업셀이 아닙니다. 사용자가 결정하기 전에는 모두 꺼져 있고, 켰던 화면에서 다시 되돌릴 수 있습니다.
우리에게 따르는 비용
솔직히 말하면 로컬 우선 구조는 일이 줄어드는 것이 아니라 늘어나는 선택입니다. 확인할 수 없는 기기에 사는 스키마의 마이그레이션을 관리해야 하고, 잘못된 행을 서버 스크립트로 고칠 수도 없습니다. 받지 않는 데이터를 기기 간 전체 텍스트 검색하는 일처럼 중앙 데이터베이스라면 쉬운 기능도 더 어렵거나 아예 선택지에서 빠집니다.
되돌릴 수 없는 것을 지키는 앱이라면 그 비용을 지불할 가치가 있다고 생각합니다. 다만 비용은 실제로 존재하고, 모든 릴리스에서 지불해야 합니다.
직접 사용해 보세요.
Google Play에서 무료로 받을 수 있습니다. Android 10 이상에서 계정 없이 기록을 시작하세요.