MidТеория9 min

UML

Class diagram, sequence diagram, component diagram, activity diagram и применение UML в проектировании

UML (Unified Modeling Language)

Что такое UML

UML -- стандартизированная нотация для визуального моделирования программных систем. Разработана в 1990-х, стандарт OMG. Включает 14 типов диаграмм, но на практике используются 4-5 основных.

Какие диаграммы реально нужны

Диаграмма Когда Частота использования
Class Diagram Структура домена, ООП дизайн Высокая
Sequence Diagram Взаимодействие компонентов Высокая
Component Diagram Архитектура модулей Средняя
Activity Diagram Бизнес-процессы, алгоритмы Средняя
State Machine Состояния объекта Низкая
Use Case Diagram Функциональные требования Низкая

Class Diagram

Class diagram показывает классы, их атрибуты, методы и связи.

Элементы

Элемент Символ Описание
Class Прямоугольник (3 секции) Имя, атрибуты, методы
Interface <<interface>> Контракт без реализации
Abstract class Курсив или {abstract} Частичная реализация
Enum <<enum>> Перечисление

Модификаторы доступа

Символ Доступ
+ public
- private
# protected
~ package (internal)

Связи между классами

Связь Символ Описание Пример
Association ── Знает о / использует Order знает о Customer
Dependency - -> Зависит от Service зависит от Logger
Aggregation ◇── Содержит (weak) Team содержит Players
Composition ◆── Владеет (strong) Order владеет OrderItems
Inheritance ──▷ Наследует Admin наследует User
Implementation - -▷ Реализует interface UserRepo реализует Repository

Пример: Class Diagram для Order System

┌───────────────────────┐     ┌────────────────────┐
│    <<interface>>       │     │    <<enum>>         │
│    OrderRepository     │     │    OrderStatus      │
├───────────────────────┤     ├────────────────────┤
│ + findById(id): ?Order │     │ Pending            │
│ + save(order): void    │     │ Confirmed          │
│ + delete(id): void     │     │ Shipped            │
└───────────┬───────────┘     │ Delivered          │
            │ implements       │ Cancelled          │
            │                  └────────────────────┘
┌───────────┴───────────┐
│  DoctrineOrderRepo    │
├───────────────────────┤           ┌──────────────────┐
│ - connection: Conn    │           │   Order           │
├───────────────────────┤     ◆─────├──────────────────┤
│ + findById(id): ?Order│           │ - id: string      │
│ + save(order): void   │           │ - status: Status  │
│ + delete(id): void    │           │ - total: Money     │
└───────────────────────┘           │ - createdAt: DT    │
                                    ├──────────────────┤
                                    │ + addItem(): void │
                                    │ + cancel(): void  │
                                    └────────┬─────────┘
                                             │ ◆ composition
                                    ┌────────┴─────────┐
                                    │   OrderItem       │
                                    ├──────────────────┤
                                    │ - product: string │
                                    │ - quantity: int   │
                                    │ - price: Money    │
                                    └──────────────────┘

Код, соответствующий диаграмме

<?php

declare(strict_types=1);

namespace App\Domain\Order;

interface OrderRepository
{
    public function findById(string $id): ?Order;
    public function save(Order $order): void;
    public function delete(string $id): void;
}

enum OrderStatus: string
{
    case Pending = 'pending';
    case Confirmed = 'confirmed';
    case Shipped = 'shipped';
    case Delivered = 'delivered';
    case Cancelled = 'cancelled';
}

final class Order
{
    /** @var array<OrderItem> */
    private array $items = [];

    public function __construct(
        private readonly string $id,
        private OrderStatus $status,
        private Money $total,
        private readonly \DateTimeImmutable $createdAt,
    ) {}

    public function addItem(OrderItem $item): void
    {
        $this->items[] = $item;
        $this->recalculateTotal();
    }

    public function cancel(): void
    {
        if ($this->status === OrderStatus::Shipped) {
            throw new \DomainException('Cannot cancel shipped order');
        }

        $this->status = OrderStatus::Cancelled;
    }

    private function recalculateTotal(): void
    {
        $sum = 0;
        foreach ($this->items as $item) {
            $sum += $item->getSubtotal();
        }
        $this->total = new Money($sum);
    }
}

final readonly class OrderItem
{
    public function __construct(
        private string $product,
        private int $quantity,
        private Money $price,
    ) {}

    public function getSubtotal(): int
    {
        return $this->price->getAmount() * $this->quantity;
    }
}
## Sequence Diagram

Sequence diagram показывает взаимодействие объектов во времени (кто кого вызывает и в каком порядке).

Элементы

Элемент Описание
Participant Объект/сервис (вертикальная линия)
Message Стрелка между участниками (вызов)
Response Пунктирная стрелка (возврат)
Activation Прямоугольник на lifeline (выполнение)
Alt/Opt/Loop Фрагменты (условия, циклы)

Пример: Order Creation Flow

Client          API Gateway      Order Service    Payment Service    DB
  │                 │                │                  │            │
  │── POST /orders ─▶                │                  │            │
  │                 │── createOrder ──▶                  │            │
  │                 │                │── validate() ────▶│            │
  │                 │                │◀─── valid ────────│            │
  │                 │                │                  │            │
  │                 │                │──── save() ──────────────────▶│
  │                 │                │◀─── saved ──────────────────│
  │                 │                │                  │            │
  │                 │                │── processPayment ▶            │
  │                 │                │                  │── charge() │
  │                 │                │◀── paymentResult ─│            │
  │                 │                │                  │            │
  │                 │   ┌─alt─[payment success]──────────────────┐  │
  │                 │   │      │── updateStatus("confirmed") ──▶│  │
  │                 │◀──│──── order ─│                  │            │
  │                 │   ├─[payment failed]───────────────────────┤  │
  │                 │   │      │── updateStatus("failed") ─────▶│  │
  │                 │◀──│──── error ─│                  │            │
  │                 │   └───────────────────────────────────────┘  │
  │◀── response ────│                │                  │            │
  │                 │                │                  │            │

