자동화 파이프라인12 분 읽기

내 대시보드는 방문자 대신 카드 이름을 세고 있었다

후원 버튼을 붙일지 계산하려고 실측을 뽑다가, 게이트의 분모가 사람이 아니라는 걸 알았습니다. token 칸에 경로·밴드·카드 슬러그·공유 토큰이 앱마다 다르게 들어가 있었고, 진범은 호출자가 방문자 토큰을 덮어쓸 수 있게 열어둔 물음표 두 개였습니다.

#analytics#instrumentation#first-principles#reality-check#gotchas
개념 도식: token 칸에 경로·밴드·카드 슬러그·공유 토큰 네 가지 뜻이 섞여 있어 고유 token 수가 콘텐츠 종류 수가 된다. token을 항상 방문자 id로 두고 공유 토큰은 src 라벨로 옮기면 해결된다.
한 칸에는 한 가지 뜻만. 고칠 것은 호출부 19곳이 아니라 덮어쓰기를 허용한 한 줄이었다.

무료 웹앱들에 후원 버튼을 붙일지 검토하고 있었습니다. 붙이기 전에 규모부터 계산하는 게 순서라, 앱별 방문자와 공유율을 뽑았습니다. 기대수익이 작업량을 넘는지 보려던 것뿐이었습니다.

숫자가 이상했습니다. 어떤 앱은 결과 조회가 198건인데 고유 방문자가 5명이었습니다. 한 사람이 40번씩 자기 궁합을 본 걸까요. 다른 앱은 방문자가 529명인데, 그 529가 전부 서로 다른 URL 경로였습니다.

여기서 멈추고 물어야 할 게 있었습니다. 당신의 대시보드에 찍힌 "방문자 수"는, 그 숫자를 만드는 컬럼이 실제로 사람 하나를 가리킨다는 걸 확인하고 쓰는 숫자입니까? 저는 확인한 적이 없었습니다. 열흘 전에 게이트의 분모를 "페이지 로드"에서 "고유 token 수"로 바꿔놓고, 그게 개선이라고 기록까지 해뒀습니다.

한 칸에 네 가지 뜻이 들어 있었다

계측 테이블에는 token 컬럼이 하나 있습니다. 게이트는 이걸 세서 "이 앱을 몇 명이 쓰는가"를 판정합니다. 30일치를 전부 받아 토큰을 모양별로 분류해 봤습니다.

token에 들어가던 값 그래서 세어진 것
개발 블로그 url.pathname 경로 개수
띠 궁합 band:3|ctx:all 판정 밴드 종류 수
타로 five-of-wands 카드 종류 수
운세 방문자 id 2종 + 공유 토큰 한 사람이 세 명

대시보드가 "방문자 124명"이라고 말할 때, 그건 124개의 경로였습니다. "카드 이름을 세고 있었다"는 건 비유가 아니라 문자 그대로입니다.

부풀려진 숫자로 판단한 게 처음도 아닙니다. 전에는 리포트가 직전 3일을 다시 실어 3배가 된 걸 두 달 동안 합산했었습니다. 그때는 값이 부풀었고, 이번엔 세는 대상 자체가 틀렸습니다.

진범은 물음표 두 개였다

앱마다 원인이 다른 줄 알았습니다. 아니었습니다. 공용 계측 컴포넌트가 이렇게 생겼습니다.

body: JSON.stringify({ event, token: token ?? visitorToken(), locale, src }),

token ??호출자가 값을 넘기면 방문자 토큰을 덮어씁니다. 그리고 공유 결과 페이지들이 정확히 그렇게 하고 있었습니다.

<TrackEvent event="result_view" token={token} locale={locale} />

여기 token은 공유 링크의 토큰입니다. 결과 1건이 방문자 1명으로 세어집니다. 이 호출부가 몇 개였냐면 19개 앱이었습니다. 하나씩 잘못 짠 게 아니라, 같은 템플릿을 19번 복제한 것이었습니다.

이 지점에서 선택지가 갈립니다. 호출부 19곳을 하나씩 고치겠습니까, 아니면 덮어쓸 수 있다는 사실 자체를 없애겠습니까?

19곳을 고치면 오늘은 초록불이 됩니다. 그리고 다음에 결과 공유 페이지를 하나 더 붙이는 순간 똑같이 깨집니다. 지금 깨져 있는 19곳이 바로 그렇게 생긴 것이니까요.

고침은 프로퍼티 이름 하나

// token은 방문자 식별 전용이다. 공유 토큰은 src 라벨로만 남는다.
const src = new URLSearchParams(window.location.search).get('src')
  ?? (shareToken ? 'shared' : null);
 
body: JSON.stringify({ event, token: visitorToken(), locale, src }),

프로퍼티를 token에서 shareToken으로 바꿨습니다. 이제 token항상 방문자 id이고, 호출자에게는 그걸 덮어쓸 문법 자체가 없습니다. 아직 공유 페이지가 없는 앱 9개도 같이 지웠습니다. 런타임 동작은 안 바뀌지만, 남겨두면 다음 결과 페이지에서 재발하니까요.

