LabHub
배우기 러닝패스 코스

デバッグ実戦

動く顧客と動かない顧客 — 差分表で候補を消す

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

성공 표본과 실패 표본을 속성별로 갈라 차이표를 만들고, 모든 실패에 있고 어떤 성공에도 없는 값만 후보로 남긴다. 완벽하게 상관하는 가짜 후보를 새 표본과 개입 실험으로 각각 떨어뜨리고, 한 속성으로는 갈리지 않는 상호작용까지 찾아낸다.

왜 중요한가

"어떤 고객은 되고 어떤 고객은 안 됩니다" 는 나쁜 소식처럼 들리지만 사실은 좋은 소식이다. 되는 쪽이 있다는 것은 대조군이 있다는 뜻이다. 실패 로그만 파면 모든 줄이 수상해 보이지만, 성공 로그에도 같은 줄이 있으면 그것은 원인이 아니라 배경이다. 이 실습에서 어려운 것은 표를 만드는 코드가 아니라 후보가 둘 남았을 때 무엇을 하는가다. 같은 날 배포된 두 가지가 언제나 함께 다니면 표본만으로는 구별할 수 없다. 이때 그럴듯한 쪽을 골라 보고하면 절반의 확률로 며칠을 버린다. 가르는 길은 둘뿐이다. 둘이 갈라지는 표본을 더 얻거나, 속성 하나만 바꾸고 나머지를 고정해 결과가 뒤집히는지 보는 것이다. 앞은 관찰이고 뒤는 실험이며, 인과를 말할 수 있는 것은 실험뿐이다. 채점기는 여러분의 결론을 믿지 않는다. 채점기가 원인과 가짜 후보를 매번 다른 자리에 심은 표본을 만들어 여러분의 도구를 실제로 실행하고, 골라낸 후보 집합을 심어 둔 답과 대조한다.

단계

  1. /root/diff/gen_cases.py 를 만들어 실행해 /root/diff/cases.json(240건), cases2.json(120건), cases3.json(180건), repro.py 를 만드세요.
  2. /root/diff/table.json 에 속성별 값마다 실패 건수와 성공 건수를 적은 차이표를 만드세요.
  3. /root/diff/differential.py 를 만들어 모든 실패에 있고 어떤 성공에도 없는 값을 후보로 고르게 하세요.
  4. /root/diff/candidates.json 에 후보 목록과 지운 후보를 근거와 함께 적으세요.
  5. 새 표본을 합쳐 다시 돌리고 /root/diff/verdict.json 에 살아남은 원인 하나와 떨어진 후보, 그 근거가 된 표본 번호를 적으세요.
  6. differential.py 에 짝 분석을 붙이고 /root/diff/pairs.json 에 cases3.json 의 짝 후보를 적으세요.
  7. repro.py 로 속성 하나만 바꿔 결과가 뒤집히는지 확인하고 /root/diff/confirm.json 에 적으세요.
  8. /root/diff/summary.json/root/diff/diff_report.md 에 네 절로 보고하세요.

참고

표본과 재현기 손에 쥐기

/root/diff/gen_cases.py 를 만들어 실행해 /root/diff/cases.json(240건)과 cases2.json(120건), cases3.json(180건), repro.py 를 만드세요.

현장에서 손에 쥐는 것은 결론이 아니라 표본입니다. 이 스크립트를 그대로 저장해 실행하면 됩니다. 만들어진 cases.json 을 잠깐 열어 성공과 실패가 어떤 모양으로 적혀 있는지 보세요.

속성별 차이표 만들기

/root/diff/table.json 에 failures·successes 와 attributes 를 적으세요. attributes 는 속성 이름마다 값별로 {"fail": 건수, "ok": 건수} 를 담습니다. case_id 와 outcome 은 속성이 아닙니다.

표가 먼저입니다. 표 없이 눈으로 훑으면 '실패에 많이 보이는 값' 과 '실패에만 있는 값' 을 구별하지 못합니다. 속성 이름은 표본에서 그대로 읽어 오세요 — 손으로 적으면 하나를 빠뜨리고, 빠뜨린 속성은 영영 후보가 되지 않습니다.

