Rain Lag

원카드 버그 극장: 코드를 건드리기 전에 실패 시나리오부터 연기하라

모든 버그를 작고 공유 가능한 ‘원카드’ 스크립트로 만들어, 연극처럼 연기하듯 재현하고 테스트 가능한 형태로 정리해 내일의 회귀 테스트 자산으로 쌓는 방법을 소개합니다.

원카드 버그 극장: 코드를 건드리기 전에 실패 시나리오부터 연기하라

대부분의 팀은 버그를 짜증 나는 방해 요소로만 취급합니다. 하지만 제대로만 잡아두면, 버그는 믿을 수 없을 만큼 정보 밀도가 높은 자산입니다.

문제는, 우리가 보통 그걸 제대로 안 한다는 거죠.

애매한 티켓을 만들고, 바로 코드로 뛰어듭니다. 버그 리포트는 “봐도 알겠지”라고 가정합니다. 그러고는 5분 만에 분명히 정리할 수 있었을 내용을 재현하느라 몇 시간을 허비합니다.

여기서 등장하는 것이 바로 원카드 버그 극장(One-Card Bug Theater) 입니다.

디버거부터 열지 말고, 먼저 버그를 작은 연극처럼 연기합니다. 사람이 읽을 수 있는 스크립트로 다음을 정리하는 겁니다.

  • 지금 무엇을 검증하려는지에 대한 한 문장 목표
  • 시스템의 초기 상태
  • 사용자가 수행한 정확한 행동 순서
  • 기대한 결과 vs 실제 결과
  • 버그가 고쳐졌을 때의 회복 경로(Recovery Path)

그리고 이 모든 내용을 카드 한 장에 들어갈 정도로만 작게 유지합니다.

이걸 실제로 어떻게 하는지 단계별로 살펴보겠습니다.


1. 한 문장 목표부터 시작하라

어떤 단계든 적기 전에, 이 시나리오의 목적이 단번에 이해될 수 있도록 한 문장으로 적습니다.

Goal(목표): "저장된 배송지를 수정해도 사용자의 기본 결제 수단이 초기화되지 않는지 확인한다."

좋은 한 문장 목표는 다음을 만족합니다.

  • 관심 있는 구체적인 동작을 명시한다
  • 어떻게가 아니라 무엇을 검증하는지를 말한다
  • 통과 여부를 "예/아니오"로 대답할 수 있을 만큼 좁고 명확하다

나쁜 목표 예시:

  • "체크아웃 버그 수정" — 너무 모호함
  • "주소 변경 시 결제 수단 깨짐" — 여전히 모호함
  • "사용자 보고 #1243 조사" — 하는 일(work)을 말할 뿐, 동작(behavior)을 설명하지 않음

좋은 목표 예시:

  • "배송지를 변경해도 이전에 선택한 기본 결제 수단이 유지된다."
  • "비회원 사용자는 인증 없이 주문 내역 페이지에 접근할 수 없다."

이 한 문장 목표가 바로 당신의 "카드" 상단에 들어갈 헤드라인입니다. 나머지 모든 내용은 이 단 하나의 동작을 뒷받침해야 합니다.


2. 연기하라: 버그를 작은 스크립트로 만들기

이제 버그를 역할과 단계가 분명한 연극 대본으로 바꿉니다. 코드 이야기는 잠시 잊으세요. 사람이 무엇을 보고 무엇을 하는지 기준으로 설명합니다.

구조는 다음과 같이 단순하게 잡습니다.

  1. 초기 상태(Initial State)
  2. 단계(사용자 행동 Steps)
  3. 기대 결과(Expected Result)
  4. 실제 결과(Actual Result)

예시 스크립트

Goal(목표): "배송지를 변경해도 이전에 선택한 기본 결제 수단이 유지된다."

