UML

작성일:2024.07.22|조회수:0

UML

소프트웨어 시스템은 코드로 구현되지만, 코드만으로 시스템 전체를 설명하기는 어렵다. 특히 여러 명이 함께 개발하거나, 시간이 지나 다시 코드를 바라보는 상황에서는 “이 시스템이 어떤 구조를 가지고 있고, 왜 이렇게 설계되었는지”를 빠르게 파악하기가 쉽지 않다. 이런 맥락에서 설계 의도를 압축적으로 전달할 수 있는 시각적 표현은 여전히 중요한 역할을 한다.

UML(Unified Modeling Language)은 이러한 문제를 해결하기 위해 등장한 표준 모델링 언어다. UML은 특정 언어나 프레임워크에 종속되지 않고, 시스템을 구성하는 요소와 그 관계, 그리고 동작 방식을 공통된 기호와 규칙으로 표현한다. 중요한 점은 UML의 목적이 문서를 남기는 데 있지 않다는 것이다. UML은 설계를 강제하는 규칙이 아니라, 사고를 정리하고 팀 간의 이해를 맞추기 위한 도구에 가깝다.

실무에서 UML이 부담스럽게 느껴지는 이유는 종종 “모든 것을 정확히 그려야 한다”는 오해 때문이다. 하지만 좋은 UML 다이어그램은 완벽함보다 명확함을 우선한다. 설명하려는 대상과 목적에 맞는 수준으로 단순화되어 있어야 하며, 필요 이상으로 많은 정보를 담을수록 오히려 전달력은 떨어진다.

결국 UML에서 중요한 것은 정확한 묘사가 아니라 적절한 추상화다. 추상화란 세부 구현을 감추는 것이 아니라, 지금 이 순간 이해해야 할 핵심만을 드러내는 행위에 가깝다. 어떤 클래스가 내부적으로 어떤 필드를 가지는지보다, 그 클래스가 어떤 책임을 수행하고 다른 요소와 어떤 관계를 맺는지가 더 중요할 수 있다.

구조 다이어그램(Structural Diagram)

구조 다이어그램은 시스템을 구성하는 요소들과 그 사이의 관계를 표현한다. 이 다이어그램의 초점은 “무엇이 어떤 역할을 맡고 있는가”에 있으며, 코드가 실제로 어떻게 실행되는지보다는 설계 단계에서의 구조적 판단을 드러내는 데 있다. 다시 말해, 구조 다이어그램은 시스템을 한 시점에 멈춰 세워 놓고 내부를 들여다보는 도구라고 볼 수 있다.

이러한 다이어그램은 특히 시스템의 규모가 커질수록 가치가 커진다. 개별 클래스나 모듈의 구현을 모두 따라가지 않더라도, 전체적인 구성과 의존 관계를 빠르게 파악할 수 있기 때문이다. 또한 구조 다이어그램은 팀 내에서 설계에 대한 공통된 이해를 형성하는 데 중요한 역할을 하며, 변경이 발생했을 때 그 영향 범위를 가늠하는 기준점이 되기도 한다.

클래스 다이어그램(Class Diagram)

클래스 다이어그램은 구조 다이어그램 가운데서도 객체지향 설계를 설명하는 데 가장 핵심적인 역할을 한다. 이 다이어그램은 시스템에 어떤 클래스들이 존재하는지, 각 클래스가 어떤 상태와 행위를 가지는지, 그리고 클래스들 사이에 어떤 관계가 형성되어 있는지를 한눈에 보여준다.

클래스 다이어그램의 중요한 목적은 단순히 클래스 목록을 나열하는 데 있지 않다. 오히려 각 클래스가 맡고 있는 책임의 경계를 드러내고, 책임이 어떻게 분리되고 협력하는지를 설명하는 데 의미가 있다. 잘 그려진 클래스 다이어그램은 코드 없이도 도메인의 주요 개념과 객체 간 역할 분담을 이해할 수 있게 만든다.

