Devin.KR

문제와 성공 지표

120분 안팎

학습 목표

분자·분모·기간·제외 조건을 정의합니다.

개념

지표는 의사결정의 질문에서 출발합니다

동아리 신청자가 접수를 참가 확정으로 오해하는 Q01 문제를 개선하고 있습니다. 앞 모듈의 R01은 참가 미확정 안내를, R02는 본인 내역으로 가는 행동 이름을 바꾸었습니다. 여기서 버튼 클릭 수만 늘었다고 성공을 선언하면 상태를 잘못 이해한 사람을 놓칩니다. 제품 담당은 먼저 “도움 없이 본인 신청 상태와 참가 확정 여부를 확인할 수 있는가”라는 질문을 씁니다. 그다음 질문에 답할 자료와 계산 규칙을 정합니다. 지표 이름보다 어떤 결정을 도울지가 먼저입니다.

실습 자료와 실행 공간

이번 모듈 미션 starter를 별도 연습 폴더에 풉니다. Python 3 표준 라이브러리와 SQLite만 사용하며 외부 설치나 운영 접속은 필요하지 않습니다. 앞 모듈 solution의 usability.json과 이전 근거 파일을 그대로 포함합니다. 새 제출은 metrics.json에 작성합니다. events.sql은 학습용 가명 이벤트를 새로 만든 provided-fiction 자료이며 앞 관찰을 변환한 로그가 아닙니다. 브라우저 SQL 테스트의 입력은 테이블 생성·삽입 SQL이고 Python 테스트의 입력은 표준 입력 JSON입니다. 두 자료를 합쳐 사람 수를 늘리지 않습니다.

대상과 집계 단위를 고정합니다

T01은 신청 상태를 찾고 참가 미확정을 설명하는 과업입니다. 이벤트의 task_id가 T01인 비테스트 계정 시도를 대상으로 잡습니다. 한 행은 attempt_id 하나의 시도이고 같은 사용자의 재시도는 다른 시도로 셉니다. 한 사람이 여러 번 시도할 수 있으므로 시도 수와 참여자 수는 다릅니다. 고유 사용자 수도 함께 보고하되 시도 완료율의 분모로 섞지 않습니다. event.user_id와 관찰의 participantId는 서로 다른 가명 체계이며 같은 사람이라는 연결 근거가 없습니다.

분자와 분모를 문장으로 정의합니다

분모는 기간 안에 시작한 유효 T01 시도 전체입니다. 분자는 그중 90초 이내 도움 없이 내역을 찾고 참가 미확정을 설명한 success 시도입니다. failure·assisted·unknown은 분모에 포함하고 분자에서는 뺍니다. 도움을 받아 끝낸 것은 가치 있는 회복 경험이지만 독립 수행과 같지 않습니다. unknown은 완료 결과 기록 누락이며 실제 실패라고 단정하지 않습니다. 이 규칙은 보수적인 기록 기준 완료율을 만들며 누락 건수도 따로 확인할 필요가 있습니다. unknown을 사후 삭제하면 분모가 줄어 비교가 유리해질 수 있습니다.

기간은 시작 이상 종료 미만입니다

before는 2026-10-01T00:00:00+09:00 이상 2026-10-08T00:00:00+09:00 미만입니다. after는 그 종료 시각부터 2026-10-15T00:00:00+09:00 미만입니다. 시작 시각으로 소속 기간을 정하므로 10월 8일 0시 시도는 after에만 들어갑니다. 끝나는 시각이 다음 주로 넘어가더라도 시작 기간 소속을 유지합니다. 두 구간은 각각 7일이며 Asia/Seoul 기준입니다. 이벤트 문자열은 고정 길이·같은 +09:00 형식으로 제공하므로 이번 SQLite 예제에서는 문자열 비교를 사용합니다. 시간대가 섞인 실자료에 이 방식을 그대로 적용하지 않습니다.

중복 전송과 실제 재시도를 구별합니다

attempt_id는 기본 키로 중복 ID가 저장되지 않습니다. 동일 시도의 전송 재시도는 수집 전에 같은 ID로 하나만 남겼다는 fixture 계약입니다. 다른 ID를 가진 같은 사용자의 두 시도는 실제 재시도이므로 둘 다 셉니다. DISTINCT user_id로 분모만 줄이면서 success 건수는 그대로 두면 완료율이 100%를 넘을 수도 있습니다. 사용자 완료율을 새로 원한다면 사용자별 최초 시도인지 기간 내 한 번 이상 성공인지부터 따로 정의해야 합니다. 지금은 시도 기준을 유지합니다.

테스트 계정 제외는 결과를 보기 전에 정합니다

is_test가 1인 행과 T01 밖 과업은 제외합니다. 개발자가 반복 확인한 성공 로그가 포함되면 사용자 어려움이 희석됩니다. 실패했다는 이유로 계정을 테스트라고 바꾸지 않습니다. 제외 기준과 제외 전후 건수를 함께 남기고 두 기간에 같은 조건을 적용합니다. is_test는 0 또는 1이고 누락이 없다는 입력 계약을 갖습니다. 실제 자료에 NULL이 있다면 자동으로 일반 계정으로 취급하기 전에 계정 분류 출처와 누락 처리를 담당자에게 확인합니다.

빈 분모는 0%와 구별합니다

