유스케이스 다이어그램을 그리다 보면 관계 표기에서 가장 자주 막힌다. “주문하기를 하려면 인증이 필요한데, 이걸 include로 묶어야 하나? extend로? 아니면 사전조건?” 같은 질문이다. 교과서와 실무 자료가 같은 동작을 다르게 그리는 경우가 흔하고, UML 명세의 엄격한 정의를 들이대면 익숙한 관행이 어긋나기도 한다.
이 글은 사용자 인증이라는 친숙한 예시를 통해 include·extend·사전조건·가드 조건의 경계를 정리하고, 같은 기준으로 다른 흔한 오남용 사례까지 살핀다.
1. include의 본래 의미와 인증의 부조화
include 관계의 본래 의미는 “기반 유스케이스가 실행될 때마다 포함된 유스케이스가 무조건 함께 실행된다”는 것이다. 즉 조건 없이 항상 일어나는 공통 동작을 분리할 때 쓰는 표기다.
먼저 흔한 오해 하나를 짚는다. include는 동시에 실행되는 행위가 아니다. 시간적으로 병렬로 함께 도는 관계가 아니라, “기반 유스케이스의 흐름 안에서, 정해진 지점에 도달하면 무조건 그 동작이 끼어들어 실행되고, 끝나면 원래 흐름으로 복귀하는” 관계다. 프로그래밍으로 비유하면 함수 본문 안에서 무조건 호출되는 헬퍼 함수 호출문에 가깝다. “동시”라는 인식으로 가면 동시성(concurrency) 개념과 혼동되기 쉬워 주의가 필요하다.
본질이 무조건성에 있다는 점을 정리하고 나면, 인증은 이 무조건성을 만족하지 못한다는 게 분명해진다.
- 인증은 보통 세션 단위로 한 번 이루어진다. 이미 로그인된 상태라면 다시 일어나지 않는다.
- “주문하기”를 세 번 수행해도 로그인은 한 번뿐이다. 기반 유스케이스의 실행 횟수와 인증의 발생 횟수가 일치하지 않는다.
또한 더 근본적인 지적이 있다. 유스케이스는 액터에게 관찰 가능한 가치(목표)를 주는 단위여야 한다는 관점에서 보면, “로그인” 자체는 사용자의 목표가 아니라 다른 목표를 수행하기 위한 전제 조건에 가깝다. 그래서 Alistair Cockburn 등 여러 저자들은 인증을 별도 유스케이스로 빼서 include로 연결하기보다, 해당 유스케이스의 사전조건으로 기술할 것을 권장한다.
표현 선택지는 세 가지다.
- 사전조건으로 기술 — 의미상 가장 깔끔하며 권장되는 방식. 예: “주문하기” 유스케이스의 사전조건에 “사용자가 인증되어 있어야 한다”고 명시.
- include로 표현 — 여러 유스케이스가 인증을 공유할 때 중복을 줄이는 실용적 표기. 학습 자료와 실무 문서에서 폭넓게 통용된다.
- 독립 유스케이스로 분리 — 인증 기능 자체가 시스템의 핵심이거나 사용자에게 의미 있는 목표일 때.
2. extend는 대안이 될 수 있는가
include가 무조건성 때문에 인증에 맞지 않는다면, 조건성을 명시할 수 있는 extend가 더 적합하지 않은가 하는 의문이 자연스럽다.
extend의 본래 의미는 “기반 유스케이스의 *확장 지점(extension point)*에서, 조건이 충족되면 확장 유스케이스가 끼어들어 실행되는” 관계다. 즉 옵셔널하고 조건적인 추가 동작을 모델링하는 표기다. 인증이 가진 “이미 로그인되어 있으면 일어나지 않고, 아니면 일어난다”는 조건성을 직접 표현할 수 있다는 점에서 include보다 한 발 가깝다.
다만 두 가지 결정적 불일치가 남는다.
- 기반 유스케이스가 확장 없이도 완결되어야 한다는 게
extend의 전제다. “주문하기”는 인증되지 않은 사용자에게는 완료될 수 없다. 즉 인증은 옵셔널이 아니라 필수다. - 시점이 다르다.
extend는 기반 유스케이스의 흐름 안에 끼어드는 동작이고, 인증은 기반 유스케이스가 시작되기 전에 충족되어 있어야 하는 상태다.
조건성만 보면 extend가 더 가깝고, 의미적 정합성으로 보면 여전히 사전조건이 가장 자연스럽다. 둘 사이에서 굳이 다이어그램 표기를 골라야 한다면 extend가 덜 부정확하지만, 본질은 사전조건이라는 결론은 바뀌지 않는다.
3. 사전조건·가드 조건·트리거의 층위
이 세 개념은 모두 “유스케이스 시작 전후”를 다루지만 층위가 다르다. 같은 인증 동작을 어떤 개념에 매핑하느냐가 흔히 흐려진다.
| 개념 | 시간상 위치 | 성격 | 예 |
|---|---|---|---|
| 트리거 (trigger) | 유스케이스 시작 시점에 발생 | 이벤트 | ”사용자가 주문 버튼을 누른다” |
| 사전조건 (precondition) | 유스케이스 시작 전에 이미 참 | 상태 | ”사용자가 인증되어 있다” |
| 가드 조건 (guard) | 흐름 안의 분기점에서 평가 | 조건식 | ”결제금액 > 100,000원이면 본인 인증 추가” |
- 트리거가 발생해야 유스케이스가 시작된다. 트리거 없이는 유스케이스가 존재하지 않는다.
- 사전조건은 트리거가 발생했을 때 이미 참이어야 한다. 거짓이면 유스케이스는 시작되지 않는다. 시작했다가 중간에 깨지는 게 아니다.
- 가드 조건은 유스케이스가 시작된 후 흐름 안의 분기점에서 평가된다. 액티비티/상태 다이어그램 표기에서 주로 쓰며, 유스케이스 텍스트 명세에서는 보통 alternative flow의 진입 조건으로 등장한다.
인증을 이 세 가지로 매핑해 보면 트리거(이벤트)나 가드(분기점)에는 어울리지 않고 사전조건(상태)이 가장 자연스럽다. 이 구분이 흐려지는 흔한 사례는 “결제 금액이 일정 이상이면 추가 인증” 같은 케이스인데, 이때는 기본 인증은 사전조건이고 추가 인증은 가드다. 같은 단어 “인증”이라도 어디 위치하느냐에 따라 다른 개념에 매핑된다.
4. “흐름의 단계”와 “사전조건”의 경계
include가 표현하는 “흐름의 단계”와 사전조건의 경계가 애매하게 느껴지는 것은 자연스러운 일이며, 바로 그 애매함 때문에 인증이 단골 논쟁거리가 된다. 다만 경계를 가르는 기준은 분명히 존재한다. 핵심 질문은 “그 동작이 이 유스케이스의 책임 범위 안에 있느냐”이다.
include되는 단계는 기반 유스케이스의 흐름이 시작된 이후에, 그 흐름의 일부로서 발생한다. 유스케이스가 그 동작의 실행을 책임지며, 동작이 실패하면 그 실패를 어떻게 처리할지(대안 흐름, 예외 처리)까지 떠안는다.
사전조건은 유스케이스의 흐름이 시작되기 전에 이미 참이어야 하는 상태다. 누가 그 상태를 만들었는지는 이 유스케이스의 관심사가 아니다. 사전조건이 거짓이면 유스케이스는 아예 시작되지 않는다. 시작했다가 중간에 실패하는 것이 아니다.
판정에 쓸 수 있는 세 가지 질문:
- 시간적으로 흐름 안인가 밖인가. 동작이 트리거 이후에 일어나면 단계, 트리거 시점에 이미 완료되어 있어야 하면 사전조건.
- 실패 처리를 누가 책임지는가. “주문하기”가 결제 거절 시 대안 흐름을 정의해야 한다면 결제는 주문하기의 책임 안에 있으므로 단계다. 반면 인증 실패 시 “주문하기” 다이어그램이 로그인 재시도 흐름을 그릴 책임은 보통 없다. 그것은 인증이라는 별개 관심사가 처리한다. 이것이 인증을 사전조건으로 보는 강한 근거다.
- 매 실행마다 반복되는가. 유스케이스 실행 횟수와 동작 발생 횟수가 일치하면 단계, 어긋나면 사전조건 쪽이다.
그런데 이 경계가 여전히 애매하게 느껴지는 진짜 이유는, 이것이 객관적 사실이 아니라 모델러의 경계 설정 결정이기 때문이다.
- “주문하기”를 “로그인 화면 진입부터 주문 완료까지”로 정의하면 인증은 흐름 안에 들어와 단계가 된다.
- “이미 로그인된 사용자가 장바구니에서 주문을 확정하는 행위”로 정의하면 인증은 흐름 밖으로 빠져 사전조건이 된다.
같은 인증이라는 동작이 유스케이스 경계를 어디에 긋느냐에 따라 양쪽 다 될 수 있다. 즉 애매함은 동작 자체에서 오는 것이 아니라, 유스케이스의 범위를 먼저 확정하지 않고 판정하려 할 때 생긴다.
따라서 실무에서 권장되는 순서는 이렇다. 먼저 “이 유스케이스는 어디서 시작해서 어디서 끝나는가”를 한 문장으로 못 박는다. 그다음 문제의 동작이 그 시작점 이전인지 이후인지를 본다. 그러면 include냐 사전조건이냐는 거의 자동으로 결정된다.
5. include로 흔히 잘못 그리는 사례들
인증 말고도 교과서에서 관행적으로 include로 그리지만 엄밀히는 다른 표현이 맞는 동작들이 있다. 같은 기준(무조건성·책임 범위·시점)으로 재검토하면 다음과 같다.
| 동작 | 흔한 표기 | 더 적절한 표기 | 이유 |
|---|---|---|---|
| 로그 기록 | include | 다이어그램에서 제외 | 횡단 관심사(cross-cutting). 모든 유스케이스에 매달면 가독성 0 |
| 권한 검사 | include | 사전조건 또는 액터 분리 | 인증과 동일 — 흐름 시작 전 상태 |
| 입력 검증 | include | 메인 흐름의 내부 step | 독립 유스케이스가 될 만큼 응집되어 있지 않음 |
| 트랜잭션 시작/종료 | include | 표현하지 않음 | 구현 디테일. 분석 모델에 등장할 일 없음 |
| 알림 발송 | include | extend | 옵셔널·조건적. 알림 실패가 기반 유스케이스를 실패시키지 않음 |
| 오류 로깅 | include | alternative flow 내부 | 정상 흐름에 끼어드는 게 아니라 예외 처리의 일부 |
이 다섯 가지가 다이어그램에 유스케이스로 등장하는 순간, 다이어그램은 비즈니스 의미가 아니라 구현 단계 흐름도로 변질된다. 검토자가 비즈니스 합의를 위해 보러 왔다가 헤매는 가장 흔한 이유 중 하나다.
6. 그럼에도 교과서는 왜 인증을 include로 두는가
엄격한 정의와 어긋남에도 불구하고 교과서가 이 예시를 고수하는 데는 몇 가지 이유가 겹쳐 있다.
교육적 편의. include를 가르치려면 “여러 유스케이스가 공유하는 공통 동작”이라는 직관적 예시가 필요하다. 인증은 “주문하기, 글쓰기, 마이페이지 보기”처럼 서로 다른 기능들이 모두 거쳐야 하는 동작으로 설명하기 쉬워, “중복되는 것을 하나로 뺀다”는 개념을 단번에 전달하기에 최적이다.
느슨한 정의. 많은 입문서가 include를 UML 명세대로 “항상 무조건 실행”이 아니라 “공통 기능의 재사용” 또는 “중복 제거”라는 느슨한 표현으로 소개한다. 이 정의 안에서는 인증이 완벽한 예시가 되며, 모순이 아니다. 불일치는 명세의 엄격한 정의를 기준으로 했을 때만 드러난다.
추상화 수준의 차이. 유스케이스를 “이미 로그인된 세션에서 주문 버튼을 누르는 행위”로 좁게 보면 인증은 매번 실행되지 않는다. 그러나 “주문하기를 완수하는 전체 시나리오”로 넓게 보면, 인증되지 않은 사용자는 그 과정에서 반드시 인증을 거친다. 교과서는 보통 이 넓은 수준에서 다이어그램을 그리며, 세션 캐싱 같은 구현 디테일은 분석 단계에서 의도적으로 추상화한다.
관행의 자기강화. 초창기 UML 교재가 이 예시를 채택한 이후 후속 자료들이 답습하면서 사실상 표준 예시로 굳어졌다. 채점자도 같은 교재로 배웠기 때문에 세대를 거쳐 정착되었다.
정리하면, 교과서의 예시는 “틀린 것”이 아니라 단순화된 정의와 넓은 추상화 수준 위에서는 타당한 설명이며, 명세를 엄격히 적용하는 관점에서만 문제가 보인다.
정리
include의 본질은 무조건성이다. 인증은 세션 단위로 한 번만 일어나기에 이 무조건성을 만족하지 못한다.extend는 조건성 측면에서는 한 발 가깝지만, 옵셔널 추가라는 의미가 인증의 필수 전제와 어긋난다. 인증은 결국 사전조건으로 두는 게 가장 정확하다.- 사전조건·가드·트리거는 시간상 위치와 성격이 다르다. 인증은 상태라서 사전조건, 흐름 안의 분기는 가드, 시작을 만드는 이벤트는 트리거다.
- 흐름의 단계인지 사전조건인지는 동작의 본질이 아니라 모델러의 범위 설정 결정이다. 범위를 먼저 못 박으면 표기가 따라온다.
- 로그·권한·검증·트랜잭션·알림 같은 흔한
include오남용은 대부분 다른 표현(텍스트 명세·예외 처리·extend·다이어그램 제외)이 더 적절하다. - 교과서가 인증을
include로 두는 관행이 명세를 엄격히 따르지 않더라도, 교육 맥락에서는 의도된 단순화다. 둘은 모순이 아니라 추상화 수준의 차이다.
표현이 헷갈리는 건 보통 동작이 모호해서가 아니라, 유스케이스의 범위가 흐려서다.