실무에서 클래스 다이어그램은 도메인 모델을 설계할 때 특히 유용하다. 엔티티, 값 객체, 서비스와 같은 개념들이 어떻게 나뉘어야 하는지 논의할 때, 클래스 다이어그램은 추상적인 대화를 구체적인 구조로 끌어내리는 역할을 한다. 또한 설계 변경이 필요할 때, 클래스 간 관계를 기준으로 영향 범위를 빠르게 파악할 수 있다는 장점도 있다.

다만 클래스 다이어그램은 구현 상세를 모두 담아내는 문서가 아니다. 모든 필드와 메서드를 표현하려고 하기보다는, 클래스의 성격과 책임이 드러나는 핵심 요소만 남기는 것이 바람직하다. 클래스 다이어그램의 가치는 정보의 양이 아니라, 구조를 얼마나 명확하게 전달하느냐에 의해 결정된다.

기호

접근 제어자

의미

+

public

외부 접근 가능

-

private

클래스 내부 전용

#

protected

상속 관계에서 접근 가능

__

static

클래스 레벨 멤버

{final}

final 메서드

재정의 불가

<<final>>

final 클래스

상속 불가

{readOnly}

읽기 전용

값 변경 불가

{leaf}

리프 클래스

더 이상 확장 불가

TS
+------------------------------------+
| <<interface>>                      |
| Payable                            |
+------------------------------------+
| + pay(amount): void                |
+------------------------------------+


+------------------------------------+
| <<abstract>>                       |
| AbstractPayment                    |
+------------------------------------+
| # id: string                       |
| __# DEFAULT_FEE: number__          |
+------------------------------------+
| + pay(amount): void {final}        |
| # calculateFee(): number           |
| __+ generateId(): string__         |
+------------------------------------+


+------------------------------------+
| <<final>> {leaf}                   |
| CreditCardPayment                  |
+------------------------------------+
| - cardNumber: string {readOnly}    |
+------------------------------------+
| + mask(): string                   |
+------------------------------------+

행위 다이어그램(Behavioral Diagram)

앞에서 살펴본 구조 다이어그램이 시스템의 정적인 모습을 설명한다면, 행위 다이어그램은 시스템이 어떻게 동작하는지, 즉 시간의 흐름 속에서 어떤 상호작용이 발생하는지를 표현한다. 구조 다이어그램이 설계의 뼈대를 보여준다면, 행위 다이어그램은 그 뼈대 위에서 실제로 벌어지는 움직임을 설명하는 도구라고 볼 수 있다.

행위 다이어그램의 핵심 관점은 “이 코드가 어떤 순서로 실행되는가”가 아니다. 대신 객체나 사용자, 시스템 요소들이 어떤 역할로 참여하고, 어떤 메시지를 주고받는가에 초점을 둔다. 그래서 행위 다이어그램은 구현 상세를 설명하기보다는, 흐름과 책임의 분리를 명확히 하는 데 더 큰 가치를 가진다. 특히 요구사항 분석이나 설계 리뷰 단계에서 행위 다이어그램은 큰 힘을 발휘한다. 구조 다이어그램만으로는 드러나지 않는 실행 흐름, 조건 분기, 사용자와 시스템 간의 상호작용을 한 눈에 보여주기 때문이다.

시퀀스 다이어그램(Sequence Diagram)

시퀀스 다이어그램은 객체나 시스템 구성 요소들이 시간 순서에 따라 어떤 메시지를 주고받는지를 표현하는 다이어그램이다. 이름 그대로 “순서(sequence)”가 가장 중요한 요소이며, 위에서 아래로 시간이 흐른다.

이 다이어그램의 목적은 로직을 상세히 설명하는 데 있지 않다. 대신 하나의 시나리오를 기준으로, 누가 시작하고, 누가 응답하며, 책임이 어디로 이동하는지를 명확히 보여준다. 그래서 시퀀스 다이어그램은 API 호출 흐름이나 요청–응답 구조를 설명할 때 특히 자주 사용된다.

아래는 결제 요청 흐름을 단순화한 시퀀스 다이어그램 예시다.

User        Controller        Service        Repository
 |              |               |               |
 |-- request -->|               |               |
 |              |-- pay() ----->|               |
 |              |               |-- save() ---->|
 |              |               |<-- result ----|
 |              |<-- response --|               |
 |<-- result ---|               |               |

