테마 동기화가 동작한 뒤 차트 설정도 같은 데이터에 추가했다. 설정이라는 공통 이름이 있으니 한 객체로 보내는 게 자연스러워 보였다. 그런데 한 기기에서 테마를 바꾸고 다른 기기에서 차트 선 색을 바꾸면 마지막 저장이 상대 변경까지 되돌리는 일이 생겼다.
큰 설정 객체 전체를 매번 덮어쓰는 방식은 구현은 단순했지만 충돌 범위가 너무 넓었다.
동시 변경 단위
테마와 글자 크기는 화면 외형이라는 같은 이유로 바뀌었다. 차트 지표와 표시 옵션은 별도 화면에서 훨씬 자주 수정됐다. 저장 모델을 영역별 문서처럼 나눴다.
{
"appearance": { "revision": 4, "theme": "dark" },
"chart": { "revision": 11, "grid": true, "indicators": [] }
}
API가 하나여도 영역별 revision과 변경 필드를 전달하면 관련 없는 설정을 덮지 않을 수 있었다.
부분 업데이트의 계약
필드가 없는 것과 값을 비우는 것은 달랐다. null을 삭제로 볼지 변경 없음으로 볼지 서버와 클라이언트가 같은 규칙을 가져야 했다.
public record ChartPatch(
Optional<bool> Grid,
Optional<IReadOnlyList<string>> Indicators);
실제 구현 방식은 달라도 “전송 안 함”, “빈 값으로 변경”, “값 설정”을 구분하는 계약이 필요했다.
영역별 적용 이벤트
설정 하나가 바뀔 때마다 모든 화면을 새로고침하면 차트가 다시 로딩되고 입력 포커스가 사라졌다. 외형 변경과 차트 변경 이벤트를 나누고 필요한 컴포넌트만 반응하게 했다.
동기화 응답을 적용할 때도 로컬에서 수정 중인 영역인지 확인했다. 서버 응답이 늦게 왔다고 현재 편집 값을 조용히 덮지 않았다.
테스트는 테마만 바꾸기, 차트만 바꾸기, 서로 다른 기기에서 동시에 각 영역 바꾸기, 같은 영역을 동시에 바꾸기로 나눴다. 성공 요청만 확인할 때는 보이지 않던 충돌 범위가 이 조합에서 드러났다. 이전 버전 클라이언트가 모르는 새 필드를 보존하는지도 함께 확인했다.
데이터 모델이 결정한 협업 경계
처음에는 JSON을 잘 나누는 정도의 문제라고 생각했다. 실제로는 어느 팀과 화면이 독립적으로 변경할 수 있는지를 데이터 구조가 결정했다. 너무 큰 객체는 코드뿐 아니라 배포와 충돌도 함께 묶었다.
이 경험 뒤 “같은 설정”이라는 이름만으로 한 덩어리로 만들지 않는다. 변경 빈도와 소유 화면, 충돌 시 영향을 보고 동기화 단위를 정한다. 데이터 경계가 작을수록 실패도 관련된 영역 안에 머물렀다.
공식 문서 기반의 추가 정리
이 문제를 고친 뒤 관련 공식 자료를 찾아 읽으면서, 당시 코드에서 우연히 맞았던 부분과 규칙으로 남겨야 할 부분을 나눠 봤다.
Unity 실행 순서 문서는 Awake, OnEnable, Start, Update 같은 엔진 이벤트가 어느 구간에서 호출되는지 설명한다. 하지만 로딩·성공·빈 결과·실패 같은 업무 상태의 순서까지 대신 정해 주지는 않는다. 두 종류의 순서를 섞어 생각하면 콜백이 한 프레임 늦게 왔다는 이유만으로 이전 화면 상태가 다시 살아날 수 있다.
그래서 수명주기 메서드는 상태 전이를 직접 흩어 놓는 장소보다, 한 곳에 모인 전이 함수를 호출하는 경계로 쓰는 편이 추적하기 쉬웠다.
다음에 테마·차트 설정 동기화 같은 문제를 보면 아래 순서부터 확인하려고 한다.
- 차트 데이터와 화면 옵션의 버전
- 시간순 정렬과 중복 시각 처리
- 보조지표를 다시 계산할 조건
- 큰 기록에서 parsing·drawing 시간 분리
새 응답을 적용하기 전에 요청 식별자와 현재 선택 조건이 여전히 같은지 확인해야 오래된 응답을 버릴 수 있다.
공식 참고 자료
- Unity 2021.3 이벤트 함수 실행 순서 — MonoBehaviour 이벤트와 프레임 단계의 실행 순서
- ECMA-334 C# 언어 사양 6판 — decimal·enum·예외를 포함한 C# 언어 규칙