Cheondi
개발 · Unity

대표 통화 변경과 열린 화면 상태

대표 통화 변경이 이미 열린 내역과 합계, 상세 패널에 퍼지는 영향을 따라가 본 기록입니다.

  • #unity
  • #events
  • #currency

설정에서 대표 통화를 바꾸면 금액을 보여 주는 화면들이 새 통화 기준으로 갱신돼야 했다. 처음에는 설정값 하나를 저장하고 각 화면에서 다음에 열릴 때 읽으면 된다고 생각했다. 그런데 이미 열려 있는 최근 내역과 상세 창은 이전 통화 표시를 그대로 갖고 있었다.

문제는 한 화면에만 있지 않았다. 합계, 개별 항목, 손익 팝업과 작은 차트가 같은 통화 설정을 사용했다. 설정 변경이 어디까지 전달돼야 하는지 먼저 알아야 했다.

화면별 값 참조 시점

어떤 화면은 열릴 때 설정을 읽고, 어떤 화면은 데이터를 받을 때 읽었다. 또 다른 화면은 처음 생성할 때 읽은 값을 필드에 보관했다. 설정 객체는 같아도 읽는 시점이 다르니 변경 이후 결과가 달랐다.

설정 변경
  -> 열려 있는 목록 갱신
  -> 상세 패널 닫기 또는 다시 계산
  -> 캐시된 화면 모델 폐기
  -> 이후 요청의 통화 기준 변경

이 흐름을 적고 나서야 단순한 저장 문제가 아니라 변경 이벤트의 전파 문제라는 걸 알았다.

직접 화면 탐색 방식의 불안정성

설정 화면이 다른 UI를 하나씩 찾아 갱신하면 당장은 빠르게 고칠 수 있었다. 하지만 새 화면이 추가될 때마다 설정 코드가 그 화면을 알아야 했다. 기존 프로젝트는 변경 이벤트를 발행하고 관심 있는 화면이 구독하는 구조를 사용하고 있었다.

public event Action<string> OnDisplayCurrencyChanged;

void ChangeCurrency(string code)
{
    displayCurrency = code;
    OnDisplayCurrencyChanged?.Invoke(code);
}

화면은 열려 있는 동안만 구독하고 닫힐 때 해제해야 했다. 해제를 놓치면 이미 사라진 화면이 이벤트를 받거나 중복 호출되는 문제가 생겼다.

재계산과 재요청의 구분

원본 금액을 여러 통화로 들고 있다면 화면에서 다시 포맷만 해도 된다. 반대로 서버가 대표 통화로 환산한 결과만 보내 준다면 새 요청이 필요하다. 어떤 데이터가 원본이고 어떤 데이터가 이미 변환된 값인지 구분하지 않고 갱신하면 틀린 계산을 할 수 있었다.

당시에는 기존 응답의 의미를 확인한 뒤, 화면에서 안전하게 다시 표시할 수 있는 값과 재조회해야 하는 영역을 나눴다. 상세 패널은 이전 기준을 보여 줄 위험이 있어 닫는 편을 택한 경우도 있었다.

설정 변경의 의존성 그래프

대표 통화 변경은 설정 화면 한곳의 기능처럼 보였다. 실제로는 여러 화면, 캐시와 요청 조건에 연결돼 있었다. 변경의 영향 범위를 코드 검색으로 먼저 찾고, 열린 화면과 다음에 열릴 화면을 따로 확인해야 했다.

이후 공통 설정을 수정할 때 값을 저장하는 코드만 보지 않는다. 누가 읽고, 언제 읽고, 변경 사실을 어떻게 알게 되는지 따라간다. 설정 하나가 작은 의존성 그래프라는 걸 알게 된 작업이었다.

후속 확인 항목

이 문제를 고친 뒤 관련 공식 자료를 찾아 읽으면서, 당시 코드에서 우연히 맞았던 부분과 규칙으로 남겨야 할 부분을 나눠 봤다.

ECMA-334에서 decimal은 10진 스케일을 가진 값으로 정의된다. 0.1 같은 10진 소수를 그대로 다뤄야 하는 금액에는 이 성질이 유리하지만, 타입만 바꾼다고 통화 정책이 생기는 것은 아니다. 통화별 자릿수, 반올림 방식, 입력 단위와 전송 단위를 따로 정해야 한다.

특히 표시를 위해 반올림한 문자열을 다음 계산의 입력으로 다시 쓰면 작은 오차가 정책 오류로 바뀐다. 계산 값과 표시 값은 끝까지 분리하는 편이 낫다.

다음에 대표 통화 변경과 열린 화면 상태 같은 문제를 보면 아래 순서부터 확인하려고 한다.

  • 원본 값과 화면 파생 값의 소유자
  • 탭·계좌 변경 시 무효화할 요청
  • 이전 선택이 남는 캐시 범위
  • 같은 값이 여러 컴포넌트에서 바뀌는지

서버와 클라이언트가 같은 반올림 모드와 최소 단위를 쓰는지 예제 값으로 맞추지 않으면 경계 금액에서 서로 다른 결과가 난다.

공식 참고 자료