Initial State(초기 상태)

  • 사용자 계정: alice@example.com 존재
  • 저장된 배송지: "Home", "Office" 두 개
  • 저장된 결제 수단: Visa (기본값), Mastercard
  • 사용자는 로그인 상태이며, 장바구니에 상품 1개를 담은 채 체크아웃(Checkout) 페이지에 진입해 있음

Steps (User Actions, 사용자 행동)

  1. 체크아웃 페이지에서 Shipping Address(배송지) 섹션의 Change(변경) 버튼을 클릭한다.
  2. 배송지로 "Office"를 선택한다.
  3. Save(저장) 를 클릭한다.
  4. Payment Method(결제 수단) 섹션에서는 아무것도 변경하지 않는다.
  5. Place Order(주문하기) 를 클릭한다.

Expected Result(기대 결과)

  • 주문은 Visa(기본값) 으로 결제된다.
  • 주문 확인 페이지에 Payment method: Visa **** 1234 와 같이 표시된다.

Actual Result(실제 결과)

  • 주문이 Mastercard 로 결제된다.
  • 주문 확인 페이지에 Payment method: Mastercard **** 5678 로 표시된다.

이건 단순히 미래의 나에게 남기는 메모가 아니라, 다른 사람 앞에서도 그대로 연기할 수 있는 스크립트입니다. 두 사람이 이 스크립트를 각각 따라 해도, 동일한 실패 현상을 봐야 합니다.


3. 각 버그를 "원카드 스토리"로 취급하라

"원카드" 제약의 핵심은 간단합니다: 카드 한 장, 한 가지 동작, 한 개의 버그 스크립트.

왜 제약을 둘까요?

  • 집중을 강제합니다: 한 번에 한 가지만 검증하게 됩니다.
  • 공유 가능성이 높아집니다: 카드(또는 그 스크린샷)만 건네줘도 동료가 이해할 수 있습니다.
  • 스코프 크리프(scope creep) 를 막습니다: 다른 동작을 발견했다면, 그건 새 카드입니다.

실제로는 인덱스 카드, 포스트잇, 이슈 트래커의 작은 디지털 카드 등 뭐든 써도 됩니다. 중요한 건 도구가 아니라 제약입니다.

전형적인 원카드 구조는 이렇습니다.

  • Title(제목): "주소를 변경하면 결제 수단이 바뀌는 문제"
  • Goal(목표): 한 문장
  • Initial State(초기 상태): 3–7개의 불릿 포인트
  • Steps(단계): 3–10개의 번호 매긴 단계
  • Expected vs. Actual(기대 vs 실제): 총 2–4개의 불릿
  • Recovery Path(회복 경로): 1–3개의 불릿 (뒤에서 자세히 설명)

이 구조가 카드 한 장이나 한 화면에 깔끔하게 안 들어간다면, 보통은 다음 중 하나입니다.

  • 여러 가지 동작을 한 카드에 섞어 놓았거나
  • 분기가 지나치게 많거나
  • 테스트를 확신하기에는 설명이 충분히 명확하지 않거나

이런 경우에는 언제나 더 작고 더 날카로운 시나리오로 쪼개는 쪽이 낫습니다.


4. 재현 가능성을 최우선 목표로 삼아라

시나리오는 "이슈 등록"으로 끝나지 않습니다. 다음 조건을 만족할 때 비로소 끝입니다.

어떤 팀원이든 이 단계를 따라 하면, 동일한 실패를 안정적으로 재현할 수 있어야 한다.

팀 동료와 함께 스크립트를 테스트해 보세요.

  • 그들에게 카드와 테스트 환경을 건네줍니다.
  • 질문 없이 그대로 따라 해 달라고 합니다.
  • 재현에 실패한다면, 그 시나리오는 아직 준비가 안 된 겁니다.

