JSON으로 화면이 만들어지는 흐름을 겨우 따라간 다음 맡게 된 건 최근 내역을 보여 주는 화면이었다. 처음 설명을 들었을 때는 서버에서 받은 배열을 foreach로 돌면서 항목을 만들면 되는 일이라고 생각했다. 학교 프로젝트에서 점수판을 만들 때도 비슷하게 했으니, 데이터 구조만 알면 금방 끝날 것 같았다.
그런데 기존 화면을 열어 보니 리스트보다 조건문이 먼저 보였다. 선택한 계좌가 무엇인지, 두 가지 상품 화면 중 어디인지, 아직 요청 중인지, 결과가 정말 비어 있는지에 따라 같은 영역이 전혀 다른 모습을 보여 줬다. 리스트는 화면의 중심이 아니라 여러 상태 중 하나였다.
데이터가 오기 전에도 화면은 존재했다
가장 먼저 헷갈린 건 Count == 0이었다. 항목이 0개라는 사실만으로는 로딩 중인지, 조회가 끝났는데 내역이 없는지 구분할 수 없었다. 그래서 데이터 개수 외에 요청 상태가 필요했다.
enum ListState
{
Idle,
Loading,
Ready,
Empty,
Failed
}
지금 보면 아주 평범한 구분이지만 당시에는 값이 없으면 빈 화면을 보여 주면 된다고만 생각했다. 요청을 보내자마자 빈 안내를 띄웠다가 결과가 오면 리스트로 바뀌는 깜빡임도 있었고, 실패했는데도 내역이 없는 것처럼 보이는 경우도 있었다. 사용자는 그 차이를 알 수 없지만 개발자는 반드시 구분해야 했다.
한 항목에도 표시 규칙이 많았다
내역 한 줄에는 시간, 결과, 통화, 금액 같은 값이 들어갔다. 문제는 값을 그대로 출력할 수 없다는 점이었다. 상품 유형에 따라 필요한 필드가 달랐고, 한 계좌가 여러 통화를 사용할 때는 손익 표시 방식도 달라졌다. 취소된 항목은 일반 결과와 같은 색으로 보여 주면 안 됐다.
처음에는 아이템 프리팹 안에서 모든 조건을 처리하려고 했다. 그러다 보니 if가 계속 늘고, 어떤 조건 때문에 텍스트가 사라졌는지 찾기 어려워졌다. 기존 코드를 따라가며 원본 데이터를 화면용 모델로 한 번 정리한 뒤 프리팹에는 표시할 값만 넘기는 이유를 조금씩 이해했다.
var row = new HistoryRow
{
title = source.displayName,
amount = FormatAmount(source.amount, source.currency),
isCanceled = source.status == ResultStatus.Canceled
};
화면을 바꾸면 이전 상태도 정리해야 했다
상품 유형을 바꿨을 때 이전 패널이 남거나, 계좌를 전환했는데 이전 계좌의 항목이 잠깐 보이는 문제도 있었다. 새 데이터를 그리는 것만 생각하고 기존 데이터를 언제 비울지는 놓친 탓이었다. 열기, 요청, 응답, 닫기 순서를 종이에 적어 보면서 어느 시점에 목록을 초기화해야 하는지 찾았다.
무조건 먼저 비우면 화면이 자주 번쩍였고, 너무 늦게 비우면 잘못된 정보가 남았다. 결국 중요한 건 Clear()를 호출하느냐보다 어떤 상태 전환에서 호출하느냐였다.
리스트를 보는 눈이 조금 달라졌다
이 작업 이후 화면에 목록이 보이면 항목 생성 코드부터 찾지 않게 됐다. 먼저 로딩, 성공, 빈 결과, 실패가 어떻게 구분되는지 보고 계좌나 탭 변경이 어떤 이벤트를 발생시키는지 확인한다. 리스트 자체보다 그 리스트가 살아 있는 동안의 상태를 먼저 보는 습관이 생겼다.
아직 새로운 구조를 설계한 건 아니었다. 기존 구현을 따라가고 오류를 하나씩 고친 수준이었다. 그래도 “배열을 화면에 뿌리는 일”이라고 생각했던 기능이 작은 상태 머신에 가깝다는 걸 알게 된 첫 작업이었다.