Archive Lab
이미지와 링크를 모으는 React Native 앱에서 스크롤을 측정하고, 최적화 가설을 검증하는 개발 기록입니다.
목차
회사에서 만드는 앱에는 목록이 자주 나온다. 메뉴를 고르고, 주문 내역을 보고, 쿠폰을 찾는 화면들이다. 기능은 구현했지만 포트폴리오에 그 과정을 옮길 때면 화면이 어떻게 바뀌었는지보다 무엇을 만들었는지를 나열하게 됐다.
Delivery Lab에서는 주문 상태를 잠금화면까지 연결해 봤다. 다음에는 평소 자주 만드는 목록 화면을 조금 더 파고들고 싶었다. 스크롤이 매끄럽다는 건 어떻게 확인하고, 끊긴다면 어디를 고쳐야 할까.
예전에 60fps 정도면 움직임이 끊김 없이 보인다는 이야기를 들은 적이 있다. 그 숫자가 계속 기억에 남았다. 다만 60을 사람 눈의 고정된 한계로 놓고 시작하지는 않기로 했다. 내가 만든 앱이 화면을 제때 그리는지부터 확인해 보고 싶었다.
이 글은 첫 화면을 만들고 기기에서 확인한 과정을 정리한 기록이다. 프로젝트 이름은 Archive Lab으로 정했다.
측정할 목록부터 만들기
이미지와 원문 링크를 모아두는 작은 아카이브 앱을 골랐다. 사진이 있는 카드를 스크롤하다가 관심 있는 자료를 검색하고, 즐겨찾기에 넣고, 상세 화면을 여는 흐름이다. 목록의 양을 늘리면서 같은 동작을 비교하기에도 맞았다.
처음부터 로그인이나 서버를 붙이지는 않았다. 이번에 궁금한 건 목록을 그리는 비용이었는데, 이미지 다운로드나 API 응답까지 기다리면 화면이 늦는 이유가 섞인다. 우선 앱 안에 샘플을 넣고, 즐겨찾기와 컬렉션 크기는 AsyncStorage에 저장했다. 자료를 직접 수집하고 동기화하는 기능은 아직 없다.
화면은 기본 FlatList의 2열 목록으로 만들었다. 카드에는 사진과 제목, 분류, 즐겨찾기 버튼이 있고 상세는 RN의 Modal로 연다. 특정 목록 라이브러리로 바꾸는 결론부터 정해두지는 않았다. 지금 구성이 어느 정도인지 알아야 다음 변경을 비교할 수 있으니까.
첫 구현은 Expo 57.0.22와 React Native 0.86.3을 사용했다. 기기 확인은 개인 갤럭시의 Android 15에서 진행했다.
5,000개를 넣는다고 사진도 5,000장은 아니다
앱에는 샘플 컬렉션을 100개, 1,000개, 5,000개로 바꾸는 버튼을 넣었다. 사진은 고정된 JPEG 12장을 반복하고 항목의 ID와 제목 같은 메타데이터를 늘린다. 같은 크기를 선택하면 같은 목록을 다시 만들도록 했다.
이 차이는 기록에 남겨둘 필요가 있었다. 5,000개 버튼을 눌렀다고 서로 다른 사진 5,000장을 다운로드하고 디코딩한 건 아니다. 고유 이미지가 많아질 때의 메모리나 캐시 문제는 이 조건만으로 설명할 수 없다. 이번에는 사진 종류를 고정하고 목록 규모를 바꿔보는 데 집중했다.
자료의 ID도 규모를 바꿀 때 유지했다. 1,000개에서 표시한 즐겨찾기가 100개로 줄였다가 돌아왔다는 이유로 사라지면 곤란하다. 검색 결과와 즐겨찾기 개수는 원본 자료와 현재 조건으로 계산하고, 따로 복제해 맞추는 상태는 만들지 않았다.
테스트는 통과했는데 사진이 너무 길었다
검색과 즐겨찾기, 상세 화면, 저장 실패 뒤 재시도까지 테스트했다. 첫 기기 설치 전에 통과한 테스트는 34개였다.
갤럭시에서 앱을 열어보니 카드 사진이 세로로 길게 늘어나 있었다. 제목은 아래로 밀려서 첫 화면에 보이지도 않았다. 스크롤 성능을 보기 전에 카드 크기부터 바로잡아야 했다.



카드 이미지에 준 스타일은 이렇게 생겼다.
폭을 정하고 비율을 줬으니 높이도 따라 계산될 거라고 생각했다. 그런데 번들에 포함한 이미지에는 원래 폭과 높이가 있었다. 사용 중인 RN의 Image.android.js를 열어보니, 자산 크기를 기본 스타일로 넣은 뒤 내가 전달한 스타일을 적용하고 있었다.
공통 ArchiveImage 컴포넌트에서 기본 높이를 해제했다. 각 화면이 전달하는 폭과 비율은 그 뒤에 적용한다.
RN 이미지 문서에도 정적 이미지의 크기 정보와 레이아웃에 맞게 크기를 해제하는 설명이 있다. 이 앱에서는 폭을 직접 지정하므로 높이를 해제하는 것으로 해결했다. 목록과 상세가 같은 이미지 컴포넌트를 쓰게 해서 두 화면에 함께 반영했다.
자동 테스트에서는 검색 결과가 바뀌고 상세가 열리는 동작을 확인했다. Android가 번들 이미지의 크기를 스타일에 넣어 실제로 배치하는 과정은 그 테스트에서 재현되지 않았다. 수정 뒤 다시 빌드한 기기 화면에서 사진 비율을 확인했다. 밝은 배경에서 잘 보이지 않던 상태바 아이콘도 같이 고쳤다.
손으로 몇 번 스크롤한 뒤 끝내지 않으려면
화면이 갖춰지니 직접 스크롤해 보게 됐다. 대체로 괜찮아 보이는데, 가끔 걸리는 것 같기도 했다. 이 느낌만으로 옵션을 바꾸면 다음에도 비슷한 감상으로 끝날 것 같았다.
같은 목록에서 같은 구간을 반복해서 움직이기로 했다. Android에는 앱과 분리된 Macrobenchmark 테스트 모듈을 붙이고, Metro 연결 없이 실행되는 측정용 APK를 준비했다. 검색이나 즐겨찾기 확인은 별도로 하고 스크롤 구간만 측정한다.
React Native의 성능 안내에서도 개발 모드의 추가 작업이 측정에 영향을 줄 수 있다고 설명한다. 그래서 개발 중 띄운 화면의 느낌과 별도 빌드에서 얻은 숫자를 구분했다.
60fps라는 숫자에서 시작했지만 첫 단계에서 한 일은 앱과 비교 조건을 만드는 것이었다. 첫 구현에 이어 100개, 1,000개, 5,000개 조건의 기준 측정까지 마쳤다. 항목을 늘리면 당연히 더 느려질 줄 알았는데, 결과는 예상만큼 벌어지지 않았다.
2편에서는 목록을 5,000개로 늘리면 얼마나 느려질까라는 질문으로 그 수치를 살펴보려 한다. 화면이 매끄럽다는 느낌과 측정값이 어디서 만나는지부터 확인해 볼 차례다.