스크립트의 재현성이 부족하다는 흔한 신호들:

  • 숨겨진 전제가 있습니다 (예: 특정 브라우저 확장, Feature Flag, 시간대, 이미 존재한다고 가정하는 특정 데이터 등).
  • 중요한 준비 단계가 빠져 있습니다 (예: "사용자는 과거 주문이 3건 있다"고 해놓고 그 주문을 어떻게 생성하는지는 적지 않음).
  • 표현이 모호합니다 ("대충 클릭한다", "일반적인 체크아웃을 진행한다" 등).

재현 가능성은 이진값처럼 다루세요.

  • ✅ "팀 누구나 이걸 돌리면, 원하는 시점에 이 버그를 터뜨릴 수 있다."
  • ❌ "가끔 나타난다" 또는 "아까는 분명 됐는데 지금은 안 된다" 수준

만약 버그가 간헐적으로만 나타난다면, 그 순간 당신의 원카드 목표는 "이 실패를 재현 가능하게 만든다" 가 됩니다. 아직 코드를 디버깅하는 게 아니라, 시나리오를 디버깅하는 단계입니다.


5. 흐릿한 시나리오를 다듬는 "인지 디버깅" 기법

"앱이 느려요", "가끔 로그아웃돼요"처럼 애매한 버그 리포트를 받았다면, 그걸 선명하게 만드는 과정을 인지 디버깅(cognitive debugging) 으로 생각하세요.

코드를 디버깅하기 전에, 먼저 내가 이해하고 있는 문제 자체를 디버깅하는 겁니다.

여기에는 세 가지 유용한 기법이 있습니다.

5.1 문제를 재정의(Reframe)하라

스스로에게 질문합니다: "정확히 뭐가 놀랍거나, 뭐가 잘못된 거지?"

다음과 같은 표현 대신:

  • "체크아웃이 망가졌어요."

다음처럼 바꿔 봅니다.

  • "배송지를 수정한 뒤, 사용자가 건드리지 않았는데 결제 수단이 바뀐다."

이렇게 재정의하면, 감정 섞인 서술에서 관찰 가능한 동작으로 초점을 옮기게 됩니다.

5.2 제약을 추가하라

시나리오를 더 좁고 구체적으로 만듭니다.

  • 브라우저 한 종류, 한 환경, 한 사용자 유형만 택합니다.
  • 데이터를 고정합니다: 특정 사용자, 특정 상품, 특정 설정.

"이 버그는 alice@example.com 계정으로 로그인했을 때, Chrome 120, 스테이징 환경, 장바구니에 상품 1개만 있을 때 발생한다."

이런 제약은 디버깅 도구입니다. 가능한 원인의 탐색 공간을 확 줄여 줍니다.

5.3 생각을 외부로 끌어내라(Externalize)

머릿속에만 시나리오를 두지 말고, 적고, 그려 보고, 말로 풀어보세요.

  • 화면 전환 순서를 그려 봅니다.
  • 전제를 나열합니다: "폰은 온라인 상태", "Feature Flag X는 ON" 등.
  • 스크립트를 동료에게 말해 주고, 그들이 허점을 짚어보게 합니다.

이렇게 머릿속 모호한 모델을 밖으로 꺼내 놓으면, 비로소 그것을 검증하고 수정할 수 있게 됩니다.


6. 엣지 케이스를 재사용 가능한 스크립트로 남겨라

어떤 버그는 영구 캐릭터로 극단에 남겨 둘 가치가 있습니다.

보통 이런 경우입니다.

  • 악명 높은 엣지 케이스
  • 비즈니스에 치명적인 회귀(regression)
  • 기능 간 미묘한 상호작용이 얽힌 문제

이런 버그들은 인근 코드를 건드릴 때마다 다시 재생할 수 있는 재사용 스크립트로 만들어 두세요.

예시:

  • "만료된 카드로 체크아웃 시도 후, 흐름 중간에 카드 정보를 갱신하는 경우"
  • "사용자가 초안을 편집하는 도중 세션이 만료되는 경우"
  • "파일 업로드 중 사용자의 네트워크 연결이 끊기는 경우"

