본문 바로가기
TYLER SONGBlog
← Blog index
CS학습6 min read

요구사항 분석: 모호한 요구를 검증 가능한 명세로 바꾸는 과정

요구사항 분석(Requirements Analysis)은 이해관계자의 모호한 요구를 명확하고 일관되며 검증 가능한 명세로 바꾸는 활동이다. 기능·비기능 요구사항을 구분하고, 우선순위와 인수 기준(Acceptance Criteria)을 정하는 것이 핵심이다. 이 글에서는 원리와 함께 요구사항을 Python 코드로 구조화해 모호성과 누락을 점검하는 예제를 다룬

By 송민성

1. 개념

요구사항 분석(Requirements Analysis)은 이해관계자(Stakeholder)가 원하는 바를 수집하고, 이를 명확하고 일관되며 검증 가능한 명세(Specification)로 정리하는 소프트웨어 공학 활동이다. 결과물은 보통 요구사항 명세서(SRS, Software Requirements Specification), 사용자 스토리(User Story), 유스케이스(Use Case) 같은 문서 형태로 남는다.

요구사항은 크게 두 가지로 나뉜다.

  • 기능 요구사항(Functional Requirement): 시스템이 *무엇을 하는가*. 예: "사용자는 이메일과 비밀번호로 로그인할 수 있다."
  • 비기능 요구사항(Non-functional Requirement): 시스템이 *얼마나 잘, 어떤 제약 아래* 동작하는가. 예: "로그인 응답은 95퍼센타일 기준 300ms 이내여야 한다."

2. 왜 사용하는가

구현 단계에서 발견된 요구사항 오류는 설계 단계에서 발견된 것보다 수정 비용이 일반적으로 훨씬 크다. 요구사항이 모호하면 다음과 같은 문제가 생긴다.

  • 개발자, 기획자, QA가 같은 문장을 서로 다르게 해석한다.
  • 범위가 끝없이 늘어나는 범위 크리프(Scope Creep)가 발생한다.
  • 완료 기준이 없어 "끝났는지"를 판단할 수 없다.
  • 성능, 보안 같은 비기능 요구가 뒤늦게 드러나 구조를 다시 설계해야 한다.

요구사항 분석은 이런 해석 차이를 개발 전에 드러내어 비용을 줄이는 수단이다.

3. 동작 원리

