신청자 수 0이 '없음'이 아니라 '모름'일 때
한눈에 답변
체험단 플랫폼 8곳이 신청자 수를 목록에 싣지 않는데, DB 컬럼이 not null default 0 이라 '모름'이 '0명'으로 저장됐다. 그 값을 그대로 평균 내면 경쟁률이 실제보다 낮게 나온다(4.87:1 → 정정 후 5.76:1). 하필 이 통계는 '인용해도 됩니다'라고 공개해 둔 페이지였다.
리뷰로거는 체험단 플랫폼 61곳의 공고를 모아 보여주는 서비스다. 각 공고에는 모집 인원과 신청자 수가 있고, 그 둘을 나눠 경쟁률을 계산한다. 이 숫자를 사이트 곳곳에서 쓴다 — 정렬 기준으로도 쓰고, “경쟁 낮은 순” 배지로도 쓰고, /insights 페이지에서는 “이 통계, 블로그·기사에 인용하셔도 됩니다”라고 공개까지 해 뒀다.
증상
/insights 를 확인하던 중 숫자가 이상하다는 느낌이 들었다. 평균 경쟁률이 4.87:1, 신청자가 모집 인원보다 적은 “신청 유리” 공고가 60%. 방문형 체험단(매장에 직접 가야 하는 것)치고는 너무 여유로운 숫자였다.
원인
DB 스키마를 열어 봤다. applicant_count int not null default 0. 이 한 줄이 문제였다 — 신청자 수를 아예 안 알려주는 플랫폼과 신청자가 0명인 플랫폼이 저장되는 순간 똑같은 값이 된다.
실측했다. 모집 인원이 공개된 공고 3,861건 중, 8개 플랫폼 597건이 신청자 수 표본 전건이 0이었다. 표본이 10~204건인데 단 한 번도 0이 아닌 적이 없다는 건 우연이 아니다 — 그 플랫폼들은 애초에 신청자 수를 목록에 표시하지 않는다.
무엇을 고쳤나
“신청자 수 미공개” 플랫폼 목록을 별도 파일로 만들고, 경쟁률을 계산하는 모든 자리(통계 페이지, 정렬 로직, 배지 표시)에서 그 플랫폼을 빼도록 했다. 뺀 뒤 값은 5.76:1, “신청 유리” 47%.
가장 중요했던 건 정렬 로직이었다. 저장값이 0이라, 빼지 않으면 “경쟁 낮은 순” 목록의 맨 앞을 전부 저 8개 플랫폼의 공고가 차지한다 — 경쟁률을 알 수 없는 공고가 “가장 경쟁이 낮은 공고”로 둔갑하는 것이다. 그 정렬이 약속한 것과 정확히 반대였다.
이 일에서 남은 것
“0” 이라는 값은 두 가지를 동시에 가리킬 수 있다 — 진짜 0, 그리고 모른다는 뜻의 0. 데이터베이스 스키마가 그 둘을 구분하지 않으면, 그 차이는 화면에 나가는 순간까지 아무도 모른 채 지나간다. 재발을 막기 위해 실데이터로 그 목록이 최신인지 대조하는 검사도 함께 만들었다 — 새 플랫폼이 붙거나, 기존 플랫폼이 공개 정책을 바꾸면 그 검사가 알려준다.