기기 안에 저장하던 설정을 다른 환경에서도 이어 쓰기 위해 서버와 맞추는 작업을 봤다. 처음에는 로그인할 때 내려받고 설정을 바꿀 때 올리면 된다고 생각했다. 두 기기에서 값을 바꾸거나 오프라인 상태에서 수정하면 어느 쪽이 최신인지 바로 모호해졌다.
동기화는 파일 복사보다 두 상태의 차이를 합의하는 과정이었다.
설정별 동기화 범위
언어, 테마, 차트 표시 옵션처럼 사용자 경험에 영향을 주는 값은 서버 동기화 대상이 될 수 있었다. 창 크기나 기기 성능에 따른 옵션은 로컬에 남기는 편이 자연스러웠다.
public class SyncSettingsDto
{
public string Language { get; init; }
public string Theme { get; init; }
public ChartOptions Chart { get; init; }
public long Revision { get; init; }
}
로컬 설정 객체 전체를 보내지 않고 계약에 포함된 필드만 DTO로 만들었다.
최신 설정의 판정 기준
기기 시각은 틀릴 수 있어서 로컬 수정 시간만 비교하기 어려웠다. 서버가 부여한 revision을 사용하고, 업데이트 요청에 내가 읽었던 revision을 함께 보냈다. 그 사이 다른 변경이 있으면 덮어쓰지 않고 충돌로 응답받았다.
GET settings -> revision 12
PUT settings (baseRevision: 12)
-> success revision 13
-> conflict current revision 14
초기 단계에서는 복잡한 자동 병합보다 새 서버 값을 보여주고 다시 선택하게 하는 안전한 정책을 택했다.
동기화 실패 시 사용 흐름 유지
설정 저장 API가 실패했다고 사용자의 화면 변경을 즉시 되돌리면 불편했다. 로컬에는 변경을 반영하고 동기화 대기 상태로 표시한 뒤 연결이 회복되면 제한적으로 재시도했다.
로그인 직후 서버 설정을 받기 전 잠깐 기본값이 보이지 않도록 초기 로딩 순서도 조정했다. 서버를 기다릴 수 없는 상황에는 마지막 로컬 설정을 사용했다.
동기화의 부분 성공 상태
API 호출 한 번이 성공하는지만 보던 시기에는 동기화도 비슷하게 생각했다. 실제로는 오프라인 수정, 다른 기기 변경, 중복 재시도, 충돌이라는 중간 상태가 있었다.
이 작업으로 설정도 작은 분산 데이터라는 걸 배웠다. 어느 값을 공유할지, 누가 버전을 정할지, 실패 중 사용자에게 무엇을 보여줄지를 정해야 동기화가 됐다.
기술 문서 기반의 책임 경계
작업 당시에는 눈앞의 오류를 먼저 고쳤지만, 이후 기술 문서와 맞춰 보며 확인 순서를 조금 더 구체화했다.
Unity 실행 순서 문서는 Awake, OnEnable, Start, Update 같은 엔진 이벤트가 어느 구간에서 호출되는지 설명한다. 하지만 로딩·성공·빈 결과·실패 같은 업무 상태의 순서까지 대신 정해 주지는 않는다. 두 종류의 순서를 섞어 생각하면 콜백이 한 프레임 늦게 왔다는 이유만으로 이전 화면 상태가 다시 살아날 수 있다.
그래서 수명주기 메서드는 상태 전이를 직접 흩어 놓는 장소보다, 한 곳에 모인 전이 함수를 호출하는 경계로 쓰는 편이 추적하기 쉬웠다.
다음에 서버 설정 동기화의 시작 같은 문제를 보면 아래 순서부터 확인하려고 한다.
- 요청 DTO와 화면 모델의 분리
- HTTP 성공과 업무 성공의 구분
- 취소·타임아웃·재시도 정책
- 예시 도메인으로 재현 가능한 로그
새 응답을 적용하기 전에 요청 식별자와 현재 선택 조건이 여전히 같은지 확인해야 오래된 응답을 버릴 수 있다.
공식 참고 자료
- Unity 2021.3 이벤트 함수 실행 순서 — MonoBehaviour 이벤트와 프레임 단계의 실행 순서
- ECMA-334 C# 언어 사양 6판 — decimal·enum·예외를 포함한 C# 언어 규칙