Flutter 레시피 목록에서 여섯 언어를 읽던 이유: 필요한 언어만 남긴 선택

VidDish의 레시피 목록은 사용자가 고른 한 언어를 보여주면서도, 다른 언어의 재료와 조리순서까지 함께 읽는 구조였습니다. 한국어로 목록을 보는 사용자가 영어·일본어 등 다른 언어의 본문도 받아야 했던 것입니다. 레시피 하나에 여러 번역을 모아 둔 원본 문서를 목록에서도 그대로 사용했기 때문입니다.

이 구조에서는 카드 수가 늘어날수록 화면에 쓰지 않는 자료도 함께 늘어납니다. 다국어 지원을 위해 보관할 필요가 있는 내용이지만, 모든 사용자가 목록을 열 때마다 전부 받을 필요는 없습니다. 이 문제를 해결하면서 고민한 것은 무엇을 덜어낼지, 그리고 덜어낸 뒤 사용자의 다음 행동이 달라지는지였습니다.

한 문서를 여러 화면에서 쓰면 처음에는 편하다

레시피 원본에는 제목과 썸네일뿐 아니라 언어별 재료, 조리순서, 분류, 저장 수 같은 정보가 함께 들어 있습니다. 목록도 이 문서를 읽으면 화면에 필요한 값을 꺼내 쓰기 쉽습니다. 카드를 눌렀을 때 내용을 보여주거나 레시피를 저장할 때도 이미 받은 자료를 사용할 수 있습니다.

여러 언어의 내용을 한 원본에 모아 두는 것에도 이유가 있습니다. 같은 영상의 한국어 레시피와 영어 레시피가 한 레시피의 번역이라는 관계를 유지할 수 있습니다. 문제는 원본의 편리한 구조를 목록 조회에도 그대로 적용했을 때 생겼습니다. 앱 화면에서 한 언어만 고른다고 해서, 기기로 가져오는 문서의 다른 언어 내용까지 사라지지는 않습니다.

예를 들어 여섯 언어의 변형이 있는 레시피라면 한국어 사용자의 목록에서는 그중 한 벌을 사용합니다. 하지만 기존 조회는 여섯 벌을 함께 가져왔습니다. 이 사례에서 먼저 줄일 대상은 사용자가 보지 않는 다른 언어의 본문이었습니다.

제목과 사진만 남기는 방법도 있었지만

목록을 가볍게 만든다고 하면 제목·사진·조리 시간 같은 요약만 따로 두는 방법을 떠올릴 수 있습니다. 카드를 누른 뒤 재료와 조리순서를 받으면 처음 가져오는 자료는 더 작아집니다.

그 대신 사용자의 다음 행동에는 조회가 하나 더 필요해집니다. 미리보기에서 재료를 확인하려고 눌렀는데 상세 내용이 아직 도착하지 않았다면 기다리는 화면을 처리해야 합니다. 저장 버튼을 눌렀을 때도 저장할 본문을 다시 읽는 과정과 그 과정의 실패를 다뤄야 합니다. 네트워크가 끊긴 상황에서는 목록은 보이지만 그 다음 행동에 필요한 내용이 없을 수 있습니다.

VidDish에서는 미리보기와 저장에 쓸 현재 언어의 재료·조리순서를 카드 자료에 남겼습니다. 목록을 더 작게 만드는 정도와, 이미 본 레시피를 확인하고 저장하는 흐름 사이에서 선택한 경계입니다. 상세 내용을 완전히 분리하는 방법도 유효하지만, 그 방법을 쓰려면 추가 로딩과 실패 상황까지 함께 기획해야 합니다.

기기에 이미 받아 둔 카드가 캐시에 있으면 그 안의 재료와 조리순서도 함께 사용할 수 있습니다. 다만 아직 받은 적 없는 카드나 다른 언어의 내용까지 오프라인에서 보장되는 것은 아닙니다. 어떤 자료를 미리 받아 놓을지와 어떤 기능을 오프라인에서도 제공할지는 별도로 정해야 합니다.

원본은 유지하고, 언어별 카드 문서를 만들었다

수정 후에는 레시피 원본에서 실제로 제공하는 언어마다 카드 문서를 만듭니다. 한국어 카드에는 한국어 변형 한 벌을, 영어 카드에는 영어 변형 한 벌을 담습니다. 목록은 사용자가 고른 언어의 카드 문서를 읽습니다.

자료 기존 목록에서 받던 내용 수정 후 해당 언어 카드에서 받는 내용
제목·재료·조리순서 원본에 있는 여러 언어의 변형 선택한 언어의 변형 한 벌
썸네일·분류·저장 수 등 원본의 공통 정보 카드 표시·정렬 등에 필요한 공통 정보
다른 언어의 본문 화면에서 쓰지 않아도 함께 받음 그 언어의 카드 문서에 따로 보관

이렇게 하면 한국어로 목록을 보는 동안 다른 언어의 조리순서를 함께 받을 필요가 줄어듭니다. 동시에 한국어 카드 안에는 미리보기와 저장에 사용할 내용이 남습니다. 원본 문서는 여러 언어를 모아 보관하는 역할을 계속 맡고, 카드 문서는 한 언어의 목록과 그 다음 행동에 맞게 구성됩니다.

여섯 언어로 번역된 김치찌개 레시피 한 장을 떠올려 보면 차이가 분명합니다. 기존에는 목록에서 원본의 여섯 언어 내용을 받고 한국어만 골라 보여줬습니다. 수정 후에는 한국어 카드 한 장을 읽고, 미리보기를 열거나 저장할 때도 그 안의 한국어 재료와 조리순서를 사용합니다. 이 예시는 가져오는 자료의 구성이 어떻게 바뀌는지 설명한 것이며, 파일 크기나 로딩 시간의 실측 결과는 아닙니다.

