> [!abstract] Introduction
> 요구사항*Requirement*은 원하는 행위에 대한 표현이다. 너무 당연해서 뭐라 할 말도 없긴 한데, 소프트웨어 공학에서는 전혀 다른 이야기가 펼쳐진다. 소프트웨어 공학에서 말하는 요구사항에는 개발자와 이용자의 관계, 그리고 체계적인 정리의 중요성이 담겨 있다.
# 요구사항이란?
> [!info] Definition
> Statement which translates or expresses a need and its associated constraints and condition (ISO/IEC/IEEE 29148:2018)
소프트웨어 공학에서 요구사항은 니즈와 그것에 대한 조건 및 제약사항을 표현한 문장으로, 시스템이 사용자에게 무엇을 제공해야 하는지를 정의한다. 사실 요구사항이 확립되지 않으면 무엇을 개발해야 할지 알 수 없기 때문에 요구사항을 확립하는 단계는 반드시 필요하다. 요구사항은 단순히 "이런 기능이 있으면 좋겠다"는 위시리스트가 아니다. 요구사항은 계약서와도 같은 역할을 하며, 개발팀과 이해관계자 사이의 합의를 문서화한 것이다. 잘 작성된 요구사항은 프로젝트의 범위_Scope_를 명확히 하고, 성공 기준을 정의하며, 향후 발생할 수 있는 분쟁을 예방하는 역할을 한다.
## 좋은 요구사항의 특징
요구사항이 제대로 기능하려면 몇 가지 특성을 갖춰야 한다:
- 명확성*Unambiguous*: 요구사항은 단 하나의 해석만 가능해야 한다. "빠른 응답 시간"이 아니라 "95%의 요청이 2초 이내에 응답"처럼 구체적이어야 한다.
- 완전성*Complete*: 시스템이 무엇을 해야 하는지 빠짐없이 기술되어야 한다.
- 일관성*Consistent*: 다른 요구사항과 모순되어서는 안 된다.
- 검증가능성*Verifiable*: 요구사항이 충족되었는지 테스트할 수 있어야 한다.
- 추적가능성*Traceable*: 요구사항의 출처와 그것이 구현된 위치를 추적할 수 있어야 한다.
## 제약 조건
이때 중요한 것 중 하나는 제약 조건*Constraints and Conditions*을 확립하는 것이다. 사용자의 요구사항은 대체로 "난 이것을(를) 하고 싶다"라는 형태로 전달되는데, 그 중에서 반드시 지켜야 하는 것들, 예를 들어 어떤 특정 규정이나 법을 위반하지 않도록 해야 할 때도 있고 특정 기술을 써야 할 때도 있다. 이러한 제약 조건은 요구사항을 만족하는 제품의 개발 이전에 고려되어야 한다.
제약 조건은 크게 세 가지로 나눌 수 있다. 특정 플랫폼, 프로그래밍 언어, 데이터베이스 등을 사용해야 하는 경우 이를 기술적 제약*Technical Constraints*이라 부른다. 예를 들어 반드시 iOS와 Android를 모두 지원해야 한다거나 기존 시스템과의 호환과 같은 것들이다. 예산, 일정, 인력 등의 제한은 비즈니스 제약*Business Constraints*에 속한다. "3개월 내에 출시해야 함" 또는 "개발 예산이 5천만원을 초과할 수 없음"과 같은 현실적인 제약이다. GDPR*General Data Protection Regulation, 일반정보보호 규정*, 개인정보보호법, 의료기기 규제 등 법적으로 반드시 준수해야 하는 요구사항들은 규제적 제약*Regulatory Constraints*에 속한다.
그러나 그 외의 모든 것은 요구사항을 정하고 나서 결정된다. 소프트웨어를 설계하는 과정이나 사용하는 기술, 구체적인 형태 등은 요구사항을 만족하기만 한다면 무엇이든 고려할 수 있어야 하기 때문에, 요구사항 단계에서는 되도록이면 구현 방법에 제한을 두지 않기 위하여 어떻게 구현해야 할지를 고려하지 않는다. 이런 원칙을 "What, not How"라고 부른다. 요구사항은 "무엇을*What*" 해야 하는지를 정의하지, "어떻게*How*" 구현할 것인지는 정의하지 않는다. 예를 들어 "사용자는 로그인할 수 있어야 한다"는 좋은 요구사항이지만, "사용자는 JWT 토큰을 사용하여 OAuth 2.0으로 로그인해야 한다"는 구현 세부사항을 너무 많이 담고 있어 좋지 않은 요구사항이다.
# 개발자 vs 고객
요구사항은 고객이 개발자에게 주는 것이다. 개발자는 고객의 요구사항을 정리하고 그에 맞게 개발을 시작한다. 이쯤에서 개발자와 고객 사이의 관계를 생각해보자. 이들의 관계는 농담으로도 좋다 말하기 어려운데, 일반적으로 고객들은 개발자의 업무를 잘 모르기 때문에 고객의 입장에서 개발자를 바라보면 개발자는 실무 현장을 제대로 이해하지 못하고 무슨 말을 해도 다 안된다고 반대하고 예산에 맞추지도 못하고 요구사항을 제대로 반영하지도 못하는 집단이 된다. 반대로 개발자 입장에서 고객을 바라보면, 고객들은 자신이 무엇을 원하는지 알지도 못하면서 꼭 필요한 것도 아닌 것을 요구하고 자신들이 써야 하는 시스템에 책임을 지지도 않으면서 자기들에게 일을 다 떠넘기는 존재들이다.
## 의사소통의 간극
이러한 갈등의 근본 원인은 지식의 비대칭성*Knowledge Asymmetry*에 있다. 고객은 도메인 전문가이지만 기술을 모르고, 개발자는 기술 전문가이지만 해당 도메인을 모른다. 이 간극을 메우는 것이 요구사항 개발 과정의 핵심이다. 예를 들어, 병원 시스템을 개발할 때 의사는 "환자 차트를 빠르게 조회해야 한다"고 말한다. 하지만 의사가 생각하는 "빠르게"는 진료실에서 환자를 기다리게 하지 않는 수준(1-2초)을 의미할 수 있지만, 개발자는 이를 "빠르게"라는 모호한 표현으로만 받아들여 일반적인 웹 응답 시간(5-10초)으로 구현할 수 있다. 이런 불일치가 나중에 큰 문제로 발전한다.
## 요구사항 엔지니어의 역할
이로부터 알 수 있는 것이 몇가지 있는데, 우선 개발자와 유저가 생각하는 '명확한 요구사항'이 서로 다르다. 고객이 즉각적인 응답시간을 말할 때, 개발자들은 구간을 나눠서 무슨 구간이 얼마만큼 걸려야 하는지 묻는 등 기술적인 의견을 원한다. 그래서 요구사항을 받는 위치에 있는 사람은 개발자들이 고객과 긴밀한 소통을 유지하며 개발할 수 있도록 고객과 가까운 관계를 맺을 필요가 있다. 이 역할을 하는 사람을 비즈니스 애널리스트*Business Analyst* 또는 요구사항 엔지니어*Requirements Engineer*라고 부른다. 이들은 양측의 언어를 모두 이해하고 번역하는 통역자 역할을 한다. 고객의 비즈니스 용어를 개발 가능한 기술 요구사항으로 변환하고, 개발팀의 기술적 제약을 고객이 이해할 수 있는 비즈니스 임팩트로 설명한다.
# 요구사항을 확립하는 과정
그래서 요구사항을 확립하는 과정은 우선 이해관계자*Stakeholder*들의 니즈와 기대를 끄집어내는 과정부터 출발한다. 하지만 이들은 소프트웨어를 잘 모르는 경우가 많기 때문에 그들의 요구사항을 만족하기 위해 시스템이 갖춰야 할 시스템 요구사항*System Requirements*이 무엇인지 한눈에 파악하기는 어렵다. 그래서 이해관계자들의 요구사항을 바탕으로 기능과 품질에 대한 속성, 그리고 제품이 만족해야 할 요구사항을 확립하는 일련의 과정을 거치게 된다.
## Steakholders
이해관계자는 고객 외에도 광고 업체나 서비스 관리자 등 소프트웨어와 이런저런 이해관계로 연결되어 있는 개체를 의미하며 그들 또한 소프트웨어에 대하여 무언가 요구할 것이 있다. 그 대상은 매우 다양하다. 최종 사용자*End Users*는 시스템을 직접 사용하는 사람들로, 사용성과 효율성을 중시한다. 고객*Customers*은 시스템 구매를 결정하는 사람들로, 비용 대비 효과와 ROI를 중시한다. 운영팀*Operations*은 전체 시스템을 유지보수하는 팀으로, 안정성과 모니터링 가능성을 중시한다. 보안팀*Security*은 데이터 보호와 규정 준수를 중시하며, 마지막으로 마케팅팀*Marketing*은 시장 출시 시기와 경쟁력 있는 기능을 중시한다.
이렇듯 이해관계자들이 각자 다른 관점과 우선순위를 가지고 있기 때문에 교통정리가 필요하다. 이해관계자 분석*Stakeholder Analysis*은 이들 각각의 니즈와 영향력을 파악하고 우선순위를 정하는 과정이다. 모든 이해관계자를 동등하게 대할 수는 없으며, 영향력과 관심도에 따라 관리 전략을 달리해야 한다.
## 요구사항 수집 기법
이해관계자로부터 요구사항을 수집하는 방법도 다양하다:
- 인터뷰*Interviews*: 일대일 대화를 통해 심층적인 니즈를 파악한다. 구조화된 인터뷰와 비구조화된 인터뷰를 적절히 혼합한다.
- 워크숍*Workshops*: 여러 이해관계자를 모아 집단 토론을 통해 요구사항을 도출한다. 서로 다른 관점의 충돌을 조기에 발견할 수 있다.
- 설문조사*Questionnaires*: 많은 수의 사용자로부터 정량적 데이터를 수집한다.
- 관찰*Observation*: 실제 작업 환경에서 사용자의 행동을 관찰하여 명시되지 않은 니즈를 발견한다.
- 프로토타이핑*Prototyping*: 간단한 프로토타입을 만들어 사용자의 피드백을 받는다. "보여주면 무엇이 필요한지 알겠다"는 사용자들에게 효과적이다.
- 문서 분석*Document Analysis*: 기존 시스템의 매뉴얼, 업무 프로세스 문서 등을 분석한다.
## Usage vs Feature
요구사항을 확립할 때 두가지 접근 방식이 있는데, 하나는 사용*Usage* 기반 접근법이고, 다른 하나는 기능*Feature* 기반 접근법이다. 사용 기반 접근법이 사용자 중심으로 요구사항을 확립하는 방법이라면 기능 기반 접근법은 소프트웨어의 기능을 중심으로 요구사항을 확립하는 방법이다. 이때 사용 기반 접근법이 기능 기반 접근법보다 먼저 이루어져야 보다 더 고객의 니즈를 잘 만족시킬 수 있다.
### 사용 기반 접근법 (Usage-based)
사용 기반 접근법은 사용자 시나리오*User Scenarios*와 유스케이스*Use Cases*를 중심으로 "사용자가 무엇을 하고 싶어 하는가?"라는 질문에서 출발한다. "고객이 제품을 검색하여 장바구니에 담고 결제한다" 혹은 "관리자가 일일 매출 보고서를 조회한다"처럼 사용자의 경험에서 출발해 요구사항을 확립하는 것이다.
이 접근법의 장점은 실제 사용자의 워크플로우를 반영하므로 사용성이 높은 시스템을 만들 수 있다는 것이다. 사용자 스토리*User Stories* 형식("~로서, ~하기 위해, ~할 수 있다")이 이 접근법의 대표적인 예시다.
### 기능 기반 접근법 (Feature-based)
기능 기반 접근법은 시스템이 제공해야 할 기능 목록을 중심으로 요구사항을 정의한다. 검색 기능, 결제 처리 기능, 보고서 생성 기능과 같이 "시스템이 무엇을 할 수 있어야 하는가?"라는 질문에서 출발한다.
이 접근법의 위험은 실제 사용자가 필요로 하지 않는 기능들이 포함될 수 있다는 것이다. "있으면 좋겠다"와 "반드시 필요하다"를 구분하지 못하면 과도한 기능으로 복잡한 시스템이 만들어진다. 따라서 일반적으로 사용 기반 접근법으로 먼저 사용자의 니즈를 파악한 후, 이를 만족시키는 기능을 도출한다.
## Process
전체 과정을 크게 세 단계로 축약할 수 있다.
### Develop Customer Requirements
우선 고객의 요구사항을 찾아내야 한다. 소프트웨어 제품의 생명 주기 전체에 걸쳐 이해관계자들의 니즈, 기대, 제약 조건, 인터페이스를 분명하게 하고 이를 우선순위가 있는 고객 요구사항으로 변환해야 한다. 이 단계에서는 비즈니스 목표*Business Goals*를 이해하는 것이 핵심이다. "왜 이 시스템이 필요한가?", "어떤 문제를 해결하려고 하는가?", "성공을 어떻게 측정할 것인가?" 같은 질문들에 답해야 한다.
고객 요구사항은 "온라인 판매를 20% 증가시킨다", "고객 서비스 응대 시간을 30% 단축한다", "모바일 사용자 경험을 개선한다"와 같이 보통 높은 수준*High-level*에서 작성되며, 비즈니스 언어로 표현된다.
### Develop Product Requirements
고객의 요구사항을 도출하고 나면, 이를 기반으로 제품과 그 하위 요소 그리고 인터페이스에 대한 요구사항을 도출한다.
이 단계에서는 고객 요구사항을 구체적이고 측정 가능한 시스템 요구사항으로 변환한다. "온라인 판매를 20% 증가"라는 요구사항을 충족하기 위해서 모바일 앱에서 원클릭 구매 기능을 제공하거나 추천 알고리즘의 정확도를 85% 이상으로 끌어올리는 목표를 제시하고, "고객 서비스 응대 시간 30% 단축"이라는 요구사항을 충족하기 위해 FAQ 챗봇 구현이나 티켓 자동 분류 시스템을 요구사항으로 도출하는 등 본디 애매모호했던 고객의 요구사항을 구현 가능한 기술적인 요구사항으로 변환한다.
제품 요구사항에는 시스템이 수행해야 할 구체적인 기능인 기능 요구사항*Functional Requirements*, 성능, 보안, 사용성 등의 품질 속성인 비기능 요구사항*Non-functional Requirements*, 다른 시스템이나 하드웨어와의 상호작용에 관한 인터페이스 요구사항*Interface Requirements*이 있다.
### Analyze and Validate Requirements
제품에 적용할 요구사항이 완성되면, 운영 컨셉과 관련 시나리오 그리고 필요한 기능과 품질 평가 지표를 확립한 다음, 요구사항들이 필요하고 충분한지, 또 이해관계자들의 니즈와 제약 조건 사이의 균형을 맞췄는지 분석한 뒤 최종 결과물이 실사용에서 어떤 문제가 발생하는지 검증한다. 이 단계에서 수행하는 주요 활동은 크게 분석*Analysis*, 검증*Validation*, 추적성 관리*Traceability*로 요약된다.
분석 과정에서는 요구사항 간의 충돌이나 모순을 찾고, 누락된 요구사항 식별하거나 우선순위를 설정한다[^1]. 그리고 조건의 실현 가능성을 평가하는 활동도 포함된다. 검증 과정에서는 이해관계자와 함께 요구사항을 리뷰하고, 프로토타입이나 목업을 통한 시뮬레이션이나 시나리오 워크스루*Walkthrough*를 진행한다. 인수 기준*Acceptance Criteria*을 정의하는 일도 여기에 포함된다. 추적성 관리 과정에서는 각 요구사항이 비즈니스 목표와 어떻게 연결되는지 문서로 만들고 요구사항이 어떻게 설계, 구현, 테스트로 이어지는지 추적한다.
# 요구사항의 종류
요구사항은 크게 네 가지 범주로 나눌 수 있다. 각각은 서로 다른 측면을 다루며, 완전한 시스템을 정의하려면 모든 범주가 필요하다.
## Functional Requirements
기능 요구사항*Functional Requirements*은 시스템이 무엇을 해야 하는지를 정의한다. 시스템의 기능, 입력과 출력, 그리고 시스템의 동작을 기술한다. 사용자나 다른 시스템과의 상호작용을 명세하고 특정 입력에 대한 시스템의 반응을 정의하며 시스템이 특정 상황에서 어떻게 동작하는지를 설명한다. 여기에는 시스템이 하지 말아야 할 것도 포함할 수 있다.
### 작성 방법
기능 요구사항은 일반적으로 다음과 같은 형식으로 작성된다:
> "시스템은 \[조건\]일 때 \[동작\]을 수행해야 한다"
예시:
- "시스템은 사용자가 로그인 버튼을 클릭했을 때 이메일과 비밀번호를 검증해야 한다"
- "시스템은 결제가 완료되면 주문 확인 이메일을 자동으로 발송해야 한다"
- "시스템은 관리자가 사용자 계정을 삭제할 때 확인 메시지를 표시해야 한다"
- "시스템은 재고가 10개 이하로 떨어지면 담당자에게 알림을 보내야 한다"
### 세부 수준
기능 요구사항은 여러 수준의 세밀도로 작성될 수 있다. 고수준, 그러니까 사용자의 언어에 가깝게 기능 요구사항을 적을 떄는 "시스템은 사용자 인증을 지원한다"라고 하지만, 더욱 상세하게 기능 요구사항을 적게 되면 "시스템은 이메일과 비밀번호 기반 로그인을 지원한다", "시스템은 소셜 로그인(Google, Facebook, Apple)을 지원한다", "시스템은 비밀번호를 최소 8자, 대소문자 및 특수문자 포함으로 검증한다", "시스템은 3회 로그인 실패 시 계정을 15분간 잠금한다", "시스템은 비밀번호 재설정 링크를 이메일로 발송한다"와 같이 적게 되는 것이다.
### 유스케이스와의 관계
기능 요구사항은 종종 [[Use Case Modeling|유스케이스]]*Use Case*로 구조화된다. 유스케이스는 사용자*Actor*와 시스템 간의 상호작용을 시나리오 형태로 기술한다.
예시:
```
유스케이스: 상품 주문
액터: 고객
사전 조건: 고객이 로그인되어 있음
주요 흐름:
1. 고객이 상품을 검색한다
2. 시스템이 검색 결과를 표시한다
3. 고객이 상품을 선택한다
4. 시스템이 상품 상세 정보를 표시한다
5. 고객이 장바구니에 추가한다
6. 시스템이 장바구니를 업데이트한다
7. 고객이 결제를 진행한다
8. 시스템이 결제를 처리한다
9. 시스템이 주문 확인을 표시한다
대체 흐름:
4a. 상품이 품절인 경우
4a1. 시스템이 품절 메시지를 표시한다
4a2. 시스템이 입고 알림 등록 옵션을 제공한다
```
## Quality Attribute Requirements
^4bb6e2
품질 속성 요구사항*Quality Attribute Requirements* 또는 비기능 요구사항*Non-Functional Requirements*은 시스템이 얼마나 잘 동작해야 하는지를 정의한다. 기능 요구사항이 "무엇을 해야 하는지"를 다룬다면, 품질 속성은 "얼마나 잘 해야 하는지"를 다룬다.
### 주요 품질 속성
#### 성능*Performance*
"시스템은 95%의 API 요청을 500ms 이내에 응답해야 한다", "시스템은 초당 10,000개의 동시 요청을 처리할 수 있어야 한다", "데이터베이스 쿼리는 평균 100ms 이내에 완료되어야 한다"와 같이 시스템의 응답성과 처리량을 정의한다.
#### 확장성*Scalability*
"시스템은 사용자 수가 두 배로 증가해도 성능 저하가 20%를 넘지 않아야 한다", "시스템은 수평 확장을 통해 처리량을 선형적으로 증가시킬 수 있어야 한다"와 같이 시스템이 증가하는 부하를 처리할 수 있는 능력을 정의한다.
#### 신뢰성*Reliability*
"시스템의 가동률*Uptime*은 99.9% 이상이어야 한다 (월 43분 이하 다운타임)", "시스템은 단일 서버 장애 시에도 서비스를 계속 제공할 수 있어야 한다", "데이터 손실은 RPO*Recovery Point Objective* 1시간 이내로 제한되어야 한다"와 같이 시스템의 가동 시간과 오류 처리 능력을 정의한다.
#### 가용성*Availability*
"시스템은 24/7 운영되어야 한다", "계획된 유지보수는 주말 새벽 시간대에만 수행되어야 한다", "시스템 장애 발생 시 5분 이내에 복구되어야 한다 (RTO*Recovery Time Objective*)"와 같이 시스템이 필요할 때 사용 가능한 정도를 정의한다.
#### 보안*Security*
"모든 데이터 전송은 TLS 1.3 이상으로 암호화되어야 한다", "비밀번호는 bcrypt 알고리즘으로 해시되어 저장되어야 한다", "시스템은 역할 기반 접근 제어*RBAC*를 구현해야 한다", "민감한 개인정보는 암호화되어 저장되어야 한다", "시스템은 모든 보안 관련 이벤트를 로깅해야 한다"와 같이 시스템의 데이터 보호와 접근 제어를 정의한다.
#### 사용성*Usability*
"신규 사용자는 5분 이내에 첫 주문을 완료할 수 있어야 한다", "주요 기능은 3번의 클릭 이내에 접근 가능해야 한다", "시스템은 WCAG 2.1 Level AA 접근성 표준을 준수해야 한다", "오류 메시지는 사용자가 문제를 해결할 수 있는 구체적인 안내를 포함해야 한다"와 같이 시스템의 사용 편의성을 정의한다.
#### 유지보수성*Maintainability*
"코드는 ESLint 규칙을 준수해야 한다", "모든 퍼블릭 API는 문서화되어야 한다", "시스템은 모듈화되어 개별 컴포넌트를 독립적으로 업데이트할 수 있어야 한다", "코드 커버리지는 80% 이상이어야 한다"와 같이 시스템의 수정과 개선 용이성을 정의한다.
#### 이식성*Portability*
"시스템은 Windows, macOS, Linux에서 동작해야 한다", "모바일 앱은 iOS 14 이상, Android 10 이상을 지원해야 한다", "시스템은 Chrome, Safari, Firefox, Edge 최신 2개 버전을 지원해야 한다"와 같이 시스템의 다양한 환경 지원 능력을 정의한다.
### 측정 가능성의 중요성
품질 속성 요구사항은 반드시 **측정 가능해야** 한다. "빠른 응답", "높은 보안", "좋은 사용성"과 같은 모호한 표현은 피해야 한다. "시스템은 빠르게 응답해야 한다" 대신 "시스템은 95%의 요청을 2초 이내에 응답해야 한다"라고 정의하고, "시스템은 사용하기 쉬워야 한다" 대신 "신규 사용자의 80%가 도움말 없이 주요 작업을 완료할 수 있어야 한다"라고 정의해야 한다.
## Constraints
제약사항*Constraints*은 시스템 설계와 구현에 대한 **제한사항**을 정의한다. 이는 선택의 여지가 없는 요구사항으로, 반드시 준수해야 한다.
### 제약사항의 유형
#### 기술적 제약*Technical Constraints*
"시스템은 AWS 클라우드에서 호스팅되어야 한다", "백엔드는 Java Spring Boot로 개발되어야 한다", "데이터베이스는 PostgreSQL을 사용해야 한다", "기존 레거시 시스템의 REST API와 통합되어야 한다", "시스템은 Docker 컨테이너로 배포되어야 한다"와 같이 특정 기술 스택이나 플랫폼 사용을 강제하는 제약이다.
#### 비즈니스 제약*Business Constraints*
"프로젝트는 6개월 이내에 완료되어야 한다", "개발 예산은 1억원을 초과할 수 없다", "개발팀은 최대 5명으로 구성된다", "시스템은 2025년 3월 1일까지 출시되어야 한다"와 같은 예산, 일정, 인력 등의 현실적 제한이다.
#### 규제적 제약*Regulatory Constraints*
"시스템은 GDPR을 준수해야 한다", "개인정보는 한국 내 데이터센터에 저장되어야 한다", "의료 데이터 처리는 HIPAA 표준을 준수해야 한다", "금융 거래는 PCI-DSS 인증을 받아야 한다", "전자서명은 전자서명법을 준수해야 한다"와 같이 법률, 규정, 표준 준수를 요구하는 제약이다.
#### 조직적 제약*Organizational Constraints*
"코드는 회사의 Git 저장소에 저장되어야 한다", "모든 배포는 CI/CD 파이프라인을 통해 이루어져야 한다", "UI는 회사의 디자인 시스템을 따라야 한다", "보안 취약점 스캔을 통과해야 한다"처럼 회사 정책이나 표준을 따라야 하는 제약이다.
#### 물리적 제약*Physical Constraints*
"모바일 앱 크기는 50MB를 초과할 수 없다 (App Store 제한)", "시스템은 오프라인 환경에서도 기본 기능을 제공해야 한다", "센서 데이터는 IoT 기기의 제한된 메모리(512KB) 내에서 처리되어야 한다"처럼 하드웨어나 환경에 의한 제약을 의미한다.
### 제약사항 vs 요구사항
제약사항과 요구사항의 차이를 이해하는 것도 중요하다. 요구사항이 목표를 달성하기 위한 것으로, 여러 방법으로 구현할 수 있다면 제약사항은 반드시 준수해야 하는 것으로, 선택의 여지가 없다. 예를 들어, "사용자 인증이 필요하다"는 요구사항은 JWT, OAuth 등 다양한 방법으로 구현할 수 있지만, "OAuth 2.0을 사용해야 한다"는 제약사항은 다른 방법으로 구현할 수 없다.
## External Interfaces
외부 인터페이스*External Interfaces*는 시스템이 **외부 개체와 어떻게 상호작용하는지**를 정의한다. 시스템은 독립적으로 존재하지 않고 다양한 외부 요소와 통신하므로, 이러한 인터페이스를 명확히 정의하는 것이 중요하다.
### 인터페이스의 유형
#### 사용자 인터페이스*User Interface*
"시스템은 웹 브라우저 기반 인터페이스를 제공한다", "모바일 앱은 iOS Human Interface Guidelines를 따라야 한다", "관리자 대시보드는 데이터 시각화를 위해 차트와 그래프를 제공한다", "시스템은 다국어를 지원해야 한다 (한국어, 영어, 일본어)", "모든 폼은 실시간 유효성 검사를 제공해야 한다"와 같이 사용자와 시스템 간의 상호작용을 정의한다.
#### 하드웨어 인터페이스*Hardware Interface*
"시스템은 바코드 스캐너로부터 USB를 통해 데이터를 수신한다", "IoT 센서는 MQTT 프로토콜을 통해 5분마다 온도 데이터를 전송한다", "결제 단말기는 RS-232 시리얼 포트로 연결된다", "프린터는 ESC/POS 명령어를 지원해야 한다"와 같이 시스템이 물리적 하드웨어와 통신하는 방법을 정의한다.
#### 소프트웨어 인터페이스*Software Interface*
"시스템은 결제를 위해 Stripe API v2023-08-16을 사용한다", "재고 관리를 위해 SAP ERP 시스템과 REST API로 통합된다", "사용자 인증을 위해 Google OAuth 2.0 API를 사용한다", "이메일 발송을 위해 SendGrid API를 호출한다"처럼 시스템이 다른 소프트웨어 시스템과 통신하는 방법을 정의한다.
구체적인 API 명세는 다음과 같이 엔드포인트와 요청 및 응답 형식을 정의한다.
```
엔드포인트: POST /api/v1/orders
요청 형식:
{
"customerId": "string",
"items": [
{
"productId": "string",
"quantity": number
}
],
"shippingAddress": {
"street": "string",
"city": "string",
"zipCode": "string"
}
}
응답 형식:
{
"orderId": "string",
"status": "pending" | "confirmed" | "failed",
"totalAmount": number,
"estimatedDelivery": "ISO 8601 date string"
}
```
#### 통신 인터페이스*Communication Interface*
"시스템은 HTTPS (TLS 1.3)를 통해 통신한다", "실시간 알림은 WebSocket을 사용한다", "대용량 파일 업로드는 HTTP multipart/form-data를 지원한다", "마이크로서비스 간 통신은 gRPC를 사용한다", "메시지 큐는 RabbitMQ AMQP 프로토콜을 사용한다"와 같이 시스템의 네트워크 통신 방법을 정의한다. 그 외에도 임의로 설정 가능한 프로토콜은 더욱 구체적으로 "모든 API는 JSON 형식으로 데이터를 교환한다", "인증은 Bearer 토큰을 HTTP Authorization 헤더에 포함한다", "API 버전은 URL 경로에 포함된다 (예: /api/v1/)", "페이지네이션은 쿼리 파라미터 page와 limit을 사용한다"와 같이 어떻게 구현할지도 설명해야 한다.
### 인터페이스 명세의 중요성
외부 인터페이스는 시스템 통합에서 가장 많은 문제가 발생하는 영역이다. 명확한 인터페이스 명세가 없으면 통합 테스트가 지연되고, 서로 다른 팀이 다른 가정을 하게 되고, 프로덕션 환경에서 호환성 문제가 발생하고, 버전 관리와 하위 호환성 유지가 어려워진다.
따라서 인터페이스 요구사항은 데이터 형식, 프로토콜, 오류 처리 등을 **상세하고 명확하게** 정의해야 하고, API 문서나 통합 가이드와 같은 형태로 **문서화되어야** 하며, 코드 변경이 주는 영향력을 최소화하기 위해 **버전 관리**가 이루어져야 하며, 마지막으로 목*Mock* 서버나 테스트 데이터 등의 테스트 환경 속에서 **테스트할 수 있어야 한다**.
[^1]:: MoSCoW(Must have, Should have, Could have, Won't have)에 따라 우선순위를 정한다.