부수효과가 오히려 본전이었습니다. 공유 링크로 들어온 방문은 지금까지 ?src가 없어서 전부 "출처 미상"이었습니다. 이제 src='shared'로 찍힙니다. 공유로 들어온 사람을 처음으로 셀 수 있게 됐습니다 — 공유를 늘리려는 실험을 하면서 정작 그 결과를 못 세고 있었다는 뜻이기도 합니다.

표준으로 통일하면 안 되는 키가 있었다

운세 앱에는 방문자 id가 두 개 있었습니다. 계측용 키 하나, 앱 자체 키 하나. 당연히 포트폴리오 표준 키로 합치려 했습니다.

그러면 안 됐습니다. 그 앱 자체 키는 오늘의 운세를 계산하는 시드였습니다. 값을 바꾸면 기존 방문자가 오늘 받는 운세 결과가 통째로 달라집니다. 계측을 고치자고 사용자가 보는 결과를 바꿀 수는 없습니다. 그래서 표준 키가 아니라 시드 쪽으로 통일했고, id 생성 규칙의 .slice(0, 24)까지 옛 함수와 똑같이 맞췄습니다. 다르면 같은 사람이 진입 경로에 따라 다른 시드를 받습니다.

블로그는 반대로 갔습니다. 프록시 서버측 계측이라 방문자를 식별할 수단이 애초에 없습니다(쿠키를 안 심습니다). 그래서 경로를 다른 칸으로 옮기고 token비웠습니다. 게이트가 이 앱을 "측정 불가"로 잡습니다. 그게 사실이기 때문입니다. 0명이라고 말하는 것보다 모른다고 말하는 게 정확합니다.

검증은 한 세션의 이벤트를 줄 세워서

고쳤다는 걸 어떻게 압니까. 로컬에서 한 사람처럼 앱을 쓰고, 그 세션이 남긴 이벤트를 전부 꺼내 봤습니다.

landing · daily_open · verdict_view · move_view · share_click   token=919bb826-b546-42e2-97b7-
result_view (공유 링크로 진입)                                    token=919bb826-…  src=shared

여섯 개가 전부 같은 토큰입니다. 고치기 전이면 이 여섯 건이 세 개의 서로 다른 id 공간에 흩어졌습니다.

솔직한 부분

과거 데이터는 복원하지 못합니다. 30일 창에 쌓인 경로·밴드·카드 슬러그 행들에서 무엇이 사람이었는지 되살릴 방법이 없습니다. 소급 정정하지 않았고, 새 계측만 신뢰하기로 했습니다. 원래 하려던 실험의 표본 기산점도 배포 시각으로 리셋됐습니다.

게이트가 표본이 모자란 채로 판정을 내리던 문제는 전에 한 번 고쳤습니다. 이번엔 표본 수가 아니라 표본의 정체가 문제였습니다. 같은 게이트에서 두 번 다른 방식으로 속은 셈입니다.

집계 코드 쪽에 필터를 하나 넣어 가릴까도 생각했습니다. 안 했습니다. five-of-swords와 랜덤 id는 모양으로 안 갈라집니다. 그럴듯한 정규식을 짜면 오늘은 맞고 다음 콘텐츠 슬러그에서 조용히 틀립니다. 원천에서만 고쳤습니다.

그리고 이 모든 게, 후원 버튼 하나 붙일지 계산하다 나왔습니다. 붙일지 말지는 아직도 모릅니다. 다만 판정에 쓰려던 숫자가 판정에 쓸 수 없는 숫자였다는 건 알게 됐습니다.

자가진단 3개

지금 당신의 계측에 대고 바로 해볼 수 있는 것들입니다.

  1. 모양별로 세어 보세요. 방문자 id 컬럼을 전부 받아 정규식으로 분류합니다. uuid/랜덤 문자열이 아닌 값이 하나라도 섞여 있으면 그 앱의 방문자 수는 이미 틀렸습니다.
  2. ??를 찾아보세요. 계측 함수에서 식별자에 붙은 ??나 기본값 병합은 전부 "호출자가 덮어쓸 수 있다"는 뜻입니다. 그 호출부를 grep 해보면 대개 하나는 엉뚱한 걸 넘기고 있습니다.
  3. 한 세션을 줄 세워 보세요. 앱을 한 번 쓰고 그 사이 이벤트를 전부 꺼내 토큰이 같은지 봅니다. 다르면 그 앱은 퍼널을 계산할 수 없습니다 — 분자와 분모가 다른 공간에 있으니까요.

셋 중에 1번이 제일 쌉니다. 쿼리 하나면 끝나고, 저는 그걸 안 해서 열흘 동안 틀린 분모를 개선이라고 믿었습니다.

당신의 대시보드에서 가장 자주 보는 숫자 하나만 골라, 그 숫자를 만드는 컬럼에 정말 그것만 들어가는지 확인해 보시겠습니까? 저처럼 카드 이름이 나온다면, 어떤 모양이었는지 알려주세요.

관련 글