Skip to content
isdnetworks
Go back

등식을 만드는 중복 제거 위치

(수정됨)

주문 수집 이상을 감지하는 설계를 하면서 임계값을 orders 의 과거 데이터로 검증하고 싶었다. 여기에는 함정이 있는데 런타임이 재는 신호와 백테스트가 재는 신호가 다르면 튜닝한 임계값이 무의미해진다는 것이다.

Table of contents

Open Table of contents

배경 — 신호가 같은지의 조건

런타임은 이번 실행에서 몇 건을 수집했는지를 보고 백테스트는 그 기간에 orders 에 몇 행이 쌓였는지를 COUNT(*) 로 본다. 둘이 같으려면 중복 제거가 어디서 일어나는지가 조건이 된다.

OrderRepository::store() 를 열어 보니 받은 데이터를 그대로 INSERT 하고 자체 중복 판정을 하지 않았다. 상위 OrderCollector 에만 exists() 확인이 있어서 이미 있으면 건너뛰고 없으면 저장 계층을 부른다.

검증 — 성립한 등식

그러면 그 실행에서 INSERT 된 행 수가 그 실행에서 새것으로 판정된 건 수이고 그것이 실제 수집한 신규 건 수와 정확히 같다. 테이블의 행만 보면 그때 얼마나 수집했는지를 알 수 있다는 뜻이다.

계측 코드가 없던 시기의 실적도 created_at 으로 묶으면 재구성되므로 새 인프라를 하나도 안 넣고 백테스트를 할 수 있게 됐다. 저장 계층이 updateOrCreate() 를 했다면 삽입 시도와 실제 삽입이 달라 이 등식이 깨진다.

원인 — 확인이 필요했던 이유

두 가지 방법이 있었는데 상위에서만 하겠거니 하고 넘어가는 것과 저장 계층 본문까지 내려가 확인하는 것이다. 뒤쪽을 골랐다. 이유는 앞쪽이면 백테스트가 다른 것을 재고 있었을 수 있어서다. 대신 저장소 계층 셋을 다 읽느라 반나절이 드는 것을 감수했다.

그러면 임계값을 열심히 튜닝해 놓고 런타임에서 무의미해진다. 백테스트를 하기 전에 두 신호가 같은 것을 재는지부터 확인해야 한다.

주의 — 좁아진 0건의 뜻

이 등식에는 이면도 있었다. 0건이 이번 실행에서 데이터베이스에 없던 신규 주문이 0건이라는 뜻이므로 조회 창을 늘려도 이미 있는 건은 안 세어 값이 안 커진다.

즉 0건은 조회 범위와 무관하다. 그런데 소량 seller_id 는 정상 상태에서도 0이 흔하므로 수집이 죽은 경우와 판매가 없는 경우가 같은 0으로 나타나 건수만으로는 구분할 수 없다. 그 구분에는 채널 간 교차 비교나 last_run_at 처럼 실행 자체를 보는 신호가 따로 필요하다.

조치 — 주석으로 막은 리팩터링

마지막으로 하나를 남겼는데 중복 제거 위치를 옮기는 리팩터링이 이 등식을 깨뜨려 과거 기반 분석을 전부 무효화한다는 것이다. 저장 계층에 updateOrCreate() 를 넣으면 코드가 더 안전해 보이지만 등식이 깨진다.

개선처럼 보이는 변경이 다른 것의 전제를 무너뜨리는 경우다. 그래서 이 메서드가 의도적으로 중복 판정을 하지 않으며 그 결과로 어떤 등식이 성립하고 무엇으로 바꾸면 그것이 깨지는지를 @see 주석으로 남겼다.

정리


Share this post on:

Previous Post
값을 비워도 남는 것
Next Post
할인 셋, 저장소 셋