좋은 스펙 작성하기
보통 빈 페이지에서 스펙을 작성하는 경우는 거의 없습니다. /opsx:propose가 요구사항과 시나리오 초안을 작성하고, 그 다음 여러분이 이를 다듬는 과정이죠. 이 페이지는 그 마지막 단계 — '좋은' 스펙이 어떤 것인지, 그리고 AI가 그 방향으로 나아가도록 유도하는 방법에 대해 다룹니다.
변경 사항 검토하기와 짝을 이루는 문서입니다: 검토는 초안의 약점을 잡아내는 과정이고, 작성은 강력한 스펙이 어떤 요소로 구성되는지 아는 과정이죠.
스펙은 코드가 아니라 동작입니다
스펙은 시스템이 무엇을 하는지를, 코드를 모르는 사람도 확인할 수 있는 용어로 설명합니다 — 어떻게 구현되는지는 다루지 않죠. 스펙은 요구사항(동작에 대한 진술)과 시나리오(그 동작을 증명하는 구체적인 예시)로 구성됩니다.
markdown
### Requirement: Session Timeout
The system SHALL expire a session after 30 minutes of inactivity.
#### Scenario: Idle timeout
- GIVEN an authenticated session
- WHEN 30 minutes pass with no activity
- THEN the session is invalidated and the user must re-authenticate구현 방법(큐, 라이브러리, 테이블 스키마 등)은 design.md나 코드에 남겨두세요. 동작과 구현이 하나의 요구사항에 섞이면, 그 요구사항은 테스트할 수 없게 되고 코드가 변경되는 즉시 오래된 정보가 되어버립니다.
좋은 요구사항이란 무엇인가
좋은 요구사항은 하나의 동작을, 다른 사람이 테스트할 수 있을 만큼 명확하게 진술한 것입니다.
하나의 진술, 하나의
SHALL/MUST. 요구사항에 "그리고 또" 절이 세 개 이상 있으면, 실제로는 세 개의 요구사항인 경우입니다. 나누세요.관찰 가능해야 합니다. 코드를 모르는 사람도 해당 요구사항이 충족되는지 확인할 수 있어야 합니다. "시스템은 업로드 크기가 10MB를 초과할 때 오류 배너를 표시해야 한다"는 관찰 가능하지만, "시스템은 대용량 업로드를 우아하게 처리해야 한다"는 그렇지 않습니다.
적절한 강도. OpenSpec은 RFC 2119 키워드를 사용하며, 각 키워드는 다른 의미를 가집니다:
키워드 의미 MUST/SHALL필수 요구사항. 타협할 수 없습니다. SHOULD강력한 권장 사항으로, 정당한 예외가 있는 경우 적용하지 않을 수 있습니다. MAY진정으로 선택 사항입니다. 기본적으로
MUST/SHALL을 사용하세요. 정말로 "좋은 이유가 없다면 적용하지 않는다"는 의미일 때만SHOULD를 사용하세요.
요구사항의 테스트 기준: 코드를 한 번도 본 적 없는 테스터가 해당 요구사항을 통과했는지 확인할 수 있는가? 그렇지 않다면 더 명확하게 다듬어야 합니다.
좋은 시나리오가란 무엇인가
시나리오는 요구사항의 가치를 발휘하는 곳입니다. 각 시나리오는 자동화 테스트가 될 수 있는 구체적인 GIVEN / WHEN / THEN 구조로 작성됩니다.
- 자신의 요구사항을 검증해야 합니다. 요구사항을 다른 단어로 다시 진술하는 시나리오는 아무것도 테스트하지 않습니다. 구체적인 상황과 구체적인 결과를 가진 시나리오로 작성하세요.
- 중요한 사례를 다루세요, 행복한 경로만이 아닙니다. 유효한 로그인은 쉽죠. 빈 입력, 만료된 토큰, 두 번 클릭, 잘못되는 상황 — 바로 그곳에 버그가 숨어 있고, 시나리오가 가장 큰 가치를 발휘하는 곳입니다.
- 제목에 사례 이름을 적으세요. "시나리오: 만료된 토큰 거부"는 리뷰어가 한 눈에 어떤 내용이 다뤄지는지 알려주지만, "시나리오: 테스트 2"는 그렇지 않습니다.
유용한 습관: 승인하기 전에 내가 깨져 있는 것을 보면 가장 화가 날 만한 단 하나의 사례가 무엇인지 생각해 보세요 — 그리고 그 사례를 다루는 시나리오가 있는지 확인하세요.
적절한 델타 유형 선택하기
변경 사항은 세 가지 섹션 유형으로 스펙에 대한 편집 내용을 설명합니다. 적절한 유형을 사용하면 아카이브된 스펙의 정확성을 유지할 수 있습니다:
## ADDED Requirements— 이전에 존재하지 않았던 완전히 새로운 동작입니다.## MODIFIED Requirements— 기존에 존재했던 동작이 변경되는 경우입니다. 새 버전 전체를 포함하고, 변경된 내용에 대한 짧은 메모를 추가하면 리뷰어에게 도움이 됩니다.## REMOVED Requirements— 삭제되는 동작으로, 삭제 이유에 대한 설명을 포함하세요.
아카이브할 때 ADDED는 메인 스펙에 추가되고, MODIFIED는 이전 버전을 대체하고, REMOVED는 삭제됩니다. 실제 변경 사항을 ADDED로 표시하면 경쟁하는 두 개의 요구사항이 생기고, 새로운 동작을 MODIFIED로 설명하면 대체할 기존 요구사항이 없게 됩니다. 확실하지 않다면 현재 스펙을 열어 해당 요구사항이 이미 존재하는지 확인하세요.
변경 규모 적절히 조정하기
가장 흔한 작성 실수는 불완전하게 작성된 요구사항이 아니라, 세 가지 변경 사항을 하나로 묶으려는 변경 사항입니다.
좋은 변경 사항은 한 문장으로 설명할 수 있는 하나의 의도를 가집니다. "다크 모드 토글 추가하기", "로그인 엔드포인트 속도 제한 적용하기", "쿠키에서 세션 마이그레이션하기" 등이죠. 변경 사항을 설명할 때 "그리고 또" 라는 말이 많이 나온다면, 나눠야 한다는 신호입니다.
변경 사항이 너무 큰 신호:
- 제안의 범위가 관련 없는 기능의 목록처럼 읽힙니다.
- 검토하는 데 오후 전체가 걸려서 아무도 검토하지 않을 것입니다.
- 두 명이 동시에 작업하려면 충돌이 발생합니다.
- 작업의 절반은 독립적으로 출시할 수 있습니다.
작은 변경 사항은 검토하기 쉽고, 한 번의 집중 세션에서 구현하기 쉽고, 아카이브만 남은 6개월 후에 다시 봐도 이해하기 쉽습니다. 여러 변경 사항을 병렬로 실행할 수도 있습니다 — 변경 사항 편집 및 반복하기와 워크플로우를 참고하세요.
반대의 경우도 있습니다: 한 줄의 오타 수정에 세 개의 요구사항과 디자인 문서가 필요하지는 않습니다. 규모에 맞는 절차를 따르세요.
AI가 좋은 초안을 작성하도록 유도하는 방법
/opsx:propose가 초안을 작성하기 때문에, 반환되는 결과의 품질은 입력하는 내용의 품질과 직결됩니다. 직접 요구사항을 작성할 필요는 없습니다 — AI를 올바른 방향으로 유도하면 됩니다:
- 의도와 범위를 명확히 설명하세요. "OS 설정을 따라 첫 로드 시 다크 모드 토글을 추가하세요 — 기존 테마 API는 건드리지 마세요." 범위에서 제외하는 부분이 포함하는 부분만큼이나 중요합니다.
- 신경 쓰는 사례를 이름 지어주세요. "사용자가 직접 테마를 선택한 경우를 다루는 시나리오가 있는지 확인하세요." AI는 여러분이 지적한 부분을 다룹니다.
- 그 다음 편집하세요. 평범한 마크다운입니다. 모호한
SHALL을 명확히 다듬고, 아무것도 테스트하지 않는 시나리오를 삭제하고, AI가 놓친 사례를 추가하세요 — 혹은 AI에게 요청할 수도 있습니다: "타임아웃 요구사항이 모호하니 30분으로 명확히 고정해줘."
초안 작성, 다듬기, 반복하기. 이 과정을 몇 번 반복하면 신뢰할 수 있는 스펙이 만들어지고, 그것이 바로 이 과정의 목적입니다.
빠른 체크리스트
- [ ] 각 요구사항은
SHALL/MUST가 포함된 하나의 관찰 가능한 동작으로 작성되었습니다. - [ ] 요구사항에 구현 세부사항이 포함되지 않았습니다.
- [ ] 모든 요구사항에는 실제로 검증하는 시나리오가 최소 하나 이상 있습니다.
- [ ] 중요한 경계값과 오류 사례에 대한 시나리오가 있고, 행복한 경로만 다루지 않습니다.
- [ ] 델타가 현재 스펙에 대해 ADDED / MODIFIED / REMOVED를 올바르게 사용했습니다.
- [ ] 전체 변경 사항이 한 문장으로 설명할 수 있는 하나의 의도를 가집니다.
다음으로 확인할 내용
- 변경 사항 검토하기 — 놓친 약점을 잡아내는 2분 간단 검토 과정입니다.
- 개념 — 스펙, 변경 사항, 델타의 근본 모델에 대해 다룹니다.
- 예시 & 레시피 — 처음부터 끝까지의 실제 변경 사항 사례입니다.