각 버그에 대해 동일하게 원카드 포맷을 유지하고, 팀이 찾기 쉬운 위치에 보관합니다.

  • 공유 테스트 플레이북
  • 회귀 테스트 모음 문서
  • 이슈 트래커 안의 "Bug Scripts" 카드 모음 폴더

새로운 변경사항이 머지될 때마다 이 라이브러리를 훑습니다.

"이번에 체크아웃 + 세션 쪽을 건드렸네. 관련 버그 스크립트 전부 다시 돌려보자."

이렇게 하면 과거의 고통미래의 방패로 바꾸게 됩니다.


7. 항상 회복 경로(Recovery Path)를 포함하라

모든 원카드 스크립트는 끝에 반드시 회복 경로(Recovery Path) 를 포함해야 합니다.

"이 버그가 고쳐진 뒤, 시스템은 어떻게 동작해야 하는가?"

이건 단순히 기대 vs 실제의 비교를 넘어서, 앞으로 어떤 상태가 ‘통과(Pass)’인지를 명확히 정의하는 작업입니다.

앞선 예시를 이어가 보겠습니다.

Recovery Path (버그 수정 후 기대 동작)

  • 배송지를 변경한 뒤에도, 사용자가 선택한 결제 수단은 바뀌지 않고 유지된다.
  • 사용자가 명시적으로 결제 수단을 변경하면, 그 새 선택이 저장되고 주문에 사용된다.
  • 이 카드 내용을 기반으로 한 회귀 테스트(자동화 또는 수동 스크립트)를 추가한다.

회복 경로를 정의하면 생기는 이점:

  • 버그 시나리오가 그대로 즉시 활용 가능한 회귀 테스트가 된다.
  • QA와 개발자가 공유하는 "고쳐졌다"의 기준이 뚜렷해진다.
  • 이 스크립트를 나중에 자동화 테스트 케이스로 옮겨 담기가 훨씬 쉬워진다.

다르게 말하면, 오늘의 버그 극장이 내일의 테스트 스위트가 된다는 뜻입니다.


모두 합쳐서 흐름 만들기

원카드 버그 극장을 습관처럼 쓰기 시작하면, 워크플로우는 이렇게 바뀝니다.

  1. 버그가 보고된다.
  2. 코드를 바로 열고 싶은 유혹을 참는다.
  3. 한 문장 목표를 정의한다.
  4. 사람이 읽기 쉬운 작은 스크립트를 작성한다: 초기 상태, 단계, 기대 vs 실제.
  5. 인지 디버깅을 활용해, 누구나 재현할 수 있을 때까지 스크립트를 다듬는다.
  6. 이를 작고, 집중된, 공유 가능한 원카드 스토리로 남긴다.
  7. 회복 경로를 정의해, 이 카드가 앞으로의 회귀 테스트가 되도록 만든다.

이 방식의 보상은 분명합니다.

  • 애매한 리포트 때문에 허비하는 시간이 줄어든다.
  • 디버깅 세션이 더 빠르고 더 집중된다.
  • 재사용 가능한 버그 스크립트 라이브러리가 쌓인다.
  • "이상한 실패"에서 "신뢰할 수 있는 테스트 케이스"로 가는 길이 훨씬 매끄러워진다.

버그는 앞으로도 계속 발생할 겁니다. 하지만 각 버그를 작고 잘 연기된 한 편의 연극으로 바꾸기 시작하면, 매번의 실패가 팀이 함께 쓸 수 있는 재사용 자산으로 변합니다.

다음에 누군가 "버그가 있어요"라고 말하더라도, 바로 IDE부터 열지 마세요.

카드 한 장을 꺼내 들고,

무대를 여는 것부터 시작하세요.

원카드 버그 극장: 코드를 건드리기 전에 실패 시나리오부터 연기하라 | Rain Lag