차트의 1분, 5분, 1시간 주기를 빠르게 바꾸면 캔들은 새 주기로 보이는데 이동평균선은 이전 모양이 남는 문제가 있었다. 잠시 뒤 정상으로 바뀌기도 해서 렌더링 속도 문제처럼 보였다. 실제로는 캔들 데이터 요청과 보조지표 계산이 서로 다른 작업으로 움직였다.
보조지표는 현재 캔들에 의존하지만 주기 버튼 이벤트가 두 작업을 각각 시작하고 있었다.
계산 입력에 주기 정보를 포함했다
보조지표 결과가 어느 캔들 집합에서 계산됐는지 확인할 수 있도록 입력 스냅샷을 만들었다.
public record ChartSnapshot(
string Symbol,
TimeSpan Interval,
long DataVersion,
IReadOnlyList<Candle> Candles);
IndicatorResult Calculate(ChartSnapshot snapshot)
=> indicator.Calculate(snapshot);
결과를 적용할 때 현재 상품, 주기, 데이터 버전이 모두 같은지 확인했다.
주기 변경을 하나의 전환으로 다뤘다
버튼 색을 먼저 바꾸고 데이터는 나중에 바꾸던 흐름을 화면 상태 전환으로 묶었다.
IntervalChanging(target)
-> 이전 요청 취소
-> 캔들 로드
-> 보조지표 계산
-> Ready(target, candles, indicators)
중간에는 이전 보조지표를 새 캔들 위에 겹치지 않고 로딩 표시나 마지막 완성 화면을 정책에 따라 유지했다.
캐시 키도 주기를 포함해야 했다
상품 코드만으로 보조지표 캐시를 찾는 코드가 있어 다른 주기의 결과를 재사용했다. 상품, 주기, 지표 종류, 입력 옵션을 키에 포함하고 캔들 데이터 버전이 달라지면 무효화했다.
sample-symbol|5m|moving-average|period=20|data=42
캐시는 계산을 빠르게 했지만 정체성이 불완전하면 오래된 값을 빠르게 보여줄 뿐이었다.
느린 네트워크와 연속 클릭 조건을 따로 만들어 완료 순서가 바뀌어도 같은 화면이 나오는지 확인했다.
파생 상태는 원본과 함께 움직여야 했다
캔들은 원본 데이터였고 보조지표는 그로부터 계산된 파생 상태였다. 둘을 독립적으로 최신화하면 각각은 맞아도 조합은 틀릴 수 있었다.
이 문제를 해결한 뒤 계산 결과를 저장하거나 캐시할 때 어떤 입력에서 만들어졌는지를 함께 본다. 차트 주기 버튼 하나가 비동기 데이터와 파생 상태의 일관성을 배우게 해 준 작업이었다.