낯선 시스템 앞에서 · 최소 재현 사례로 줄이기 · 이론
줄이기 전에 판정기부터 만든다
한 줄 요약
최소 재현 사례를 만드는 일의 절반은 줄이는 기술이 아니라 "아직도 같은 실패인가" 를 기계가 판정하게 만드는 일이다. 판정기가 없으면 줄이는 일은 추측이 된다.
왜 이게 필요했나
고객이 보내 준 재현 절차는 대개 그 사람이 그날 한 일 전부다. 12단계짜리 절차와 200줄짜리 입력 파일이 딸려 온다. 그 전부를 안고 원인을 찾으려 하면 봐야 할 조합이 폭발하고, 아무 데서나 시작하게 되고, 이틀 뒤에도 같은 자리에 있다.
줄여야 한다는 것은 다들 안다. 문제는 줄이다가 길을 잃는다는 것이다. 한 줄을 빼면 프로그램이 다른 오류로 죽는다. 다른 오류도 오류니까 "아직 재현된다" 고 착각하고 계속 줄인다. 그렇게 나온 세 줄짜리 입력은 우리가 찾던 결함과 아무 상관이 없는 다른 결함을 재현한다. 그 세 줄을 들고 고객 개발팀에 가면 하루가 날아간다.
왜 판정기가 먼저인가
그래서 순서가 있다. 줄이기 전에 판정기를 만든다. 판정기(오라클)는 후보 입력 하나를 받아 "지금 이것이 우리가 쫓는 그 실패를 내는가" 에만 답하는 프로그램이다. 사람이 눈으로 보는 판정은 축소에 쓸 수 없다. 축소는 후보를 수십에서 수백 번 시험하는 일이고, 그 횟수를 사람이 감당할 수 없기 때문이다.
판정기가 보는 것은 세 가지쯤이다.
- 종료 코드 — 0 이 아니라는 것만으로는 부족하다. 어느 코드인지까지 본다.
- 서명 문자열 — 그 실패에만 나오는 오류 이름이나 예외 이름.
ERR-QTY-COMMA처럼 좁을수록 좋다. - 자리 — 필요하면 어느 단계에서 났는지까지. 같은 예외가 두 자리에서 나는 프로그램이 있다.
반대로 판정기가 보면 안 되는 것도 있다. 실행 시각, 임시 파일 이름, 로그 줄 수처럼 실행마다 달라지는 것은 판정에 넣지 않는다. 넣으면 같은 후보가 어떤 날은 재현되고 어떤 날은 안 된다.
어떻게 동작하나
판정기가 생기면 줄이는 일은 기계가 한다. 가장 단순한 방법은 한 줄씩 빼 보는 것이다. 200줄이면 판정기를 200번 부르고, 한 번 지나갈 때마다 남은 줄이 줄어드니 또 한 바퀴를 돈다. 맞기는 한데 느리다.
[Zeller 와 Hildebrandt 의 ddmin](https://www.st.cs.uni-saarland.de/papers/tse2002/)은 이것을 덩어리 단위로 한다. 후보를 n 조각으로 갈라서, 조각 하나만으로 재현되는지를 먼저 보고, 안 되면 조각 하나를 뺀 나머지로 재현되는지를 본다. 둘 다 아니면 더 잘게 갈라 같은 일을 반복한다. 원인이 되는 줄이 둘뿐이라면 부르는 횟수가 줄 수의 로그에 가깝게 떨어진다 — 256줄에서 두 줄을 찾는 데 판정기를 백 번 남짓만 부르면 된다.
[a b c d e f g h] 전체가 재현된다 갈라 본다 → [a b c d] [e f g h] [a b c d] 재현 안 됨 [e f g h] 재현 안 됨 ← 조각 하나만으로는 안 된다 나머지로 본다 → [e f g h](= a b c d 를 뺀 것) 안 됨, [a b c d] 안 됨 더 잘게 → [a b] [c d] [e f] [g h] [a b] 뺀 나머지 재현됨 → 후보가 [c d e f g h] 로 줄었다 … 반복 …결과: [c g] — 여기서 c 나 g 를 빼면 재현되지 않는다결과가 1-최소(1-minimal) 라는 말은 남은 것 중 어느 하나를 빼도 재현이 멈춘다는 뜻이다. "가장 작다" 는 뜻이 아니다 — 전혀 다른 더 작은 조합이 있을 수도 있다. 그래서 축소를 끝낸 뒤에는 남은 줄 하나하나를 빼 보고 멈추는 것을 따로 증명해 적어 둔다. 이 증명이 없으면 "왜 이 줄이 필요한가" 라는 질문에 답할 수 없다.
현장에서 만나는 모습
첫째, 절차도 입력과 똑같이 줄인다. 12단계 중 실제로 필요한 것이 네 단계뿐인 경우가 흔하다. 나머지 여덟 단계는 담당자의 습관이다. 절차를 줄이면 "환경 탓" 이라는 막연한 설명이 사라진다.
둘째, 깨끗한 자리에서 돌린다. 앞 실행이 남긴 파일이 있으면 "설정 파일을 만드는 단계" 를 빼도 재현된다. 그러면 그 단계가 필요 없다는 잘못된 결론이 나온다. 절차를 시험할 때마다 빈 디렉터리를 새로 잡는다.
셋째, 줄인 사례가 진짜인지 값을 바꿔 확인한다. 남은 두 줄이 locale=de 와 qty=1,5 라면, 숫자를 9,25 로 바꿔도 재현되는지 본다. 재현되면 원인은 그 숫자가 아니라 쉼표와 로케일의 조합이다. 여기까지 해야 고객 개발팀이 곧바로 고칠 수 있는 보고가 된다.
넷째, 최소 사례는 판정기와 함께 보낸다. 입력 두 줄만 보내면 받는 쪽은 "이게 왜 문제인가" 부터 묻는다. 판정기를 함께 보내면 받는 쪽이 자기 자리에서 한 번 돌려 보고 곧바로 같은 자리에 선다.
실무에서 진짜 중요한 것
- 판정기를 먼저 만든다. 이 순서를 바꾸면 줄이기는 추측이 된다.
- 아무 실패나 같은 실패가 아니다. 종료 코드와 서명을 함께 본다.
- 1-최소를 증명해 적는다. 줄마다 빼 보고 멈추는 것을 기록으로 남긴다.
- 값이 아니라 구조인지 확인한다. 값을 바꿔도 재현되면 원인은 구조다.
다음 실습에서 할 것
(가상) 대림물산이 보내 온 장애 꾸러미를 펼친다. 처리기 하나, 피드 200줄, 재현 절차 12단계다. 먼저 "같은 실패" 를 판정하는 오라클을 만들고, 그 오라클로 피드를 줄이고, 남은 줄 하나하나를 빼 보아 1-최소임을 증명한다. 그다음 ddmin 을 직접 구현해 축소를 자동화한다 — 채점기는 매번 다른 자리에 답을 숨긴 256줄짜리 입력에 여러분의 축소기를 돌리고, 결과가 맞는지와 판정기를 몇 번 불렀는지를 함께 본다. 마지막으로 절차 12단계를 줄이고, 값을 바꿔도 재현되는지 확인해 보고서로 낸다.