군만두의 IT 개발 일지

[스터디14] 07. UML을 활용한 소프트웨어 모델링 본문

학습일지/Java

[스터디14] 07. UML을 활용한 소프트웨어 모델링

mandus 2026. 7. 2. 16:29

목차

    9장. UML을 활용한 소프트웨어 모델링

    9-1 UML이란?

    • UML: 표준 표기법을 사용하여 소프트웨어 시스템의 구조와 동작을 시각적으로 모델링하고 문서화하는 언어

    UML의 4가지 특징

    • 가시화(Visualization): 눈에 보이는 그래프 형태로 작성하여 시스템의 구조와 동작을 한눈에 파악한다.
    • 명세화(Specification): 개발 과정마다 필요한 모델을 완전하고 정확하게 표현한다.
    • 구축화(Construction): 객체 지향 언어로 변환할 수 있어 모델을 바탕으로 실제 시스템을 구축한다.
    • 문서화(Documentation): 이해관계자 간의 평가와 의사소통을 위해 문서화를 지원한다.

    UML 다이어그램의 종류

    UML 다이어그램은 크게 구조 다이어그램, 행위 다이어그램, 상호 작용 다이어그램으로 구분한다.

    분류 설명 대표 다이어그램
    구조 다이어그램 시스템의 정적 구조와 구성 요소 간의 관계를 표현함 클래스, 컴포넌트, 객체, 복합 구조, 배포, 패키지 다이어그램
    행위 다이어그램 시간 흐름에 따른 객체 간의 상태 변화와 상호 작용을 표현함 액티비티, 유스 케이스, 상태 차트 다이어그램
    상호 작용 다이어그램 행위 다이어그램의 한 유형으로, 객체 간 상호 작용 중심의 데이터 전달과 흐름을 표현함 시퀀스, 커뮤니케이션, 인터랙션 오버뷰, 타이밍 다이어그램

    9-2 유스 케이스 다이어그램

    유스 케이스(use case)란 사용자가 시스템을 사용하는 시나리오를 문서화한 것으로, 기능적 요구 사항을 도출할 수 있다. 작성 수준에 따라 세 종류로 분류한다.

    • Brief(간략한 유스 케이스): 최초 작성 단계에서 사용하며, 2~3줄로 간략히 요약한다.
    • Casual(일반 유스 케이스): 메인 시나리오, 대체 시나리오, 예외 시나리오 등을 구분하여 작성한다.
    • Fully Dressed(상세 유스 케이스): 가장 상세한 유스 케이스로, 사전 조건(precondition)과 후속 동작(postcondition) 등을 추가로 명확히 정의한다.

    유스 케이스 작성법

    유스 케이스를 작성할 때는 유연한 스타일블랙박스 스타일을 적용하는 것이 중요하다.

    • 유연한 스타일: 구체적인 방법보다 사용자 관점의 시나리오에 집중하는 방식이다.
    • 블랙박스 스타일: 시스템의 내부 구현을 기술하지 않고 외부에서 보이는 기능에만 집중하는 방식이다.
    구분 좋은 예 나쁜 예
    유연한 스타일 Admin이 자신을 인증합니다. Admin이 키보드로 ID와 PW를 입력하여 인증합니다.
    블랙박스 스타일 상품 정보를 저장합니다. SQL DB에 INSERT INTO 쿼리로 상품 정보를 저장합니다.

    초기 단계에서 너무 구체적인 개발 수준으로 작성하면 이후 요구 사항 변경에 유연하게 대응하기 어렵고 개발자의 피로도가 증가할 수 있다. 따라서 사용자 관점에 집중한 유스 케이스를 먼저 작성하는 것이 바람직하다.

    유스 케이스 다이어그램과 구성 요소

    유스 케이스 다이어그램은 시스템, 액터, 유스 케이스, 관계 이렇게 4가지 요소로 구성된다.

    • 시스템(system): 유스 케이스를 둘러싼 사각형 영역이다. 외부에서 액터가 바라보는 시스템의 경계와 내부 동작을 하나의 영역으로 구분한다.
    • 액터(actor): 시스템 외부에서 시스템과 상호 작용하는 사용자 또는 시스템이다. 주 액터(primary actor)는 시스템을 주로 사용하는 사용자를, 보조 액터(secondary actor)는 기능을 지원하는 외부 요소를 나타낸다.
    • 유스 케이스(use case): 사용자가 시스템을 통해 수행할 수 있는 기능을 타원형으로 표현한다.
    • 관계(relation): 액터와 유스 케이스, 그리고 유스 케이스 간의 연관성을 나타낸다.

    ▲ 계정 관리 시스템 유스 케이스 다이어그램

    관계는 포함 관계, 연관 관계, 확장 관계, 일반화 관계로 나눌 수 있다.

    종류 설명
    포함 관계 특정 유스 케이스를 실행할 때 반드시 선행해야 하는 유스 케이스를 나타냄 (include)
    연관 관계 액터와 유스 케이스 간에 상호 작용하고 있음을 나타냄
    확장 관계 기본 유스 케이스를 정상 수행한 후, 조건에 따라 부가 기능을 추가하는 경우에 사용함 (extend)
    일반화 관계 추상적인 유스 케이스를 구체적인 유스 케이스로 세분화함. 하위 유스 케이스는 상위 유스 케이스의 공통 동작을 상속받음

    9-3 클래스 다이어그램

    클래스 다이어그램을 이해하려면 먼저 객체 지향 분석과 설계(OOAD)를 알아야 한다.

    • 객체 지향 분석(OOA): 문제를 정의하고 모델을 제작하여 객체 간의 관계와 동작을 식별하는 단계
    • 객체 지향 설계(OOD): 도출한 모델을 기반으로 객체 속성, 동작, 상호 작용을 구체적으로 설계하는 단계
    • 클래스 다이어그램은 OOA 단계에서는 도메인 모델로, OOD 단계에서는 디자인 모델로 활용된다.

    객체와 클래스의 구성 요소와 표현 방법

    • 객체(object): 이름의 첫 글자를 소문자로 표기하고 속성과 현재 값을 명시한다.
    • 클래스(class): 첫 글자를 대문자로 표기하고 속성의 구체적인 값 대신 자료형을 표기한다. 또한 오퍼레이션(operation)을 명확하게 기술한다는 점에서 객체와 차이가 있다.

    속성과 오퍼레이션에는 접근 가능 영역을 지정하는 접근 제어자를 붙일 수 있다. 명시하지 않으면 기본적으로 private이 지정된다.

    접근 제어자 표시 접근 가능 영역
    public + 모든 영역
    private - 클래스 내부
    protected # 클래스 내부와 하위 클래스
    • / 기호: 접근 제어자가 아니라 다른 속성이나 연산 결과에 의해 자동 계산되는 파생 속성을 나타낸다.
    • UML에서는 오퍼레이션과 메서드를 구분한다. 오퍼레이션은 실제 구현 코드가 없는 상태를 의미하며, 다이어그램에 표현되는 것은 메서드가 아니라 오퍼레이션이다.
    • 클래스 변수(class variable): 클래스 자체에 속하는 속성이다. static 예약어를 사용하며 다이어그램에서는 밑줄로 표현한다.

    클래스 간의 관계 표현

    클래스 간의 관계는 관계 강도가 약한 것부터 강한 것 순으로 의존 → 연관 → 집합 → 합성 → 실체화 → 일반화 관계로 표현한다.

     

    의존 관계(dependency)

     

    한 클래스가 다른 클래스를 지역 변수, 매개변수, 반환값 등으로 참조하는 것이며, 점선 화살표로 표현한다. 메서드를 수행하는 동안에만 두 클래스의 생애 주기가 함께 유지된다.

    public class Person {
        int age;
        int weight;
        // Food를 매개변수로만 사용하므로 의존 관계
        void eat(Food food) {
            weight += food.getCalorie() / 100;
        }
    }
    
    class Food {
        int calorie;
        int getCalorie() {
            return calorie;
        }
    }

    연관 관계(association)

     

    참조하는 클래스를 멤버 변수로 할당하여 두 클래스의 생애 주기를 함께한다는 점에서 의존 관계와 다르다. 연관 관계에서는 방향성다중성을 명확하게 이해하는 것이 중요하다. 화살표가 없으면 양방향 참조, 있으면 단방향 참조를 의미한다.

    • 방향성: 연관 관계에서 클래스 간의 참조 방향
    • 다중성: 클래스 간의 연관 관계에서 객체의 수
    표기 형식 의미
    1 1
    * 0 또는 그 이상 (0…*과 동일한 의미)
    1…* 1 또는 그 이상
    0…1 0 또는 1
    A…B A에서부터 B 사이의 값
    A,B A 또는 B
    // Student(1) : Email(0…*) → 1:N 연관 관계
    public class Student {
        private List<Email> emailList;
    }
    class Email {
        String address;
        String domain;
        String pw;
        Date createDt;
    }

    집합 관계(aggregation)

     

    클래스 간의 전체와 부분 관계를 나타내며, 전체 객체와 부분 객체의 생애 주기가 서로 독립적이라는 특징이 있다. 전체 객체가 소멸되더라도 부분 객체는 독립적으로 유지될 수 있다. 다이어그램에서 빈 마름모로 표현한다.

    public class Lecture {
        private List<Student> studentList;
        private LectureRoom lectureRoom;
        private Professor professor;
    
        // 외부에서 부분 객체를 받아오므로 Lecture 클래스가 소멸되어도 부분 객체는 유지됨
        public Lecture(List<Student> studentList,
                       LectureRoom lectureRoom, Professor professor) {
            this.studentList = studentList;
            this.lectureRoom = lectureRoom;
            this.professor = professor;
        }
    }

    합성 관계(composition)

     

    집합 관계와 유사하지만, 전체 객체가 소멸되면 부분 객체들도 함께 소멸된다는 점에서 차이가 있다. 부분 객체는 전체 객체의 생애 주기에 완전히 종속된다. 다이어그램에서 채워진 마름모로 표현한다.

    public class Lecture2 {
        private List<Student> studentList;
        private LectureRoom lectureRoom;
        private Professor professor;
    
        // 객체 생성이 클래스 내부에서 이루어지므로 부분 객체가 전체 객체의 생애 주기에 종속됨
        public Lecture2() {
            this.studentList = new ArrayList<>();
            this.lectureRoom = new LectureRoom();
            this.professor = new Professor();
        }
    }

    실체화 관계(realization)

     

    인터페이스와 이를 실제로 구현한 클래스 간의 관계를 나타낸다. '나는 인터페이스에 정의된 기능을 수행할 수 있다'는 의미로 해석한다.

    interface Flyable {
        public void fly();
    }
    
    public class Bird implements Flyable {
        @Override
        public void fly() {
            System.out.println("날개를 이용하여 날아갑니다.");
        }
    }

    일반화 관계(inheritance)

     

    IS-A 관계라고도 하며, 한 클래스가 다른 클래스를 포함하는 상위 개념일 때 사용한다. 객체 지향 프로그래밍에서는 상속 관계라고도 한다.

    public abstract class User {
        private String id;
        private String pw;
        public abstract void login();
    }
    
    class NormalUser extends User {
        @Override
        public void login() {
            System.out.println("일반 사용자 로그인");
        }
    }
    
    class Admin extends User {
        @Override
        public void login() {
            System.out.println("관리자 로그인");
        }
    }

     

    9-4 시퀀스 다이어그램

    시퀀스 다이어그램(sequence diagram)은 시간의 흐름에 따라 객체 간의 상호 작용을 나타내는 가장 널리 사용하는 상호 작용 다이어그램이다. API 호출 흐름이나 유스 케이스 시나리오를 파악할 수 있다.

    시퀀스 다이어그램의 구성 요소

    • 객체(object): 행동 주체를 나타내며, 직사각형으로 표현한다.
    • 생명선(lifeline): 객체의 수명을 점선으로 나타내며, 아래로 갈수록 시간 경과를 의미한다.
    • 활성 박스(activation box): 생명선 위에 긴 직사각형으로 표시하며, 해당 객체가 현재 특정 활동을 수행하고 있음을 나타낸다.
    • 메시지: 객체 간에 주고받는 데이터로, 요청과 응답을 표현한다.
    메시지 유형 설명
    동기(sync) 메시지 요청 결과 응답이 올 때까지 기다림. 실선과 꽉 찬 화살표로 표현하며, 일반 함수 호출과 유사함
    비동기(async) 메시지 응답을 기다리지 않고 다른 작업을 수행함. 실선과 빈 화살표로 표현함
    자체(self) 메시지 객체가 자체적으로 내부 작업을 처리할 때 사용하며, 자신의 생명선을 따라 회귀하는 화살표로 나타냄
    반환(return/reply) 메시지 요청 결과를 반환할 때 사용함. 점선과 빈 화살표로 표현함

    시퀀스 다이어그램의 흐름 제어

    프로그래밍의 조건문이나 반복문처럼 흐름을 제어하기 위해 가드(guard)시퀀스 프래그먼트(sequence fragment)를 사용한다.

    • 가드: 메시지 앞쪽에 대괄호 [ ]로 조건을 명시하여, 조건을 만족할 때만 메시지가 전달되도록 제어한다.
    • 시퀀스 프래그먼트: 여러 생명선과 활성 박스를 포함하는 박스 형태로 표현되며 반복, 조건, 분기 등의 흐름을 제어한다.
    종류 표기 역할
    Alternative alt if~else 문처럼 조건 만족 여부에 따라 분기함
    Option opt if 문처럼 특정 조건에 만족하는 경우에만 동작함
    Loop loop 반복문 역할. loop(최솟값, 최댓값) 형식으로 표기함
    Break break break 문처럼 조건 만족 시 해당 시퀀스를 종료하고 빠져나옴
    Parallel par 스레드처럼 프로세스의 병렬 처리를 의미함

    Loop는 다음과 같이 다양하게 표현할 수 있으며, 등호(=)를 기준으로 좌우 표현이 동일함을 의미한다.

    loop = loop(*) = loop(0, *)
    loop(5, 5) = loop(5)
    loop(1, 10) = loop(1 .. 10)

     

    9-5 상태 차트 다이어그램

    상태 차트 다이어그램(state chart diagram)은 행위 다이어그램에 속하며, 객체의 생애 주기 동안 발생하는 상태 변화를 시간 순서대로 나타낸다. 주요 구성 요소는 상태전이다.

    상태 차트 다이어그램의 구성 요소

    • 상태(state): 객체가 가질 수 있는 조건이나 상황을 나타내며, 생애 주기 동안 변화한다. 상태를 상세형으로 표기할 때 다음 활동을 함께 작성하면 상태 변화에 따른 동작을 명확하게 나타낼 수 있다.
      • entry/Activity(): 객체가 특정 상태에 진입할 때 실행하는 활동
      • do/Activity(): 객체가 특정 상태에 머무르는 동안 수행하는 활동
      • exit/Activity(): 객체가 특정 상태에서 벗어날 때 실행하는 활동
    • 전이(transition):는 하나의 상태에서 다른 상태로 변화하는 과정을 나타낸다. 원래 상태(source state), 목표 상태(target state), 이벤트(event), 조건(guard), 동작(action)으로 구성된다.

    상태 차트 다이어그램의 다양한 상태

    상태 설명
    복합(composite) 상태 하나의 상태 내에 계층 구조를 포함함(OR 상태). 여러 하위 상태 중 반드시 하나만 활성화되어야 함
    동시(orthogonal) 상태 하나의 복합 상태가 2개 이상의 지역(region)으로 분할된 구조(AND 상태). 진입 시 모든 지역이 동시에 활성화됨
    서브머신(SubMachine) 상태 하위 상태 다이어그램을 포함한 상태(안경 모양). 복잡한 상태를 더 작은 하위 차트로 분할함
    기록(history) 상태 이전에 진행했던 상태를 기억하여 필요할 때 해당 상태로 복귀함

    기록 상태는 표기법에 따라 두 가지로 구분한다.

    • shallow history state (H): 동일한 계층의 시작 노드로 이동한다.
    • deep history state (H*): 계층에 관계없이 마지막으로 활성화됐던 substate로 이동한다.

    각 상태에 대해 들어오는 전이와 나가는 전이를 모두 정의해야 한다. 들어오는 전이만 있고 나가는 전이가 없으면 종료 상태에 도달하지 못해 무한 루프에 빠지는데, 이러한 상태를 블랙홀 상태(Black Hole State)라고 한다.

    9-6 액티비티 다이어그램

    액티비티 다이어그램(activity diagram)은 시스템이나 메서드, 함수의 동작 흐름을 보여 준다. 데이터의 상태보다 시스템의 작업 흐름을 시각적으로 나타내는 데 중점을 둔다.

    액티비티 다이어그램의 구성 요소

    • 활동(activity): 단계별로 실행되는 동작이며, 둥근 사각형으로 표현한다.
    • 이동(transition): 두 활동 사이의 흐름이며, 화살표가 있는 실선으로 표시한다.
    • 시작점(start state): 검은 원으로 표현하며 다이어그램의 시작을 나타낸다.
    • 분기점(decision point): 마름모로 표현하며, 조건(guard)에 따라 흐름이 여러 경로로 분기된다.
    • 종료점(final state): 하얀 원 안에 검은 점으로 표현하며, 도달 시 다이어그램이 종료된다.
    • 객체(object)와 객체 흐름(object flow): 객체는 사각형으로, 객체 흐름은 점선 화살표로 표현한다.
    • 포크 노드(fork node)와 조인 노드(join node): 포크 노드는 프로세스가 병렬로 수행되도록 하나의 흐름을 여러 흐름으로 나누는 역할을 하고, 조인 노드는 분할된 병렬 흐름을 다시 하나로 합친다. 조인 노드 이후의 동작은 받아야 할 모든 흐름을 완료한 후에 시작된다.

    스윔 레인

    스윔 레인(swimlane)은 객체 간의 역할 분리를 나타내며, 가로 또는 세로로 배치할 수 있다. 각 활동의 주체가 사용자(user)인지 시스템(system)인지를 한눈에 파악할 수 있어 시스템의 흐름을 효과적으로 분석할 수 있다.

    액티비티 다이어그램과 상태 차트 다이어그램의 비교

    항목 액티비티 다이어그램 상태 차트 다이어그램
    중요 표현 객체 간의 동작 흐름을 표현 객체의 상태와 상황 표현
    이동 방식 각 활동의 완료에 따라 노드 간 이동 이벤트 작업 결과에 따라 이동

    9-7 컴포넌트 다이어그램

    컴포넌트 다이어그램(component diagram)은 컴포넌트 간의 관계와 구성을 표현한다. 시스템이 어떻게 모듈화되는지 컴포넌트끼리 어떻게 연결되고 인터페이스에서 상호 작용하는지를 파악할 수 있다.

    컴포넌트 다이어그램의 구성 요소

    • 컴포넌트(component): 코드로 개발되는 독립된 단위이며, 여러 클래스의 집합이다. 탭이 달린 직사각형으로 표현한다.
    • 포트(port): 컴포넌트와 외부 세계 간의 접점을 하나로 묶어 표현할 때 사용하며, 작은 사각형으로 표현한다.
    • 의존 관계(dependency): 한 컴포넌트가 다른 컴포넌트를 참조하거나 의존함을 점선 화살표로 나타낸다.
    • 아웃풋 인터페이스(output interface): 외부로 제공하는 서비스나 데이터이며, 흰 원으로 표현한다.
    • 인풋 인터페이스(input interface): 외부에서 공급받는 서비스나 데이터이며, 빈 반원으로 표현한다.

    컴포넌트 다이어그램의 표현 방법

    방식 설명
    볼과 소켓 기호(ball and socket symbols) 가장 많이 사용한다. 아웃풋은 흰 원, 인풋은 반원으로 표현한다.
    스테레오타입(stereotype natation) 인풋은 의존 관계, 아웃풋은 실체화 관계로 정의하며 각 인터페이스를 명시적으로 작성한다.
    텍스트 목록(text listing) 인터페이스를 컴포넌트 내부에 텍스트 목록 형태로 작성한다.

    어셈블리 커넥터와 대리자 커넥터

    • 어셈블리 커넥터(assembly connector): 시스템 내 컴포넌트 간의 연결을 나타낸다.
    • 대리자 커넥터(delegation connector): 외부 컴포넌트와 컴포넌트 내부의 구성 요소를 연결할 때 사용한다. 외부에서 발생한 요청이나 이벤트를 컴포넌트 내부의 적절한 영역으로 전달하고, 그 결과를 외부로 전달한다.

    이 글은 『 Do it! 클린 프로그래밍 』 책을 학습한 내용을 정리한 것입니다.

     

    Comments