언어별 문서를 만들면서 레시피의 정체성도 유지해야 했습니다. 한국어 카드와 영어 카드는 문서가 두 개지만, 저장·숨김·이벤트 처리에서는 같은 원본 레시피를 가리켜야 합니다. 카드 문서의 언어 구분을 그대로 레시피 ID처럼 사용하면 저장한 레시피와 목록의 레시피를 서로 다른 것으로 다룰 수 있습니다. 현재 코드는 카드 문서에서 원래 레시피 ID를 복원해 사용합니다.

목록 조회에도 언어 조건을 넣습니다. 이 조건이 빠지면 같은 레시피의 번역 카드들이 인기 목록의 여러 자리를 차지할 수 있습니다. 원본에 해당 언어의 번역이 없다면 그 언어의 카드를 만들지 않습니다. 그래서 목록이 비었을 때는 레시피가 없는지와 선택한 언어의 카드가 없는지를 구분해 살펴봐야 합니다.

작아진 목록의 대가는 갱신 관리다

자료를 복제하면 읽는 쪽은 편해지지만, 쓰는 쪽에서 맞춰야 할 내용이 늘어납니다. 원본 제목을 바꾸면 카드 제목도 바뀌어야 하고, 저장 수가 변하면 카드가 정렬에 사용하는 값에도 반영해야 합니다. 레시피를 숨겼거나 번역 하나를 삭제했을 때는 이전 카드가 목록에 남아 있지 않도록 처리해야 합니다.

현재 구현은 원본 변경을 받아 카드 문서를 갱신하고, 더 이상 필요하지 않은 언어의 카드를 삭제합니다. 기존 카드와 새 내용이 같으면 다시 쓰지 않는 비교도 합니다. 하지만 내용이 실제로 바뀌었다면 관련 카드들의 갱신은 필요합니다. 언어별 카드가 늘어난 만큼 저장 공간과 동기화 작업도 추가됩니다.

또 원본과 카드가 항상 같은 순간에 바뀐다고 가정할 수 없습니다. 현재는 원본 변경 후 트리거가 카드 반영을 수행하고, 그 작업이 실패하면 로그를 남깁니다. 원본 저장 성공만 보고 카드까지 갱신됐다고 판단해서는 안 됩니다. 기존 자료를 카드로 채우는 작업과, 누락된 카드를 다시 만드는 재색인 경로도 함께 관리해야 합니다.

특히 삭제와 숨김은 생성만큼 중요합니다. 새 레시피가 목록에 올라오는지만 확인하면 이미 지운 번역이 남거나 수정 전 제목이 계속 표시되는 상황을 놓칠 수 있습니다. 문서를 분리한 설계를 검토할 때는 ‘어떻게 만들지’에 더해 원본이 바뀌거나 사라졌을 때 복제본을 어떻게 정리할지까지 설명할 수 있어야 합니다.

자료가 작아졌다는 것과 비용·속도는 따로 확인한다

현재 코드와 테스트에서 확인할 수 있는 변화는 카드에 다른 언어 변형을 넣지 않고, 해당 언어의 재료·조리순서를 유지한다는 것입니다. 문서의 구성 자체가 달라졌다는 점은 분명합니다. 이 글에서는 개발 기록의 크기 수치를 실제 사용자에게 전송된 양이나 체감 속도 개선 수치로 제시하지 않습니다.

같은 개수의 문서를 읽더라도 문서 안의 내용이 줄면 받는 자료는 작아질 수 있습니다. 그러나 그것만으로 문서 읽기 횟수도 같은 비율로 줄었다고 계산할 수는 없습니다. Firestore는 문서·인덱스 읽기와 네트워크 전송 등을 각각 과금 항목으로 다룹니다. 카드 문서를 만들고 갱신하는 비용까지 포함해 봐야 전체 비용을 비교할 수 있습니다. Firestore 과금 공식 안내

속도를 비교할 때도 같은 언어와 같은 카드 수에서, 캐시가 있는 경우와 처음 읽는 경우를 나눠 봐야 합니다. 목록이 표시되는 시간에 더해 미리보기를 열거나 저장을 완료하는 시간도 확인해야 합니다. 목록만 빨라지고 다음 행동에서 기다리게 된다면 그 변화까지 사용 경험에 포함되기 때문입니다.

이 방식을 검토할 만한 조건은 목록을 자주 읽고, 그때마다 가져오는 내용 중 화면에서 쓰지 않는 부분이 많은 경우입니다. 반대로 한 언어만 제공하거나 문서가 이미 작고 변경이 잦다면, 복제본을 유지하는 부담에 비해 덜어낼 내용이 적을 수 있습니다. 먼저 실제 문서에서 목록과 다음 행동에 필요한 부분이 얼마나 되는지 살펴본 뒤 분리 여부를 정하는 편이 좋습니다.

자신의 앱에서도 목록 자료를 줄이려 한다면 카드 하나가 쓰는 정보와, 그 카드에서 바로 이어지는 행동이 쓰는 정보를 먼저 적어 보세요. VidDish에서는 다른 언어 본문은 덜어내고, 선택한 언어의 재료와 조리순서는 남겼습니다. 목록을 읽는 부담을 줄이면서 미리보기와 저장 흐름을 이어가기 위한 선택이었습니다.

위로 스크롤