앞선 글에서 회고를 두 모델로 교차 검증했더니 정정이 네 번 나왔고, 넷 다 결론이 아니라 세는 단위가 어긋나 있었다고 적었다. 거기서 얻은 규칙은 이거였다.
수치를 인용할 때 무엇을 한 건으로 셌는지와 언제 쟀는지를 함께 적는다.
그 글을 쓰고 며칠 뒤에 다섯 번째가 나왔다. 이번엔 교차 검증이 못 잡았다.
채택해놓고 오탐이라고 적었다
동료가 메시지를 보냈다. 에러 문구 작업의 회고에서 리뷰 봇 지적 하나를 오탐으로 분류했는데 그게 오탐이 아닌 것 같다는 얘기였다.
내가 오탐이라고 적은 근거는 단순했다. 그 코멘트가 가리킨 줄을 열어보니 주석이었다. 코드가 아니라 주석에 지적을 달았으니 엉뚱한 데를 짚은 것이라고 봤다.
확인해보니 아니었다. 코멘트가 달린 그 시점의 그 줄은 실제 코드였다.
// 코멘트가 달렸을 때 (앵커 커밋)
248: const statusCode = parseStatusCode(error);
그리고 15분 뒤 커밋이 그 제안을 그대로 반영했다. 가드를 넣고, 왜 넣었는지를 설명하는 주석 두 줄을 위에 붙이고, 커밋 메시지에 어느 지적을 반영한 것인지까지 적어뒀다.
// 수정 후
248: // `parseStatusCode` 는 인자를 무가드로 역참조한다. `null` 이 던져지면 여기서 …
249: // … 안내를 보여주려다 지면을 잃는다 (리뷰 지적 반영).
250: const statusCode = error !== null && typeof error === 'object' ? parseStatusCode(error) : undefined;
주석 두 줄이 붙으면서 코드가 250줄로 밀렸다. 나는 현재 파일의 248줄을 보고 “주석이네” 라고 판단했다. 받아들여 고쳐놓고, 나중에 오탐으로 적은 것이다.
채택한 지적이 나중에 오탐처럼 보일 수 있다
이게 우연한 실수가 아니라 구조적으로 생기는 오류라는 게 요점이다.
리뷰 코멘트의 줄 번호는 그 코멘트가 달린 커밋에 고정된 좌표다. 그 뒤에 대상 줄 위로 한 줄이라도 추가되면 현재 파일에서 같은 번호는 다른 것을 가리킨다. 지적을 반영하면서 가드나 설명 주석을 대상 코드 위에 추가하면 이런 이동이 생긴다.
| 현재 파일의 그 줄 | |
|---|---|
| 반영 전 코드가 그대로인 경우 | 대상 줄이 남아 있다 — 코멘트가 맞아 보인다 |
| 반영하며 위쪽 코드가 바뀐 경우 | 대상 줄이 밀려 있다 — 코멘트가 엉뚱해 보인다 |
판정이 뒤집힌다. 채택한 지적이 나중에 오탐처럼 보이는 역전이 생길 수 있다. 회고에서 “봇이 오탐을 몇 건 냈나”를 셀 때 이 가능성을 제외하지 않으면 통계에도 그대로 반영된다.
규칙은 이미 갖고 있었다
앞 글에서 만든 규칙에 이미 답이 있었다. “무엇을 한 건으로 셌는지와 언제 쟀는지를 함께 적는다.” 그런데 정작 인용할 때는 앞쪽 절반만 지켰다.
앞의 네 건과 결이 다르다.
| 어긋난 것 | |
|---|---|
| 첫 번째 ~ 네 번째 | 무엇을 한 건으로 세는가 — 심각도 표기 · 소비처 경계 · 지적과 답글 · 파일과 호출부 |
| 다섯 번째 | 언제 기준으로 보는가 — 코멘트의 앵커 커밋 vs 현재 파일 |
세는 단위에는 두 축이 있었는데 나는 한 축만 챙기고 있었다.
교차 검증이 이건 왜 못 잡았나
앞의 넷은 두 모델을 번갈아 돌려서 잡혔다. 한쪽이 낸 수치를 다른 쪽이 원자료로 다시 세게 했고, 그 과정에서 어긋난 단위가 드러났다.
다섯 번째는 안 걸렸다. 양쪽 다 현재 파일을 열었기 때문이다.
교차 검증이 잡아내는 건 “같은 것을 서로 다르게 세는 경우”다. 이번은 둘이 같은 방식으로 셌고, 다만 둘 다 잘못된 시점의 스냅샷을 보고 있었다. 관점을 둘로 늘려도 기준 시각이 하나면 그 축의 오류는 양쪽에 똑같이 들어간다.
그래서 앞 글의 결론에 조건이 하나 붙는다. 교차 검증에는 다른 관점만이 아니라 다른 기준 시각도 필요하다. 최소한, 과거의 기록을 인용할 때 그게 어느 시점의 좌표인지를 명시해야 한다.
사람이 필요했던 게 아니다
잡아준 건 사람이었고, 하필 그 코멘트를 직접 쓴 당사자였다. 그래서 처음에는 “그때 거기 있던 사람이 아니면 모른다”고 정리했는데, 다시 보니 과한 결론이었다.
앵커 커밋을 열면 누구나 확인할 수 있다.
# 코멘트가 달린 시점의 그 줄
git show "${ANCHOR_COMMIT}:${FILE_PATH}" | sed -n '244,252p'
# 지금의 그 줄
git show "HEAD:${FILE_PATH}" | sed -n '244,254p'
실제로 나도 이 두 명령으로 확인했고, 나는 그 코멘트를 쓴 사람이 아니다. 필요했던 건 그 자리에 있던 기억이 아니라 좌표의 시점을 밝히는 절차였다. 동료가 먼저 불일치를 알아챈 것은 자기 코멘트의 처리 결과를 기억하고 있었기 때문이다. 다만 판정 근거는 그 기억이 아니라 앵커 커밋이었다.
그래서 한 줄을 더한다
앞 글에서 회고·지표를 쓸 때 대보는 항목 네 개를 적었다. 다섯 번째를 더한다.
| 확인 | 이번에 걸린 것 |
|---|---|
| 과거 시점의 기록을 인용할 때 그 시점의 파일을 연다. 줄 번호·경로·상태는 전부 시점에 묶여 있다 | 현재 파일 줄 번호로 과거 코멘트를 판정했다 |
리뷰 도구를 쓴다면 더 간단한 방법도 있다. 대부분의 플랫폼이 코멘트마다 앵커 커밋을 들고 있으니, 판정할 때 그 커밋을 함께 적으면 나중에 다시 열어볼 수 있다. 줄 번호만 적으면 그 좌표는 다음 커밋에서 조용히 만료된다.
앞 글에서 “가장 오래 남을 것은 세는 단위를 밝힌다는 한 줄”이라고 썼다. 그 한 줄이 아직 덜 적혀 있었다. 무엇을 세는지 옆에 언제 기준인지를 나란히 적어야 완성된다.