LabHub
배우기 러닝패스 코스

In Front of an Unfamiliar System

From 200 lines and 12 steps down to two lines and four steps

LabHub 에서 이어서 보기

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

목표

고객이 보내 온 장애 꾸러미(처리기 하나, 피드 200줄, 재현 절차 12단계)를 최소 재현 사례로 줄인다. 먼저 "아직도 같은 실패인가" 를 기계가 판정하게 만들고, 그 판정기로만 줄이고, 남은 것 하나를 빼면 재현이 멈춘다는 것까지 증명한다.

왜 중요한가

고객이 적어 준 재현 절차는 대개 그 사람이 그날 한 일 전부다. 그 전부를 안고 원인을 찾으면 봐야 할 조합이 폭발한다. 그렇다고 줄이기부터 시작하면 더 위험하다 — 한 줄을 뺐더니 프로그램이 다른 오류로 죽고, 그것도 오류니까 아직 재현된다고 착각하게 된다. 그렇게 나온 사례는 우리가 쫓던 결함과 상관없는 다른 결함을 재현한다. 그래서 순서가 있다. 판정기를 먼저 만들고, 그 판정기로만 줄인다. 판정기는 종료 코드와 그 실패에만 나오는 서명 문자열을 함께 본다. 실행 시각이나 임시 파일 이름처럼 실행마다 달라지는 것은 판정에 넣지 않는다. 줄이는 일은 기계가 한다. 한 줄씩 빼 보면 줄 수만큼 판정기를 부르지만, 후보를 덩어리로 갈라 보는 델타 디버깅(ddmin)은 그 횟수를 줄 수의 로그에 가깝게 떨어뜨린다. 채점기는 여러분이 적어 낸 숫자를 믿지 않는다. 오라클에는 채점기가 만든 여러 후보를 넣어 보고, 축소기에는 매번 다른 자리에 답을 숨긴 256줄짜리 입력을 주어 결과와 판정기 호출 횟수를 함께 잰다.

단계

  1. /root/mre/gen_case.py 를 만들어 실행해 /root/mre/app/ingest.py, /root/mre/input.txt(200줄), /root/mre/repro/steps.txt(12단계)를 펼치세요.
  2. /root/mre/oracle.py 를 만드세요. --input 으로 받은 후보가 우리가 쫓는 실패를 내면 종료 코드 0, 아니면 1 입니다. 다른 오류는 재현이 아닙니다.
  3. 오라클로 피드를 줄여 /root/mre/min_input.txt 를 만드세요. 남은 줄은 원본의 줄이고 원본 차례를 지킵니다.
  4. /root/mre/minimality.json 에 남은 줄마다 그것을 뺐을 때 재현되는지를 적어 1-최소임을 증명하세요.
  5. /root/mre/shrink.py 에 델타 디버깅(ddmin)을 구현하세요. --input --oracle --out 을 받고, 판정기를 부르는 횟수가 줄 수에 비례하지 않아야 합니다.
  6. 재현 절차 12단계를 줄여 /root/mre/min_steps.txt 를 만드세요. 남은 단계는 원본 줄 그대로이고 차례를 지킵니다.
  7. 값을 바꿔도 재현되는지 확인해 /root/mre/generalize.json 과 변형 파일 셋을 남기세요.
  8. /root/mre/mre_report.md 에 네 절로 보고하세요.

참고

장애 꾸러미 펼치기

/root/mre/gen_case.py 를 만들어 실행해 /root/mre/app/ingest.py, /root/mre/input.txt(200줄), /root/mre/repro/steps.txt(12단계)를 만드세요.

현장에서 받는 것은 프로그램과 데이터와 절차 셋뿐입니다. 펼친 뒤에는 절차를 한 번 그대로 돌려 실패를 눈으로 보세요 — MRE_WORK 를 아직 없는 디렉터리로 잡고 돌립니다.

같은 실패인지 기계가 판정하게 하기

/root/mre/oracle.py 를 만드세요. --input 으로 받은 후보가 우리가 쫓는 실패를 내면 종료 코드 0, 아니면 1 입니다. 설정 파일은 오라클이 스스로 만들고, 종료 코드와 서명 문자열을 함께 봅니다.

0 이 아닌 종료 코드를 전부 재현으로 보면, 줄이다가 전혀 다른 오류로 넘어간 것을 눈치채지 못합니다. 이 처리기는 설정을 못 읽으면 2, 우리가 쫓는 결함이면 3, qty 줄이 하나도 없으면 4 로 끝납니다. 표준오류의 서명 문자열도 함께 보세요.