유효 시도가 0건이면 완료율은 계산할 수 없어 null 또는 산출 불가로 보고합니다. 시도가 있었는데 success가 0건이면 0%입니다. 두 경우를 같은 0%로 쓰면 이용자가 없다는 사실과 이용자가 목적을 달성하지 못했다는 사실을 혼동합니다. SQL의 건수는 0으로 출력해도 비율까지 0이라고 추정하지 않습니다. 보고서에 분자·분모를 같이 적으면 빈 기간을 쉽게 알아볼 수 있습니다. 빈 자료를 처리하는 규칙도 지표 정의의 일부입니다.

시간 지표는 성공 조건을 함께 적습니다

시간은 성공 시도의 duration_seconds만 사용하며 시작부터 독립 완료까지의 초입니다. 실패 시도는 90초 제한에 도달했다고 가정해 평균에 넣지 않습니다. assisted 시간도 진행자 개입이 있으므로 독립 완료 시간과 분리합니다. 성공 시간이 빠르더라도 실패가 늘면 전체 경험이 좋아졌다고 말하기 어렵습니다. 완료율과 성공 시간의 표본 수를 함께 제시합니다. 이번 events.sql의 duration_seconds는 성공 행에만 있고 m07 관찰 사건의 at는 완료 시간 필드가 아니므로 그대로 옮기지 않습니다.

증거 종류마다 주장 범위가 다릅니다

m07의 v1 세션 S01·S02·S03은 3건 중 독립 성공 1건이고 v2의 V01은 새 가상 참여자 1건의 성공입니다. 전후 과업과 완료 기준은 같아도 참여자 수와 사람은 다릅니다. 이벤트는 더 많은 시도를 흉내 낸 별도 연습 자료입니다. 관찰은 어떤 표현을 오해했는지 설명하고 집계는 정의한 조건에서 몇 건이 있었는지 요약합니다. 숫자가 비슷하다는 이유로 같은 출처라고 합치지 않습니다. 가상 자료 계산을 실제 조사나 운영 성과처럼 쓰지 않습니다.

목표값과 보호 지표를 구분합니다

현재 표본을 보고 목표를 소급해 맞추면 의사결정 기준이 바뀝니다. 이 연습에서는 상승 여부와 한계를 먼저 보고 추가 검증 여부를 정합니다. 실제 적용 전에는 팀이 의미 있는 변화 수준과 관찰 기간을 합의합니다. 보호 지표는 개선하면서 악화되면 안 되는 결과입니다. 예를 들어 완료율이 올라도 참가 확정 오해나 도움 의존이 증가한다면 문구를 다시 검토합니다. 보호 지표도 대상과 판정 규칙을 써서 클릭 증가만을 좇는 결정을 피합니다.

지표 계약을 동료가 재현하도록 씁니다

metrics.json의 contract에는 과업·단위·분자·분모·시간대·구간·제외·중복·빈 분모·시간 조건을 적습니다. “최근 사용자 성공률” 같은 표현은 누가 언제 무엇을 했는지 숨깁니다. 동료에게 10월 8일 경계 시도와 도움 후 완료를 하나씩 주고 어느 칸에 들어가는지 물어봅니다. 판단이 다르면 계산 코드보다 계약을 먼저 보완합니다. 다음 레슨에서 계약을 SQL 조건으로 바꿉니다. JSONDecodeError가 보이면 따옴표와 쉼표를 먼저 고치며 FAIL contract는 형식뿐 아니라 고정된 계산 조건과 다른 항목을 읽으라는 뜻입니다.

따라하기

m07 근거를 보존합니다

미션 starter의 usability.json에서 Q01·E003·E006·E005, S01~S03, R01·R02, V01을 찾아 기록합니다. I01만 채택 범위이며 I02·I03 보류와 D01 미결을 그대로 둡니다.

지표 계약을 적습니다

metrics.json contract에서 T01 시도 단위·success 분자·유효 시도 분모·7일 구간·테스트 제외·중복·빈 분모·시간 조건을 채웁니다. 전후 경계 시도를 동료가 같은 기간으로 분류하는지 확인합니다.

빈 분모와 기록 기준을 계산합니다

다음 독립 예제를 실행하고 결과의 대상과 단위를 확인합니다.

for success, attempts in [(1, 3), (0, 0), (0, 2)]:
    rate = None if attempts == 0 else round(100 * success / attempts, 1)
    print(success, attempts, rate)

실행 결과

1 3 33.3
0 0 None
0 2 0.0

출처별 보고 표를 설계합니다

observationSummary와 eventResults를 각각 작성할 칸으로 남깁니다. 전자는 가상 카드 관찰, 후자는 별도 가명 이벤트이며 숫자를 합치지 않는 이유를 interpretation에 기록합니다.

확인 문제

실습

metrics.json의 contract에 T01·시도 단위·분자·분모·Asia/Seoul·두 구간의 시작 포함 종료 제외·테스트/다른 과업 제외·재시도와 중복 ID 처리·빈 분모·성공 시간 조건을 작성합니다. 경계 시도, assisted, unknown, 반복 사용자를 동료가 같은 기준으로 분류하면 제출합니다. 실제 운영 측정으로 표현하지 않습니다.

더 읽기

면접 질문

  • 기능 개선 여부를 확인할 지표를 정하는 방법을 설명해 주시면 됩니다.