교환 건의 정산이 어느 항목에 붙는지 확인해야 했고 내 가설은 교환 원주문 항목에 붙는다는 것이었다.
Table of contents
Open Table of contents
확인했다고 생각한 조회
과거 처리 이력을 조회했고 결과가 나왔다. 교환 상태 항목에 정산이 붙어 있었으므로 가설대로라고 보고 그렇게 보고했다.
그런데 담당자가 재발송 항목에 물려야 하는 것 아니냐고 했다. 업무 규칙상 그것이 맞다는 것이었고 내 조회 결과와 정반대였다.
쿼리 안의 순환
쿼리를 다시 봤다.
WHERE oio.status = 76 -- 교환 상태
교환 상태인 것만 조회했으니 나오는 것은 당연히 교환 상태 항목이다. 가설이 정산은 교환 항목에 붙는다는 것인데 조회가 교환 항목만 뽑고 결과로 교환 항목이 나왔으니 가설이 맞다고 결론지은 것이다.
재발송 항목에 붙은 것들은 조회에서 아예 제외됐으므로 있는지 없는지조차 모르는 상태였다. 결론을 조건에 넣으면 그 결론과 다른 것은 결과에 들어올 수 없다.
조건을 넓힌 뒤의 결과
가설과 반대 경우를 같은 쿼리에 담았다.
WHERE (oio.status = 76 OR oio.origin_order_item_option_id IS NOT NULL)
다시 조회하니 표본 전부가 원본 참조를 가진 재발송 항목에 연결돼 있었다. 정반대 결과였고 처음 조회에서 나온 것들은 조인 조건상 몇 건이 걸린 것이었다.
이 함정의 성질
이것이 위험한 이유는 결과가 가설과 일치한다는 형태로 나타나기 때문이다. 쿼리가 성공했고 결과가 나왔고 가설과 맞으니 전부 좋아 보이고 아무 신호가 없다.
오류가 났으면 다시 봤을 텐데 맞는 결과가 나오면 더 안 본다. 검증을 통과한 것처럼 보이는 상태가 검증을 안 한 상태보다 나쁠 수 있다.
규칙과 근거 수준
이 뒤로 검증 쿼리의 조건에 검증하려는 결론을 넣지 않는 것을 규칙으로 뒀다. 가설과 반대 경우를 같이 뽑아 분포를 보면 어느 쪽인지 나오는데 필터하면 필터한 것만 나온다.
바뀐 결론도 그냥 믿지 않고 실제로 재발송 항목에 정산을 연결하는 수정을 넣고 확인 커맨드를 돌려 봤다. 조회는 이렇게 돼 있다는 것까지 말해 주고 실행은 이렇게 하면 된다는 것을 말해 준다.
보고에는 근거 수준도 적었다. 전 기간을 다 센 것이 아니라 최근 표본을 봤고 업무 규칙은 담당자에게 확인했다는 것을 명시했다. 전부 그렇다고 쓰지 않았다.
처리 못 하는 케이스도 정리했다. 재발송이 아직 생성되지 않은 교환은 붙일 항목이 없어 지금은 매칭이 안 되는데 재발송이 생기면 확인 커맨드가 자연히 처리한다. 이것을 매칭 실패로 세면 없는 문제가 생기므로 아직 시점이 안 된 것으로 분류했다.
정리
- 검증 쿼리의 조건에 결론을 넣으면 순환논증이 된다
- 가설과 반대 경우를 같은 쿼리에 담고 분포를 본다
- 이 함정은 결과가 가설과 일치하는 형태로 나타난다
- 오류보다 맞는 결과가 더 위험하고 다시 안 보게 된다
- 결론이 바뀌면 실행으로 확인한다
- 조회는 상태를 말하고 실행은 동작을 말한다
- 근거가 표본인지 전수인지 적는다
- 아직 시점이 안 된 것을 실패로 세지 않는다