Component Diagram

Component diagram показывает модули системы и их зависимости.

┌────────────────────────────────────────────────┐
│              Web Application                    │
│                                                │
│  ┌────────────┐    ┌────────────┐              │
│  │ Controller │───▶│  Service   │              │
│  │   Layer    │    │   Layer    │              │
│  └────────────┘    └─────┬──────┘              │
│                          │                      │
│                    ┌─────┴──────┐               │
│                    │ Repository │               │
│                    │   Layer    │               │
│                    └─────┬──────┘               │
│                          │                      │
└──────────────────────────┼──────────────────────┘
                           │
                    ┌──────┴──────┐
                    │  Database   │
                    │ PostgreSQL  │
                    └─────────────┘

Activity Diagram

Activity diagram показывает поток выполнения (workflow), включая параллельное выполнение и ветвления.

Элементы

Элемент Символ Описание
Start Заполненный круг Начало процесса
End Круг с обводкой Конец процесса
Action Прямоугольник (скруглённый) Действие
Decision Ромб Ветвление
Fork/Join Жирная полоса Параллельное выполнение
Swimlane Вертикальная/горизонтальная полоса Ответственный

Пример: Order Processing

                (●) Start
                 │
          ┌──────┴──────┐
          │ Receive Order│
          └──────┬──────┘
                 │
          ┌──────◇──────┐
          │  In Stock?  │
        Yes│            │No
          │             │
    ┌─────┴────┐  ┌─────┴──────┐
    │  Reserve │  │ Notify     │
    │  Stock   │  │ Out of     │
    │          │  │ Stock      │
    └─────┬────┘  └─────┬──────┘
          │             │
    ══════╤═════        (●) End
    Fork  │
    ┌─────┴─────┐
    │           │
┌───┴───┐ ┌────┴────┐
│Process│ │ Send    │
│Payment│ │ Email   │
└───┬───┘ └────┬────┘
    │          │
    ══════╧═════
    Join  │
          │
    ┌─────┴─────┐
    │ Ship Order│
    └─────┬─────┘
          │
         (●) End

State Machine Diagram

State Machine показывает состояния объекта и переходы между ними.

<?php

declare(strict_types=1);

namespace App\Domain\Order;

/**
 * Order state machine:
 *
 *  (●) ──▶ [Pending] ──confirm()──▶ [Confirmed]
 *                │                       │
 *           cancel()               ship()
 *                │                       │
 *                ▼                       ▼
 *          [Cancelled]             [Shipped]
 *                                       │
 *                                  deliver()
 *                                       │
 *                                       ▼
 *                                 [Delivered]
 */
final class OrderStateMachine
{
    private const TRANSITIONS = [
        'pending' => ['confirm' => 'confirmed', 'cancel' => 'cancelled'],
        'confirmed' => ['ship' => 'shipped', 'cancel' => 'cancelled'],
        'shipped' => ['deliver' => 'delivered'],
        'delivered' => [],
        'cancelled' => [],
    ];

    public function transition(OrderStatus $current, string $action): OrderStatus
    {
        $allowed = self::TRANSITIONS[$current->value] ?? [];

        if (!isset($allowed[$action])) {
            throw new \DomainException(
                sprintf('Cannot perform "%s" on order in "%s" status', $action, $current->value),
            );
        }

        return OrderStatus::from($allowed[$action]);
    }

    /**
     * Get available actions for current state.
     *
     * @return array<string>
     */
    public function availableActions(OrderStatus $current): array
    {
        return array_keys(self::TRANSITIONS[$current->value] ?? []);
    }
}
## PlantUML примеры

Sequence Diagram в PlantUML

@startuml
participant Client
participant "API Gateway" as GW
participant "Order Service" as OS
participant "Payment Service" as PS
database "PostgreSQL" as DB

Client -> GW: POST /orders
GW -> OS: createOrder()
OS -> DB: INSERT order
DB --> OS: ok

OS -> PS: processPayment()
PS --> OS: paymentResult

alt success
    OS -> DB: UPDATE status = confirmed
    OS --> GW: Order (201)
else failure
    OS -> DB: UPDATE status = failed
    OS --> GW: Error (402)
end

GW --> Client: Response
@enduml

Практические советы

Совет Описание
Не моделируйте всё Только ключевые части системы
Начинайте с Sequence Самая полезная диаграмма для обсуждений
Class Diagram = домен Моделируйте domain, не infrastructure
Diagram as Code PlantUML/Mermaid для версионирования
Обновляйте Устаревшая диаграмма вводит в заблуждение

Правило: UML -- инструмент коммуникации, а не документации. Рисуйте диаграммы для обсуждения и принятия решений, а не для отчётности.

Итоги

Диаграмма Показывает Когда использовать
Class Структура домена Проектирование ООП, domain model
Sequence Взаимодействие во времени API design, integration flows
Component Модули и зависимости Архитектура приложения
Activity Поток выполнения Бизнес-процессы, алгоритмы
State Machine Состояния и переходы Workflow, order lifecycle