Firebase에서 전체 조회를 멈추고, 변경분만 동기화하기까지
빠른 출시를 위해 택한 서버리스 구조에서 반복 조회 비용을 발견하고, 콘텐츠 버전으로 변경된 작물 정보만 가져오게 바꾼 기록.
2026년 8월 23일
다조아는 짧은 기간 안에 만들어야 하는 앱이었다. 처음부터 서버를 크게 구성하기보다 Flutter와 Firebase로 시작했다. 관리자가 작물 정보와 병해충 정보, 유튜브 영상을 등록하면 앱에서 바로 보여 주는 구조였다. 처음에는 이 선택이 맞았다. 운영 기능을 빨리 만들고, 인프라를 따로 관리하지 않아도 됐기 때문이다.
문제는 “빨리 만든 첫 구조”를 그대로 두었을 때 생겼다.
처음에는 앱을 열면 전부 가져왔다
작물 수가 많지 않으니 앱을 열 때마다 전체 목록을 내려받는 방식으로 시작했다. 구현도 단순하다. 목록을 가져오고, 로컬에 보여 주면 끝이다.
그런데 개발 중 핫 리로드를 반복하면서 같은 조회가 계속 발생했다. 사용자가 많지 않은 개발 단계에서도 데이터베이스 사용량이 늘어나는 모습이 보였다. 실제 출시 뒤에는 앱을 여는 사용자 수만큼 전체 조회가 반복될 수 있었다.
문제는 데이터 양만이 아니었다. 작물 하나의 설명을 수정해도, 앱은 바뀌지 않은 다른 작물까지 다시 받았다. 서버리스라고 해서 비용을 신경 쓰지 않아도 되는 것은 아니었다.
시간 비교는 첫 개선이었지만 충분하지 않았다
처음 떠올린 해결은 마지막으로 데이터를 받은 시간과 관리자 업데이트 시간을 비교하는 방식이었다. 업데이트가 없으면 로컬 데이터를 그대로 쓰고, 업데이트가 있을 때만 다시 받는다.
이것만으로도 매 실행마다 전체 데이터를 받는 문제는 줄었다. 하지만 작물 하나를 고쳐도 전체 목록을 다시 가져와야 했다. “업데이트가 있었는가”만 알 수 있을 뿐, “무엇이 바뀌었는가”는 알 수 없었기 때문이다.
콘텐츠 버전을 기준으로 바꾸기
그래서 앱 배포 버전과 별개로 콘텐츠 동기화 버전을 뒀다. 관리자가 작물이나 병해충 정보를 수정할 때마다 전체 콘텐츠 버전을 하나 올리고, 변경된 데이터에도 그 버전을 기록한다.
현재 콘텐츠 버전: 14
앱이 마지막으로 동기화한 버전: 10
가져올 대상: syncVersion 11 ~ 14의 데이터만
앱은 먼저 현재 콘텐츠 버전만 확인한다. 로컬의 마지막 동기화 버전과 같으면 아무것도 받지 않는다. 다르다면 그 사이에 변경된 작물 정보만 조회하고, 반영이 끝난 뒤 마지막 동기화 버전을 갱신한다.
이 방식의 핵심은 작물마다 별도 확인 요청을 보내는 것이 아니다. 변경 버전을 조건으로 한 번 조회해, 실제로 바뀐 항목만 받는 것이다. 전체 100개 중 3개만 바뀌었다면 3개만 내려받는다. 반대로 모든 작물이 바뀌었다면 전체 조회와 다르지 않다. 그래서 이 구조는 데이터가 대부분 그대로이고 일부만 수정되는 콘텐츠 서비스에 잘 맞는다.
비용을 줄이는 것과 잘못된 데이터를 막는 것
버전 기반 동기화는 조회량만 줄이는 장치가 아니다. 앱이 어떤 시점의 데이터를 갖고 있는지 분명하게 만들어 준다. 네트워크가 중간에 끊겼다면 마지막 동기화 버전을 올리지 않고, 다음 실행 때 같은 변경분을 다시 받을 수 있다.
다만 삭제된 항목도 같이 생각해야 했다. 단순히 문서를 지우면 이전 앱은 무엇이 사라졌는지 알 수 없다. 그래서 실제 서비스라면 삭제 이벤트도 버전이 있는 변경 목록으로 남기거나, 삭제 표시를 내려준 뒤 로컬에서 정리하는 기준까지 같이 둬야 한다.
다조아에서 얻은 결론은 거창하지 않다. 빠른 출시를 위해 단순한 구조를 택하는 것은 괜찮다. 대신 반복 호출되는 지점이 어디인지 일찍 보고, 사용량이 늘기 전에 변경분만 움직이는 구조로 고칠 수 있어야 한다.