사용자 스토리 (마이클 콘)
User Stories Applied 핵심 + 실무 시나리오 정리
- 사용자 스토리 (마이클 콘)
사용자 스토리 (마이클 콘)
대상 도서: User Stories Applied (Mike Cohn)
목표: 요구사항을 "한 번에 완성된 명세"로 다루지 않고, 작은 가치 단위 + 대화 + 검증으로 운영하기.
1) 사용자 스토리의 본질
사용자 스토리는 PRD/설계서의 축약본이 아니다.
- 스토리 = 대화를 시작하기 위한 약속
- 상세는 대화로 확정하고, 완료는 검증 기준으로 판단
- 핵심 프레임: 3C (Card / Conversation / Confirmation)
3C를 실무에 적용하는 법
- Card: 1~2문장으로 의도만 담는다.
- Conversation: 기획/개발/QA가 예외/경계/범위제외를 맞춘다.
- Confirmation: AC(수용 기준)와 테스트로 Done을 판단한다.
실제 시나리오
문제: "주문 검색 고도화"가 너무 큰 요구로 들어옴.
- Card:
- As a 상담사, I want 주문을 고객 전화번호로 검색, so that 고객 문의를 빠르게 처리할 수 있다.
- Conversation에서 나온 쟁점:
- 부분일치 허용 여부
- 기간 기본값
- 개인정보 마스킹 기준
- Confirmation:
- 3자리 미만 입력 시 검색 불가
- 최근 90일 데이터 기본 조회
- 응답 목록의 전화번호는 가운데 4자리 마스킹
2) 스토리 템플릿
기본 형태:
As a [사용자 유형], I want [원하는 것], so that [얻는 가치].
좋은 문장과 나쁜 문장
좋은 예:
- As a 구매자, I want 주문 내역을 기간별로 조회, so that 월별 지출을 확인할 수 있다.
나쁜 예:
- 주문 API에서 인덱스를 추가한다. (사용자/가치 없음)
- Redis 캐시를 붙인다. (해결수단만 있고 문제정의 없음)
실무 팁
so that가 비어 있으면 거의 항상 품질이 낮다.- 기술 태스크는 스토리의 하위 Task로 내린다.
- 스토리에는 "왜"를, 태스크에는 "어떻게"를 적는다.
3) 좋은 스토리 기준 (INVEST)
- Independent: 독립성
- Negotiable: 협상 가능성
- Valuable: 가치
- Estimable: 추정 가능성
- Small: 작은 크기
- Testable: 검증 가능성
INVEST 점검 예시 (결제 실패 재시도)
스토리:
As a 구매자, I want 결제 실패 후 즉시 재시도, so that 주문을 놓치지 않는다.
점검:
- Independent: 주문조회 개선 스토리와 분리됨 (O)
- Negotiable: 재시도 횟수/쿨타임 조정 가능 (O)
- Valuable: 주문 전환율과 직결 (O)
- Estimable: 대략 3~5pt 추정 가능 (O)
- Small: 재시도 버튼 + API 1개 범위로 제한 (O)
- Testable: 실패 코드/성공 전환 시나리오 테스트 가능 (O)
4) 수용 기준(AC) 상세 작성법
스토리는 짧게, AC는 구체적으로.
AC 작성 원칙
- 관찰 가능해야 함
- 모호한 단어 금지("빠르게", "적절히")
- 정상/예외/경계값 포함
- 가능한 Given/When/Then 형식
실제 시나리오: 주문 목록 기간 조회
스토리:
As a 구매자, I want 주문을 기간별로 조회, so that 지출 추이를 파악할 수 있다.
AC:
- Given 로그인 사용자일 때
- When 기간을 2026-03-01~2026-03-31로 설정하면
- Then 해당 기간 주문만 최신순으로 반환된다.
- And 응답 시간 p95는 1.0초 이하이다.
- And 주문이 0건이면 빈 배열과 "주문 없음" 메시지를 반환한다.
경계값 AC:
- 시작일 > 종료일이면 400 에러
- 최대 조회 기간은 365일
5) 스토리 분할 전략 (큰 요구를 작게)
큰 스토리를 한 번에 구현하면 예측도 품질도 무너진다.
대표 분할 방식
- 워크플로우 단계 분리: 조회 → 생성 → 수정 → 취소
- 규칙 분리: 기본 규칙 → 예외 규칙
- 데이터 분리: 핵심 필드 → 부가 필드
- 접점 분리: API → UI → 운영도구
- 난이도 분리: happy path → edge cases
실제 시나리오: "환불 자동화"
원본 에픽:
- "환불 자동화 구축"
분할 후 스토리:
1) 상담사가 환불 요청을 생성한다.
2) 결제상태가 PAID일 때만 승인 가능하다.
3) 승인 시 PG 환불 API 호출 이력이 저장된다.
4) 실패 시 재시도 큐에 적재된다.
5) 관리자 화면에서 환불 상태를 조회한다.
이렇게 쪼개면 각 스토리가 사용자 가치와 테스트 경계를 가진다.
6) Theme / Epic / Story 운영
- Theme: 전략적 방향
- Epic: 큰 기능 그룹
- Story: 스프린트 단위 구현 항목
실제 시나리오
- Theme: 고객센터 처리속도 개선
- Epic: 상담사 주문조회 고도화
- Stories:
- 전화번호 검색
- 기간 필터
- 상태 필터
- 결과 CSV 다운로드
운영 팁:
- 계획 단계에선 Epic 중심, 실행 단계에선 Story 중심으로 전환
- 스프린트 중 "생각보다 큼"이 확인되면 즉시 재분할
7) 추정(Estimation)과 불확실성 관리
핵심은 "정답 시간"이 아니라 "상대 크기"다.
실무 방식
- 스토리 포인트 기반 상대 추정
- 기준 스토리(앵커) 1~2개 유지
- 불확실성 큰 건 스파이크(탐색) 먼저 수행
실제 시나리오
문제: 신규 정산 배치가 데이터량에 따라 성능 위험 큼.
대응:
- 스토리 직접 개발 전 스파이크 1pt 배정
- 샘플 데이터 100만 건으로 실행시간 측정
- 결과 기반으로 본 스토리 재추정(5pt → 8pt)
효과:
- 중간에 "예상 밖 지연"으로 스프린트 깨지는 확률 감소
8) 우선순위: 가치 + 위험 + 학습
우선순위는 "중요해 보임"이 아니라, 아래 4축으로 본다.
- 비즈니스 가치
- 리스크 감소
- 학습 가치(빠른 피드백)
- 구현 비용
실제 시나리오
후보 3개:
- A: 신규 대시보드 UI 개선 (가치 중, 위험 낮음)
- B: 결제 중복요청 멱등 처리 (가치 높음, 위험 높음)
- C: 관리자 필터 추가 (가치 중, 비용 낮음)
우선순위: 1) B (장애/금전 리스크 감소) 2) C (빠른 가치 제공) 3) A
9) 안 좋은 스토리 신호와 수정법
신호
- 사용자/가치가 없음
- AC가 없음
- 한 스프린트 내 종료 불가
- 의존성이 과도함
- 팀원 해석이 다름
수정 예시
나쁜 스토리:
- "정산 모듈 리팩토링"
개선:
- As a 운영자, I want 정산 실패 건을 즉시 재처리, so that 수동 정산 시간을 줄인다.
- AC:
- 실패 건 목록 조회 가능
- 단건 재처리 가능
- 재처리 결과 이력 저장
10) 실무 템플릿 (복붙용)
스토리 카드
[Story]
As a [role]
I want [goal]
so that [value]
[Acceptance Criteria]
1) Given ... When ... Then ...
2) Given ... When ... Then ...
3) 예외/경계 조건
[Notes]
- 범위 제외(Out of Scope):
- 의존성:
- 리스크:
- 측정지표(KPI):
스프린트 진입 체크리스트
- INVEST 충족
- AC 3개 이상
- 범위 제외 명시
- 테스트 가능
- QA/개발/기획 공통 이해
PR 본문 연결 템플릿
[Story]
링크: ...
[AC Mapping]
- AC1: 어떤 코드/테스트로 충족했는지
- AC2: ...
- AC3: ...
[Validation]
- 통합테스트:
- 수동검증:
- 모니터링 포인트:
11) 백엔드 팀 적용 시나리오 (Kotlin/Spring)
시나리오 A: 주문 상태 필터 API
스토리:
As a 상담사, I want 주문을 상태별로 필터, so that 고객 문의를 빠르게 처리한다.
AC:
- 상태 파라미터가 없으면 전체 조회
- 상태 파라미터가 있으면 해당 상태만 반환
- 잘못된 상태값이면 400 에러
Task 예시:
- Controller 파라미터 검증
- Service 필터 로직
- Repository query 추가
- 테스트(정상/예외)
시나리오 B: 멱등 키 기반 중복 결제 방지
스토리:
As a 구매자, I want 결제가 한 번만 처리, so that 중복 결제를 피한다.
AC:
- 동일 idempotency key 재요청 시 기존 결과 반환
- key 만료시간 정책 적용
- 충돌/경합 상황에서 이중 처리 없음
검증:
- 동시성 테스트
- DB unique 제약/락 확인
- 운영 로그에서 중복 결제 0건 확인
시나리오 C: 배치 실패 재처리
스토리:
As a 운영자, I want 실패 배치를 재실행, so that 정산 지연을 줄인다.
AC:
- 실패 목록 조회 가능
- 재실행 버튼/API 제공
- 성공/실패 이력 보관
추가 포인트:
- 재처리 idempotent 설계
- 재시도 횟수/백오프 정책 명시
12) 도입 로드맵 (2주)
1주차
- 스토리 템플릿 팀 공통화
- AC 없는 이슈 스프린트 진입 금지
- PR에 AC 매핑 필수 적용
2주차
- 에픽 분할 리뷰 미팅 15분 고정
- 스프린트 회고에서 "스토리 품질" 항목 추가
- INVEST 미충족 사례 수집 후 개선
측정 지표:
- 스프린트 carry-over 감소율
- 리뷰 재작업 횟수 감소
- AC 누락 이슈 비율
요약
마이클 콘의 사용자 스토리 핵심은 "형식"이 아니라 "운영"이다.
- 스토리는 짧게(Card)
- 대화는 충분히(Conversation)
- 검증은 구체적으로(Confirmation)
- 구현 단위는 작고 독립적으로
이걸 지키면, 스프린트 예측 가능성과 코드 리뷰 품질이 같이 오른다.