요구사항 분석은 대체로 다음 순서로 반복(Iteration)된다.

  1. 도출(Elicitation): 인터뷰, 설문, 관찰, 기존 시스템 분석, 워크숍으로 요구를 수집한다.
  2. 분석(Analysis): 요구 간 충돌, 중복, 누락을 찾고 실현 가능성을 검토한다. 우선순위는 MoSCoW(Must, Should, Could, Won't) 같은 기법으로 정한다.
  3. 명세(Specification): 합의된 요구를 문서화한다. 각 요구에 고유 ID를 붙여 추적 가능하게 한다.
  4. 검증(Validation): 이해관계자와 함께 "올바른 것을 만들고 있는가"를 확인한다.
  5. 관리(Management): 변경 요청을 추적하고 요구사항과 설계·코드·테스트 사이의 추적성(Traceability)을 유지한다.

좋은 요구사항은 다음 성질을 가진다.

성질의미
명확성(Unambiguous)한 가지로만 해석된다
검증 가능성(Verifiable)테스트로 충족 여부를 판정할 수 있다
일관성(Consistent)다른 요구와 충돌하지 않는다
완전성(Complete)필요한 조건과 예외가 빠지지 않는다
추적 가능성(Traceable)출처와 구현·테스트를 연결할 수 있다

"빠르게 응답해야 한다"는 검증할 수 없지만, "동시 접속 500명 조건에서 95퍼센타일 응답 시간이 300ms 이하"는 검증할 수 있다.

4. 코드 예제

요구사항을 데이터로 구조화하면 모호한 표현과 누락을 자동으로 점검할 수 있다. 아래 Python 코드는 요구사항에 ID, 유형, 우선순위, 인수 기준을 담고, 모호한 표현과 검증 기준 누락을 찾아낸다.

python
from dataclasses import dataclass, field from enum import Enum class Kind(Enum): FUNCTIONAL = "기능" NON_FUNCTIONAL = "비기능" class Priority(Enum): MUST = "Must" SHOULD = "Should" COULD = "Could" WONT = "Won't" @dataclass class Requirement: id: str text: str kind: Kind priority: Priority acceptance_criteria: list[str] = field(default_factory=list) # 검증하기 어려운 모호한 표현 (예시 목록) VAGUE_WORDS = ["빠르게", "빨리", "적절히", "충분히", "쉽게", "가능한 한", "유연하게"] def lint(reqs: list[Requirement]) -> list[str]: problems = [] seen_ids = set() for r in reqs: if r.id in seen_ids: problems.append(f"[{r.id}] ID 중복") seen_ids.add(r.id) for word in VAGUE_WORDS: if word in r.text: problems.append(f"[{r.id}] 모호한 표현 '{word}' 포함") if r.priority is Priority.MUST and not r.acceptance_criteria: problems.append(f"[{r.id}] Must 요구사항에 인수 기준이 없음") return problems if __name__ == "__main__": reqs = [ Requirement( "FR-001", "사용자는 이메일과 비밀번호로 로그인할 수 있다.", Kind.FUNCTIONAL, Priority.MUST, [ "올바른 자격 증명이면 200 응답과 세션 토큰을 반환한다", "잘못된 비밀번호가 5회 연속이면 계정을 15분간 잠근다", ], ), Requirement( "NFR-001", "로그인은 빠르게 처리되어야 한다.", Kind.NON_FUNCTIONAL, Priority.MUST, ), Requirement( "NFR-002", "동시 접속 500명에서 로그인 95퍼센타일 응답 시간은 300ms 이하여야 한다.", Kind.NON_FUNCTIONAL, Priority.SHOULD, ["부하 테스트에서 p95 <= 300ms"], ), ] for p in lint(reqs): print(p)

실행하면 NFR-001에 대해 모호한 표현 '빠르게'와 인수 기준 누락이 보고된다. 단어 목록 기반 점검은 보조 수단일 뿐이고, 모호성 판단을 완전히 대체하지는 못한다.

인수 기준은 테스트로 옮기기 쉬운 형태로 쓰는 것이 좋다. 아래는 Given-When-Then 형식을 TypeScript 테스트로 옮긴 예이다.

typescript
import assert from "node:assert/strict"; type LoginResult = { ok: boolean; locked: boolean }; class AuthService { private failures = new Map<string, number>(); private readonly users = new Map([["a@example.com", "secret"]]); login(email: string, password: string): LoginResult { const count = this.failures.get(email) ?? 0; if (count >= 5) return { ok: false, locked: true }; if (this.users.get(email) === password) { this.failures.set(email, 0); return { ok: true, locked: false }; } this.failures.set(email, count + 1); return { ok: false, locked: count + 1 >= 5 }; } } // Given: 등록된 사용자가 있고 const auth = new AuthService(); // When: 잘못된 비밀번호로 5회 연속 로그인하면 for (let i = 0; i < 5; i++) auth.login("a@example.com", "wrong"); // Then: 올바른 비밀번호여도 계정이 잠겨 있다 const result = auth.login("a@example.com", "secret"); assert.equal(result.ok, false); assert.equal(result.locked, true); console.log("인수 기준 통과");

5. 시간 복잡도 또는 성능 특성

요구사항 분석은 알고리즘이 아니므로 시간복잡도 대신 비용 특성을 본다.

  • 요구사항 결함은 뒤 단계로 갈수록 수정 비용이 커지는 경향이 있다. 다만 증가 배율은 프로젝트마다 달라 일반화된 단일 수치로 말할 수 없다.
  • 요구사항 간 충돌 가능성은 요구 수가 늘수록 빠르게 증가한다. n개 요구의 쌍은 n(n-1)/2개이므로, 모든 쌍을 사람이 검토하면 O(n²)이다. ID와 분류, 의존 관계를 명시해 검토 범위를 줄이는 이유다.
  • 위 lint 함수는 요구사항 수 n, 모호어 목록 크기 m에 대해 O(n·m)(문자열 길이 제외)이다.

6. 실무 사용 사례

  • 애자일 팀: 사용자 스토리와 인수 기준을 백로그(Backlog)에 두고, 스프린트 계획 때 "완료의 정의(Definition of Done)"와 함께 검토한다.
  • 행위 주도 개발(BDD): Given-When-Then 시나리오를 자동화 테스트로 연결해 요구사항이 곧 테스트가 되게 한다.
  • API 설계: 비기능 요구(지연 시간, 가용성 목표 SLO, 처리량)를 먼저 정하고 캐시, 큐, 확장 전략을 결정한다.
  • 외주·계약 프로젝트: SRS를 기준으로 범위와 검수 조건을 합의한다.
  • 규제 산업: 요구사항과 테스트를 연결하는 추적성 매트릭스(Traceability Matrix)를 유지한다.

7. 주의할 점

  • 해결책을 요구로 착각: "Redis를 써야 한다"는 요구가 아니라 설계 결정이다. 뒤에 있는 문제(예: "조회 응답 50ms 이하")를 찾아야 한다.
  • 비기능 요구 누락: 성능, 보안, 접근성, 운영성은 묻지 않으면 나오지 않는다. 체크리스트로 의도적으로 질문한다.
  • 이해관계자 편중: 말하는 사람의 요구만 반영하면 운영팀, 보안팀, 최종 사용자의 요구가 빠진다.
  • 한 번에 확정하려는 시도: 요구는 변한다. 변경을 막기보다 변경 요청을 추적하고 영향 범위를 평가하는 절차를 둔다.
  • 검증 불가능한 문장: "사용자 친화적인", "확장 가능한" 같은 표현은 측정 가능한 기준으로 바꾼다.
  • 과도한 문서화: 팀과 프로젝트 규모에 맞는 수준으로 쓴다. 문서의 양이 아니라 공통 이해가 목표다.

8. 핵심 정리

  • 요구사항 분석은 도출 → 분석 → 명세 → 검증 → 관리를 반복하는 활동이다.
  • 요구사항은 기능과 비기능으로 나누며, 비기능 요구는 의도적으로 찾아야 한다.
  • 좋은 요구사항은 명확하고, 검증 가능하고, 일관되고, 완전하며, 추적 가능하다.
  • 인수 기준을 Given-When-Then 등 테스트 가능한 형태로 쓰면 요구사항이 곧 검증 수단이 된다.
  • 해결책이 아니라 문제를 기술하고, 우선순위(예: MoSCoW)와 변경 관리 절차를 함께 둔다.