이 다이어그램에서 읽어야 할 정보는 다음과 같다.

시퀀스 다이어그램은 하나의 유스케이스, 하나의 시나리오를 기준으로 그리는 것이 중요하다. 여러 흐름을 한 장에 억지로 담기 시작하면, 다이어그램은 설명 도구가 아니라 해석이 필요한 퍼즐이 된다.

유스케이스 다이어그램(Use Case Diagram)

유스케이스 다이어그램은 시스템을 사용자 관점에서 바라본다. 이 다이어그램은 내부 구조나 구현 방식에는 관심이 없고, 오직 “이 시스템이 사용자에게 어떤 기능을 제공하는가”에만 집중한다.

그래서 유스케이스 다이어그램은 개발자뿐 아니라 기획자, 디자이너, 이해관계자와 소통할 때 특히 유용하다. 시스템의 범위를 명확히 하고, 무엇을 제공하고 무엇을 제공하지 않는지를 선명하게 드러내기 때문이다.

아래는 간단한 유스케이스 다이어그램 예시다.

CSS
[사용자]
   |
   |-- (로그인)
   |-- (결제하기)
   |-- (주문 조회)

이 다이어그램에서 중요한 점은 다음과 같다.

유스케이스 다이어그램을 화면 흐름도나 기능 명세서처럼 사용하는 경우가 있는데, 이는 흔한 오해다. 유스케이스 다이어그램의 목적은 상세 설명이 아니라 합의다. 이 시스템이 어떤 책임을 가지는지에 대해 공통된 인식을 만드는 것이 핵심이다.

더 읽어보기

  • 2026.03.01

    함수, 펑터, 그리고 모나드

    복잡한 버그는 대개 거대한 기능이 아니라 사소한 데이터 변환 구간에서 시작된다. 문자열을 한 번 다듬고, 숫자를 한 번 바꾸고, 그 결과를 다음 단계로 넘기는 단순한 흐름이다. 그런데 조건이 조금씩 추가되는 순간 로직은 빠르게 복잡해진다. 값만 바꾸던 코드가 어느새 값의 부재, 비동기…

  • 2026.01.03

    CSS Color Functions

    이 포스트는 Sunkanmi Fafowora가 css-tricks에 올린 CSS Color Functions 게시글을 번역한 것이다. 번역하는 과정에서 다소 의역이 있을 수 있으며, 일부 번역에는 사견이 포함되어있기도 하다.몇 달 전 누군가 저에게 “웹사이트가 돋보이려면 무엇이 필요할까…

  • 2026.04.17

    Code Server

    처음 코드 서버를 만들었던 건 아마도 3년쯤 전의 일이다. 맥미니만 있던 탓에 밖에서 개발하는 게 쉽지 않았고, 아이패드로 언제 어디서든 개발을 하고 싶었던 끝에 찾아낸 해결책이었다. 다행히 집에는 Synology NAS가 있었고, Docker를 통해 어렵지 않게 코드 서버를 만들 수…

  • 2026.04.11

    Trie 자료구조

    문자열 데이터를 다룰 때 단순히 “이 단어가 있나?”만으로는 부족한 순간이 있다. 자동 완성처럼 특정 접두사로 시작하는 후보를 모아야 할 때도 있고, 어떤 키에 값을 두고 빠르게 찾고 싶을 때도 있다. 이럴 때 가장 자연스럽게 떠올릴 수 있는 자료구조가 바로 Trie이다.Trie는 무엇…

  • 2026.03.19

    Streams API 부록 2. 왜 이미지는 위에서 아래로 나타날까

    웹 페이지에서 이미지를 로드할 때 흥미로운 장면을 종종 볼 수 있다. 이미지가 한 번에 완전히 나타나는 것이 아니라, 위에서 아래로 조금씩 채워지면서 나타나는 경우가 있기 때문이다. 특히 네트워크가 느리거나 이미지가 큰 경우 이런 현상이 더 분명하게 보인다. 마치 이미지가 위쪽부터 스캔…

댓글

댓글을 불러오는 중...