피드를 줄이기

오라클로 피드를 줄여 /root/mre/min_input.txt 를 만드세요. 남은 줄은 전부 원본 input.txt 의 줄이어야 하고 원본 차례를 지켜야 하며, 어느 한 줄을 빼면 재현이 멈춰야 합니다.

이 단계는 손으로 해도 됩니다. 한 줄씩 빼 보면서 재현이 유지되는 줄만 남기는 방법이 가장 단순합니다. 200번쯤 판정기를 부르게 되는데, 그 느림이 5단계에서 ddmin 을 만드는 이유입니다.

남은 줄이 왜 다 필요한지 증명하기

/root/mre/minimality.json 에 min_input.txt 의 줄마다 그 줄을 뺐을 때 재현되는지를 적으세요. 모든 줄에서 재현이 멈추면 minimal 은 true 입니다. lines 는 min_input.txt 의 차례 그대로입니다.

1-최소는 '남은 것 중 어느 하나를 빼도 재현이 멈춘다' 는 뜻입니다. 이 증명이 없으면 '왜 이 줄이 필요한가' 라는 질문에 답할 수 없고, 받는 쪽도 그냥 믿어야 합니다. 판정은 오라클에게 맡기고 결과만 적으세요.

줄이기를 자동화하기

/root/mre/shrink.py 에 델타 디버깅(ddmin)을 구현하세요. --input --oracle --out 을 받고, 원본이 재현되는지 먼저 확인한 뒤 줄이며, 판정기 호출 횟수가 줄 수에 비례하지 않아야 합니다.

한 줄씩 빼는 방법은 줄 수만큼 판정기를 부릅니다. ddmin 은 후보를 n 조각으로 갈라 조각 하나만으로 재현되는지 먼저 보고, 안 되면 조각 하나를 뺀 나머지로 재현되는지 봅니다. 둘 다 아니면 더 잘게 갈라 반복합니다. 채점기는 256줄짜리 입력에 여러분의 축소기를 돌리고 판정기를 몇 번 불렀는지 셉니다.

재현 절차도 줄이기

재현 절차 12단계를 줄여 /root/mre/min_steps.txt 를 만드세요. 남은 단계는 steps.txt 의 줄 그대로이고 원본 차례를 지켜야 하며, 어느 한 단계를 빼면 재현이 멈춰야 합니다.

절차를 시험할 때마다 MRE_WORK 를 아직 없는 디렉터리로 새로 잡으세요. 앞 실행이 남긴 설정 파일이 있으면 '설정을 만드는 단계' 를 빼도 재현되어, 그 단계가 필요 없다는 잘못된 결론이 나옵니다. 재현 판정은 표준오류에 서명 문자열이 나오는지로 합니다.

값이 아니라 구조인지 확인하기

최소 사례에서 값을 바꾼 판과 구조를 바꾼 판을 만들어 /root/mre/generalize.json 에 적으세요. 변형은 셋이고, 값만 바꾼 /root/mre/min_input_generic.txt 는 재현되어야 하며 나머지 둘은 재현되지 않아야 합니다. 세 파일 모두 실제로 남기세요.

남은 두 줄이 우연한 값 때문인지, 구조 때문인지를 가르는 단계입니다. 숫자를 다른 숫자로 바꿔도 재현되면 원인은 그 숫자가 아닙니다. 반대로 쉼표를 마침표로 바꾸거나 로케일을 바꾸면 멈추는 것을 보이면, 원인이 두 조건의 조합이라는 것이 증명됩니다.

무엇을 재현이라고 불렀는지 적기

/root/mre/mre_report.md## 무엇을 재현이라고 불렀나 ## 얼마나 줄였나 ## 남은 줄이 왜 다 필요한가 ## 남은 가정 네 절로 적으세요. 원본과 최소 사례의 줄 수와 단계 수, 오라클이 보는 종료 코드와 서명 문자열이 모두 나와야 합니다.

받는 쪽은 입력 두 줄만으로는 '이게 왜 문제인가' 부터 묻습니다. 무엇을 같은 실패로 보았는지 먼저 적고, 그다음 얼마나 줄였는지와 왜 더 못 줄이는지를 적으세요. 마지막 절에는 값을 바꿔도 재현된다는 사실과 무엇을 바꾸면 멈추는지를 적습니다.