후보를 고르는 도구 만들기

/root/diff/differential.py 를 만들어 모든 실패에 있고 어떤 성공에도 없는 속성=값 을 candidates 로, 모든 실패에 있지만 성공에도 있는 값을 eliminated 로 내게 하세요. --cases 는 여러 번 줄 수 있어야 합니다.

집합 연산 두 번이면 끝납니다. 실패 표본들의 교집합을 구하고, 성공 표본들의 합집합을 뺍니다. 뺄셈에서 사라진 값이 eliminated 입니다. 사람이 표를 눈으로 훑는 대신 이 두 줄을 쓰는 이유는, 속성이 스무 개가 되어도 절차가 같기 때문입니다.

후보와 지운 후보를 근거와 함께 적기

/root/diff/candidates.json 에 candidates(후보 목록)와 eliminated(지운 후보) 를 적으세요. eliminated 의 각 항목은 {"attribute": "속성=값", "reason": "…"} 이고, reason 에는 그 값이 나온 성공 표본의 건수가 숫자로 들어가야 합니다.

지운 것을 적어 두는 이유는 다음 사람이 같은 길을 다시 걷지 않게 하기 위해서입니다. '모든 실패에 token 인증이 있었다' 는 사실은 성공 몇 건에도 token 이 있었다는 사실과 함께 놓일 때만 뜻이 생깁니다. 그 숫자를 표에서 가져오세요.

새 표본으로 가짜 후보 떨어뜨리기

cases.json 과 cases2.json 을 함께 넣어 다시 돌리고 /root/diff/verdict.json 에 cause(살아남은 원인 하나), eliminated_by_new_batch(떨어진 후보), evidence_case_ids(근거가 된 cases2.json 의 건 번호)를 적으세요.

표본만으로 둘을 구별할 수 없었던 이유는 자료에 둘을 가르는 조합이 없었기 때문입니다. 새 표본에 그 조합이 들어 있습니다. 근거가 되는 건은 두 종류입니다 — 떨어질 속성을 가졌는데 성공한 건, 또는 그 속성이 없는데 실패한 건입니다.

한 속성으로 갈리지 않는 경우

differential.py 에 --pairs 를 붙여 짝 후보를 찾게 하고, cases3.json 에 돌려 /root/diff/pairs.json 에 single_candidates 와 pair_candidates 를 적으세요. 짝은 두 값을 담은 목록으로 적습니다.

단독 후보가 하나도 없는 표본이 있습니다. 두 값이 함께일 때만 실패하기 때문입니다. 실패 전부에 있는 값들 중 두 개씩 짝지어, 그 둘을 함께 가진 성공이 하나도 없는 짝을 찾으세요. 이미 단독으로 후보인 값이 낀 짝은 새로운 정보가 아닙니다.

속성 하나만 바꿔 뒤집히는지 보기

/root/diff/confirm.json 에 claim(주장하는 원인), base(기준 속성 조합 일곱 개), flipped_attribute, base_outcome, flipped_outcome 을 적으세요. base 와 뒤집은 조합은 정확히 한 속성만 달라야 하고 두 결과는 서로 달라야 합니다.

표본은 관찰이고 재현기는 실험입니다. 나머지를 전부 고정한 채 주장하는 속성 하나만 바꿔 결과가 뒤집히면, 그 속성은 상관이 아니라 원인입니다. 두 가지를 한꺼번에 바꾸면 어느 쪽이 뒤집었는지 알 수 없습니다.

지운 것까지 한 장으로 보고하기

/root/diff/summary.json 에 week1_cases·week1_candidates·cause·eliminated_by_new_batch·pair_only_tenant·intervention 을 적고, /root/diff/diff_report.md## 무엇이 갈렸나 ## 무엇을 지웠나 ## 상관인가 원인인가 ## 남은 위험 네 절로 보고하세요.

보고서에 남은 후보만 적으면 다음 사람이 같은 길을 다시 걷습니다. 지운 후보와 지운 근거를 함께 적으세요. 개입 실험의 두 결과도 숫자가 아니라 낱말이지만 증거입니다.