개념
이 레슨의 경계 — 원인 진단이 아니라 운영 규칙
m13 레슨 6은 흔들리는 테스트 하나를 붙잡고 왜 흔들리는지 좁히는 방법을 다뤘다. 대기 전략, 공유 상태, 순서 의존, 외부 의존 — 네 관점으로 원인을 분류하고 재시도가 해결책이 아닌 이유를 짚었다. 그 레슨은 테스트 한 건의 진단 이다.
이 레슨은 그 진단을 할 수 있을 만큼의 정보를 조직이 모으고, 진단 전까지 그 테스트를 어떻게 다루고, 누가 언제까지 고치고, 고쳐졌는지 어떻게 판정하는지를 다룬다. 500개 테스트 중 어떤 20개가 흔들리는지 모르면 m13 의 진단 기법은 쓸 자리가 없다. 플래키 관리의 절반은 목록을 갖는 일 이다.
플래키를 측정 가능하게 정의한다
"가끔 깨지는 테스트"는 정의가 아니다. 집계할 수 없고, 따라서 줄었는지도 알 수 없다. 운영에 쓸 정의는 이렇다.
플래키 테스트 — 동일한 환경 좌표와 동일한 커밋에서 실행했을 때 결과가 통과와 실패로 갈리는 테스트.
이 정의의 두 전제가 중요하다. 동일한 커밋 이 아니면 제품 변경이 원인일 수 있고, 동일한 환경 좌표 가 아니면 환경 변경이 원인일 수 있다. 레슨 3의 좌표 기록이 없으면 이 정의를 적용조차 할 수 없다 — 그래서 플래키 관리는 좌표 기록 다음에 온다.
정의에서 명확히 제외해야 할 것도 있다.
| 현상 | 플래키인가 | 어디로 보내는가 |
|---|---|---|
| 같은 커밋·같은 좌표에서 결과가 갈린다 | 그렇다 | 이 레슨의 장부 |
| 특정 커밋 이후로 항상 실패한다 | 아니다 | 제품 결함 또는 테스트 결함 (레슨 7) |
| 특정 시간대에만 실패한다 | 조건부 — 좌표 밖 요인 | 환경 문제로 분류 후 원인 제거 (레슨 3) |
| 환경 장애 시간대의 실패 | 아니다 | 집계 제외 표시 (레슨 1의 소유 규칙) |
| 병렬 수를 올린 뒤 생긴 실패 | 플래키처럼 보이지만 설비 자원 문제일 수 있다 | 러너 자원 확인 먼저 (레슨 2) |
마지막 행이 실무에서 가장 자주 오분류된다. 자원이 모자란 러너의 타임아웃은 플래키 장부를 오염시키고, 테스트를 고치려는 헛수고를 만든다. 장부에 넣기 전에 설비를 한 번 본다 는 절차를 규칙에 넣어 두는 것이 좋다.
탐지 — 세 가지 신호를 모은다
플래키는 한 번의 실행으로는 알 수 없다. 같은 조건의 복수 실행을 비교해야 한다. 실무에서 쓰는 신호는 셋이고, 셋 다 두는 것이 가장 좋다.
① 재실행 결과 차이(가장 값싸다). 실패한 테스트를 같은 실행 안에서 한 번 더 돌려 통과하면, 그 건은 "재실행 통과"로 기록된다. 이 기록 자체가 플래키 신호다. 주의할 점은 재실행을 조용히 성공으로 덮지 않는 것 이다. 재시도로 통과한 결과를 그냥 초록으로 보고하면 신호가 사라진다. m55 레슨 3이 리포트에서 이 둘을 가르는 방법을 다뤘고, 여기서는 그 기록을 집계에 쓴다.
② 이력 집계. 같은 테스트의 지난 N 회 결과를 모아 통과·실패가 섞였는지 본다. 커밋이 다른 실행도 섞이지만, 윈도우가 길어지면 제품 변경의 영향은 평균화되므로 실용적으로 쓸 수 있다. 윈도우는 보통 최근 20~50회 실행으로 둔다.
③ 전용 반복 실행. 주기적으로(예: 주 1회 야간) 같은 커밋에서 테스트 묶음을 여러 번 반복 실행한다. 정의에 가장 충실한 신호이고 가장 비싸다. 전체를 반복하지 않고 ①·②로 의심 목록을 뽑은 뒤 그 목록만 10회 반복하면 비용이 감당 가능해진다.
플래키 탐지 파이프라인
매 실행 → 재실행 통과 건을 'flaky-signal' 로 기록 (신호 ①)
매일 집계 → 최근 30회 윈도우에서 결과가 섞인 테스트 목록 생성 (신호 ②)
주 1회 야간 → 위 목록만 같은 커밋으로 10회 반복, 갈리는 건을 확정 (신호 ③)
확정 건 → 플래키 장부에 등록, 임계 초과 시 자동 격리 심사플래키율 — 두 가지를 따로 센다
플래키율이라는 말은 두 가지로 쓰이고, 섞으면 대화가 꼬인다.
테스트 단위 플래키율
= (윈도우 안에서 결과가 갈린 테스트 수) / (전체 테스트 수)
→ "우리 테스트 중 몇 %가 믿을 수 없는가" → 기술 부채의 크기
실행 단위 플래키 발생률
= (플래키로 분류된 실패 건수) / (전체 실행 횟수)
→ "한 번 돌릴 때 평균 몇 건의 가짜 실패를 보는가" → 사람이 겪는 고통의 크기
예) 전체 500개, 윈도우 30회, 결과가 갈린 테스트 15개, 그 15개가 30회 동안
만든 가짜 실패 90건
테스트 단위 = 15/500 = 3.0%
실행 단위 = 90/30 = 실행당 3건둘을 같이 봐야 하는 이유는 개선 효과가 다르게 나타나기 때문이다. 아주 자주 흔들리는 테스트 하나를 고치면 실행 단위는 크게 떨어지지만 테스트 단위는 거의 안 움직인다. 사람의 체감을 빨리 개선하려면 실행 단위 기준 상위 건부터 손대는 것이 맞고, 부채를 실제로 줄이려면 테스트 단위를 추세로 본다.
플래키 장부 — 격리 운영의 단일 출처
장부는 스프레드시트든 저장소 안의 파일이든 상관없지만, 열은 고정해야 한다. 열이 빠지면 그 열에 해당하는 운영이 무너진다.
플래키 장부 (필수 열)
테스트 ID | 최초 탐지일 | 최근 30회 실패율 | 상태 | 소유자 | 격리일 | 격리 만료일
| 추정 원인 범주 | 커버하는 시나리오 | 대체 수단
상태 값: 관찰중 / 격리 / 복귀심사 / 해결 / 삭제승인세 열이 특히 중요하고, 셋 다 격리의 부작용을 막기 위해 있다.
- 소유자 — 비어 있으면 격리를 허용하지 않는다. 주인 없는 격리가 쓰레기통의 시작이다.
- 격리 만료일 — 격리에는 기한이 있다. 기한이 지나면 자동으로 복귀심사나 삭제승인 중 하나로 넘어간다.
- 커버하는 시나리오와 대체 수단 — 이 테스트가 격리된 동안 무엇이 검증되지 않는지, 그 공백을 수동 확인이나 다른 테스트로 메우는지. 이 열이 격리의 실제 비용이다.
자동 격리 규칙
격리(quarantine)는 테스트를 지우지 않고 결과가 게이트를 막지 않게 하는 조치다. 테스트는 계속 돌지만 실패해도 빌드를 빨갛게 만들지 않고, 결과는 별도로 집계된다. "끄기"와 다른 점이 여기 있다 — 끄면 데이터가 사라지고, 격리하면 데이터는 계속 쌓인다. 복귀 판정이 가능한 이유도 데이터가 쌓이기 때문이다.
자동 격리 규칙은 임계와 윈도우로 쓴다.
자동 격리 규칙 (예시 — 조직 상황에 맞게 조정)
진입 조건 (하나만 충족해도 심사 대상)
- 최근 30회 실행 중 재실행 통과가 3회 이상
- 최근 30회 실행 중 실패율이 10% 이상이면서 같은 커밋에서 갈린 사례가 1회 이상
- 전용 반복 실행 10회에서 결과가 갈린다
자동 집행 조건
- 위 진입 조건 + 소유자가 지정됨 → 즉시 격리, 만료일 = 격리일 + 14일
- 소유자 미지정 → 격리하지 않고 '관찰중' 유지 + 팀 채널에 소유자 지정 요청
격리 중 동작
- 테스트는 계속 실행하되 게이트에서 제외
- 결과는 '격리 집계' 로 별도 기록 (통과율 지표에서 분리)
- 주간 리뷰 안건에 자동 포함
금지
- 전체의 2% 를 넘는 격리는 자동 집행하지 않고 리뷰로 올린다 (플래키 예산)마지막 줄이 플래키 예산 이다. 격리 가능한 총량에 상한을 두는 장치다. 상한이 없으면 격리는 가장 손쉬운 해결책이 되고, 손쉬운 해결책은 항상 선택된다. 상한에 닿으면 새 격리를 위해 기존 격리를 해결해야 하므로, 격리가 자동으로 유한 자원이 된다.
예산을 넘겼을 때의 조치도 미리 정해 둔다. 보통 "새 기능 작업을 멈추고 플래키 정리에 한 스프린트를 쓴다" 같은 형태가 되고, 이 조항은 사전 합의 없이는 집행되지 않는다. 예산 수치보다 합의 문서가 있다는 사실 이 더 중요하다.
격리가 쓰레기통이 되는 문제
격리 제도를 도입한 조직에서 1년 뒤 관찰되는 전형적 상태는 이렇다. 격리 목록에 40개가 있고, 절반은 누가 왜 넣었는지 모르고, 그중 몇 개는 사실 제품 결함을 숨기고 있다. 마지막 항목이 가장 위험하다 — 격리된 테스트가 진짜 결함을 가리면, 그 결함은 사용자가 발견한다.
이 결과를 막는 장치는 다섯 개이고, 전부 저렴하다.
- 소유자 필수 — 주인 없는 격리 금지. 규칙 한 줄로 집행된다.
- 만료일 자동 — 기한이 지나면 복귀심사 또는 삭제승인으로 강제 이동.
- 총량 상한(예산) — 넘으면 새 격리가 안 된다.
- 주간 리뷰 — 격리 목록 전체를 15분 안에 훑는다. 길어졌다면 목록이 너무 큰 것이다.
- 격리 중 실패 패턴 확인 — 격리된 테스트가 항상 실패로 바뀌었다면 그건 더 이상 플래키가 아니다. 제품 결함 또는 확정된 테스트 결함이므로 즉시 레슨 7의 트리아지로 보낸다.
다섯 번째가 자주 빠진다. 격리는 "결과를 안 본다"가 아니라 "게이트에서만 뺀다"는 뜻이고, 결과를 계속 보는 것이 격리의 전제다.
복귀 기준
고쳤다고 선언하는 기준이 없으면 격리는 단방향이 된다. 복귀 기준은 두 조건을 모두 요구한다.
복귀 조건
(1) 변경 근거 — 원인을 설명하는 수정 커밋이 있다.
"요즘 안 깨지더라" 는 근거가 아니다.
(2) 통계 근거 — 같은 커밋에서 20회 연속 통과했다.
(전용 반복 실행으로 확인. 횟수는 조직의 허용 위험에 따라 10~50회)
복귀 후 관찰
- 2주간 '관찰중' 상태로 두고 재발하면 즉시 재격리한다.
- 재격리가 2회 이상이면 '수정' 이 아니라 '설계 변경' 또는 '삭제' 를 검토한다.(1) 없이 (2)만으로 복귀시키는 것이 가장 흔한 실수다. 통계만 보면 운 좋은 20회일 수 있고, 원인이 그대로 있으면 재발한다. 반대로 (1)만으로 복귀시키면 "고친 줄 알았는데 아니었다"가 된다.
삭제도 정당한 결말 이라는 점을 규칙에 명시해 두는 것이 좋다. 재격리를 반복하는 테스트는 그 시나리오를 다른 층(단위·API·수동 확인)에서 검증하도록 옮기고 지우는 것이 합리적일 때가 많다. 삭제할 때는 장부의 "커버하는 시나리오" 열을 근거로 대체 수단을 남기고, 그 결정을 기록한다. 기록 없는 삭제는 커버리지가 조용히 사라지는 경로다.
실무에서 왜 필요한가
플래키의 비용은 실패 건수가 아니라 신뢰 손실 로 나타난다. 실행당 가짜 실패가 3건이면 사람들은 빨간 결과를 보고 먼저 재실행 버튼을 누르게 되고, 재실행이 습관이 되면 진짜 실패도 두 번 돌려 보고 넘어간다. 그 상태의 자동화는 돌고 있지만 아무것도 막지 않는다. 레슨 1의 성숙도 눈금에서 1단계와 2단계를 가르는 선이 정확히 여기다.
시간 비용도 계산 가능하다. 실행당 가짜 실패 3건, 하루 실행 8회, 건당 분류 5분이면 하루 2시간이다. 여기에 "실패를 보고 멈추는" 심리적 전환 비용이 더 붙는다. 플래키율을 절반으로 줄이는 작업은 보통 새 테스트 20개를 추가하는 작업보다 투자 수익이 크다.
격리 제도가 필요한 이유는 현실적이다. 플래키를 발견한 즉시 고칠 수 있는 조직은 없다. 고칠 때까지 그 테스트가 게이트를 막으면 사람들은 게이트를 무시하기 시작하고, 그게 가장 나쁜 결말이다. 격리는 신뢰를 유지하면서 부채를 명시적으로 쌓는 장치 이고, 명시적으로 쌓은 부채는 관리할 수 있다.