PythonユーザーのためのPlantUML入門：シーケンス図と状態遷移図

# はじめに

**[PlantUML](https://plantuml.com/ja/)** は、シンプルなテキスト記述から各種UMLダイアグラムを生成できるオープンソースツールです。テキストベースで記述できるため設計内容をコード同様にバージョン管理しやすく、Gitでの管理とも相性が良い点が魅力です。特にPythonエンジニアにとっては、PlantUMLをPythonスクリプトから呼び出して図を自動生成することも可能で、シーケンス図やクラス図などを手軽に作成できます。本記事では、**シーケンス図**と**状態遷移図**（ステートマシン図）に焦点を当て、Pythonの考え方に対応づけながらPlantUMLの基本的な使い方を解説します。物理実験装置や衛星開発、観測機器のオペレーションといった場面で現れるシーケンスや状態遷移に使えるよう分かりやすく説明してみます

## 初めての方向け : まずはオンラインでやってみよう

初めての方は、下記のコードをコピーして、

``` :
@startuml

start
:User Submits Order;
if (Check Warehouse Stock?) then (In Stock)
    if (Process Payment) then (Payment Success)
        if (Dispatch Order) then (Dispatch Success)
            :Show Success;
        else (Dispatch Failed)
            :Show Error;
        endif
    else (Payment Failed)
        :Show Error;
    endif
else (No Stock)
    :Show Error;
endif

stop

@enduml
```

を、

https://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa700003

にある、plantuml のオンラインのインターフェースにコピペしてみてください。

次のような図を生成されるはずです。(qiita は plantuml というコード指定で可視化します。)


```plantuml:
@startuml

start
:User Submits Order;
if (Check Warehouse Stock?) then (In Stock)
    if (Process Payment) then (Payment Success)
        if (Dispatch Order) then (Dispatch Success)
            :Show Success;
        else (Dispatch Failed)
            :Show Error;
        endif
    else (Payment Failed)
        :Show Error;
    endif
else (No Stock)
    :Show Error;
endif

stop

@enduml
```



## PlantUML以外の選択肢

PlantUML以外にも似たようなツールがあるので、長所と短所を整理しておきます。

| ツール名     | URL                                | 長所                                           | 短所                                           |
|--------------|-------------------------------------|------------------------------------------------|------------------------------------------------|
| PlantUML     | https://plantuml.com/              | 多彩な図に対応、カスタマイズ性高い             | Java依存、構文がやや複雑                       |
| Mermaid      | https://mermaid-js.github.io       | Markdown埋め込み可、軽量、ブラウザ対応         | 表現力に制限あり、詳細制御が難しい             |
| draw.io      | https://www.diagrams.net/          | GUIで直感的、チーム共有に便利                  | ソースコード管理に不向き                        |
| Graphviz     | https://graphviz.org/              | グラフ構造やDAG(有向非巡回グラフ)可視化に強い                    | シーケンスや状態遷移図には不向き               |
| D2           | https://d2lang.com/                | 軽量、次世代的、Mermaidより表現力が高め         | 開発中でツールや環境が限定的                   |

ここでは、汎用性の高いPlantUMLについて紹介します。

# シーケンス図とは？

**シーケンス図**は、システム内のオブジェクトやコンポーネントなどの**参加者**（パーティシパント、エンティティ）が時間軸に沿ってどのように相互作用するか、一連の処理の流れをメッセージのやり取りとして表現する図です。オブジェクト間のメソッド呼び出しやデータの受け渡しなど、**「誰が」「誰に」「何を」** 実行するかを時系列で示すことで、処理手順やオブジェクト間の責務分担を視覚化できます。

開発時には「どのクラスがどの処理を担うか」「複数のモジュールがどの順番でやりとりするか」を整理するのに有用で、既存実装のトレースやユースケースの確認にも利用されます。Pythonの関数呼び出しやオブジェクトメソッドの呼び出しに馴染みのある読者であれば、シーケンス図は**プログラム内の関数コールフロー**を図式化したものと捉えると理解しやすいでしょう。

## PlantUMLでシーケンス図を描く

PlantUMLでは、シーケンス図をテキストで記述する際に以下のような基本構文を用います。

* **参加者（Participants）の定義:**
  シーケンス図に登場する主体を`participant`キーワードで定義します。人（アクター）を表す場合は`actor`キーワードを使うとシルエットが人型になり、それ以外のシステムや外部サービスは`participant`（デフォルトのボックス表示）で定義します。オブジェクト名に**別名**をつけたい場合は`as`を使ってエイリアスを指定できます。例えば、`actor ユーザ as User` のように書くと「ユーザ」という表示名のアクターを定義し、内部では`User`という別名で参照できます。

* **メッセージ（矢印）の記述:**
  矢印演算子`->`で**メッセージ送信**（メソッド呼び出しやデータ送信など）を表現します。左辺に送信元、右辺に宛先を書き、コロン`:`に続けてメッセージ名や説明を記述します。例えば、`A -> B : 実行要求` と書けば「AがBに対して『実行要求』というメッセージを送る」ことを表します。戻りメッセージや応答は実線の矢印の代わりに点線の矢印（`-->`）で描くこともできます（この場合、PlantUMLでは同期/非同期の表現として用いられますが、基本的な図では深く気にしなくても構いません）。メッセージ行はコメント（`'`から行末）を付けて補足説明することも可能です。

* **アクティブ期間（ライフライン）の明示:**
  `activate オブジェクト名` と `deactivate オブジェクト名` を使うと、あるオブジェクトが処理を実行している期間（ライフライン上の細長い長方形）を強調表示できます。例えば、`activate Server`～`deactivate Server`でサーバーオブジェクトの処理区間を図中にハイライトできます。これは「あるオブジェクトが処理中であること/応答待ちであること」を明示し、処理の開始・終了タイミングを表現するのに役立ちます。ただし、簡単な図では必須ではありませんので、必要に応じて使用すると良いでしょう。

以上の基本構文を踏まえて、実際にPlantUMLでシーケンス図を描いてみます。以下は「ユーザがPCに対して入力を行い、その結果がディスプレイに表示される」というシンプルな対話のシーケンス図の例です。

```
@startuml
actor ユーザ
participant PC
participant ディスプレイ

ユーザ -> PC : キー入力
PC -> ディスプレイ : 文字を表示
ディスプレイ -> ユーザ : 表示結果
@enduml
```

```plantuml
@startuml
actor ユーザ
participant PC
participant ディスプレイ

ユーザ -> PC : キー入力
PC -> ディスプレイ : 文字を表示
ディスプレイ -> ユーザ : 表示結果
@enduml
```

上のPlantUMLコードを、下記に貼り付けると、このようなシーケンス図が得られます(`qiita`では\`\`\`plantuml で記述すると画像で表示します)。

https://www.plantuml.com/plantuml/uml/SyfFKj2rKt3CoKnELR1Io4ZDoSa700003 

図では左に人型アイコンの「ユーザ」、中央に「PC」、右に「ディスプレイ」が配置され、それぞれ実線矢印でメッセージの流れが描画されています。例えば「ユーザ -> PC : キー入力」はユーザからPCへの入力操作を表現し、続く「PC -> ディスプレイ : 文字を表示」でPCがディスプレイに文字出力を行い、その結果を「ディスプレイ -> ユーザ : 表示結果」でユーザが目にする、といった一連の流れを示しています。

このように、シーケンス図を読むことで**処理の流れ**と**担当箇所**が一目で把握できます。特に、Pythonコードで書かれた関数呼び出しの連鎖やオブジェクト間メッセージのやり取りを視覚化するのに便利です。

### Python視点で見るシーケンス図

上記のシーケンス図の内容は、Pythonのオブジェクトや関数で擬似的に表現すると以下のようになります。

```python
class Display:
    def output(self, text):
        print(f"[ディスプレイ] {text}")

class PC:
    def __init__(self, display):
        self.display = display
    def receive_input(self, text):
        print(f"[PC] ユーザ入力を受信: {text}")
        # 入力を処理しディスプレイに出力
        self.display.output(text)

class User:
    def __init__(self, pc):
        self.pc = pc
    def type_input(self, text):
        print(f"[ユーザ] PCに入力: {text}")
        self.pc.receive_input(text)

# オブジェクトの準備
display = Display()
pc = PC(display)
user = User(pc)

# シーケンス実行のシミュレーション
user.type_input("Hello")  
# 出力例:
# [ユーザ] PCに入力: Hello
# [PC] ユーザ入力を受信: Hello
# [ディスプレイ] Hello
```

上のコードでは、`User.type_input`メソッドがPCに入力を送り（ユーザからPCへの矢印）、PC側で`receive_input`メソッドがその入力を受け取りディスプレイの`output`メソッドを呼び出しています（PCからディスプレイへの矢印）。ディスプレイの`output`では単純にテキストを表示するだけですが、これがシーケンス図中のディスプレイからユーザへの点線矢印（「表示結果」）に対応すると考えてください。実際のコードではディスプレイからユーザへ直接通知することはないものの、ユーザがディスプレイを見て結果を知るという受動的な関係を図ではメッセージとして表現しています。

このように、シーケンス図の各矢印は**メソッド呼び出し**や**関数の実行**に相当し、コード上の処理フローと対応しています。Pythonでクラス間のメソッド呼び出しを追っていくイメージでシーケンス図を描くと、プログラムの動的な振る舞いを整理しやすくなるでしょう。

# 状態遷移図とは？

次に**状態遷移図（ステートマシン図）**を見ていきます。状態遷移図は、システムやオブジェクトが取り得る**さまざまな状態**と、それらの間で起こり得る**遷移（状態の変化）**を視覚的に表現した図です。形式的には「有限状態マシン（Finite State Machine, FSM）」の考え方に基づいており、「**ある状態で特定のイベントが起こったら、別の状態（または同じ状態）に遷移する**」という振る舞いを記述します。各遷移にはしばしばトリガーとなる**イベント**や条件が付加され、システムが時間経過とイベント発生によってどのように状態を推移していくかを表します。

例えば、物理実験装置を考えてみましょう。装置には「待機中」「計測中」「エラー発生中」「停止」などの状態があり、ユーザが「計測開始ボタン」を押す、計測が完了する、異常が検出される、といったイベントによって状態が変化します。状態遷移図ではこれらを**丸や角丸四角の「状態」ノード**と\*\*矢印の「遷移」\*\*で表し、矢印には遷移を引き起こすイベント名をラベルとして記載します。こうした図を描くことで、システムのライフサイクル全体や異常系も含めた振る舞いを俯瞰できます。

## PlantUMLで状態遷移図を描く

PlantUMLで状態遷移図（ステート図）を記述する基本構文は以下の通りです。

* **状態の定義:**
  状態は`state`コマンドで定義します。例えば、単純に `state Idle` と書けば「Idle」という名前の状態が定義されます。状態名に空白や記号が含まれる場合や、図中に表示する名前と内部識別子を分けたい場合は、`state "表示名" as 別名` の形式で **表示名** と **別名（エイリアス）** を設定できます。別名をつけておけば、遷移の記述を簡潔にしたり、名前変更にも柔軟に対応できます。長い名前と別名が同じで良い場合は`as`以降を省略可能です（つまり前述の簡易な `state Idle` でOK）。

* **遷移（矢印）の記述:**
  状態間の遷移は、`状態A --> 状態B` のように矢印`-->`で二つの状態名（もしくは別名）を結んで表現します。矢印の上には必要に応じてイベント名や条件を `:` の後ろに記述できます。例えば `Locked --> Unlocked : コイン投入` と書けば、「Locked状態でコイン投入イベントが発生するとUnlocked状態に遷移する」ことを意味します。イベント名を省略すれば単なる状態遷移（常時または内部処理による遷移）を表せます。なお、同じ状態への自己遷移も `State --> State : Event` と記述できます。

* **開始状態・終了状態:**
  UML状態図には、特別な **開始状態**（開始ノード）と **終了状態**（終了ノード）が存在します。PlantUMLではどちらも `[*]` という記号で表現します。開始状態は図のエントリポイントで、通常はそこから最初の状態への矢印を描きます。同様に、終了状態は最終的な停止/完了を示すもので、ある状態から終了状態 `[*]` へ矢印を描くことで「システムが停止する」などの終端を表現できます（複数描いても構いません）。開始状態から最初の状態への遷移、および各状態から終了状態への遷移を適切に記述することで、状態図が完結します。

以上の構文を踏まえ、具体例として**ストップウォッチ**の状態遷移図をPlantUMLで描いてみましょう。ストップウォッチは「計測中」「一時停止（ポーズ）」「リセット/終了」といった状態を持ち、ユーザが押すボタンによって状態が変わる典型的な状態機械です。

```  
@startuml ストップウォッチ状態遷移
[*] --> 計測中 : Sボタン   ' 開始状態から計測中へ（スタートボタン）
計測中 --> 一時停止 : Sボタン   ' 計測中に再度スタートボタン（ポーズ）
一時停止 --> 計測中 : Sボタン   ' ポーズ中にスタートボタン（再開）
一時停止 --> [*] : Rボタン    ' ポーズ中にリセットボタン（終了）
@enduml
```


```plantuml
@startuml ストップウォッチ状態遷移
[*] --> 計測中 : Sボタン   ' 開始状態から計測中へ（スタートボタン）
計測中 --> 一時停止 : Sボタン   ' 計測中に再度スタートボタン（ポーズ）
一時停止 --> 計測中 : Sボタン   ' ポーズ中にスタートボタン（再開）
一時停止 --> [*] : Rボタン    ' ポーズ中にリセットボタン（終了）
@enduml
```

上図はストップウォッチの状態遷移を表したものです。最初、開始ノード`[*]`から「計測中」状態に遷移しています。これはストップウォッチが初期状態（待機状態）から、ユーザの\*\*Sボタン（スタートボタン）**操作によって計測を開始することを意味します。その後、計測中に再度Sボタンを押すと「一時停止」状態へ遷移し、さらにもう一度Sボタンを押すと「計測中」状態に戻っています。これは計測の一時停止と再開を表現しています。そして「一時停止」状態で **Rボタン（リセットボタン）** を押すと終了状態`[*]`（停止）へ遷移し、計測が完全に終了する流れになっています。

この状態遷移図により、ストップウォッチの挙動を網羅的に理解できます。どのボタン操作でどの状態に移るのか、一目瞭然です。また、例えば「計測中」にRボタンを押すケース（この図では描かれていない）など、**図にない遷移**が発生した場合は何も起こらない（入力無視）か、あるいは操作自体を無効化する、といった扱いになることも読み取れます（状態遷移図では表現しない部分ですが、コード設計時に検討が必要なポイントです）。

### Python視点で見る状態管理

続いて、このストップウォッチ状態遷移のロジックをPythonコード風に表現してみます。状態は文字列やEnumなどで管理し、ボタン押下イベントごとに状態を更新する実装です。

```python
class Stopwatch:
    def __init__(self):
        # 初期状態を「停止中(Reset)」とする
        self.state = "Reset"

    def press_s(self):
        # Sボタン押下時の状態遷移
        if self.state == "Reset":
            self.state = "Measuring"      # 停止→計測開始
        elif self.state == "Measuring":
            self.state = "Paused"         # 計測中→一時停止
        elif self.state == "Paused":
            self.state = "Measuring"      # 一時停止→再開（計測中）
        print(f"[Sボタン] 現在の状態: {self.state}")

    def press_r(self):
        # Rボタン押下時の状態遷移
        if self.state == "Paused":
            self.state = "Reset"          # 一時停止→リセット(停止)
        print(f"[Rボタン] 現在の状態: {self.state}")

# ストップウォッチ状態遷移のテスト
sw = Stopwatch()
sw.press_s()  # 初期停止状態 -> 計測中
sw.press_s()  # 計測中 -> 一時停止
sw.press_s()  # 一時停止 -> 計測中（再開）
sw.press_r()  # 計測中状態ではRボタン効かず（状態変化なし）
sw.press_s()  # 計測中 -> 一時停止
sw.press_r()  # 一時停止 -> 停止リセット
```

上記コードでは、`Stopwatch`クラスが内部に`self.state`を持ち、`press_s()`メソッドと`press_r()`メソッドがそれぞれSボタン・Rボタン押下時の状態遷移を実装しています。初期状態は「Reset」（停止中）で、`press_s()`が呼ばれると`Reset -> Measuring`に状態が変わります（計測開始）。続けてもう一度`press_s()`を呼ぶと`Measuring -> Paused`（一時停止）になり、さらに`press_s()`で`Paused -> Measuring`（再開）となります。`press_r()`は一時停止中（Paused）のときのみ`Reset`状態に遷移させ、それ以外（計測中など）では状態を変えないようにしています。この挙動は前述の状態遷移図と一致しています。

実行結果のログ（コメントで示した状態変化）からも、PlantUMLで描いた図の通りに状態が遷移していることが確認できます。なお、実際の実装では計測中にRボタンが押された場合の扱い（このコードでは無視しています）や、エラー状態の追加など、状態遷移図に描かれていないケースも検討する必要があります。しかし、状態遷移図があることで **「実装すべき基本遷移」と「無視すべきイベント」** が明確になり、抜け漏れの少ない堅牢な設計につながります。

※補足：Pythonにはこのような状態遷移を扱うための便利なライブラリ（例えば`transitions`）も存在します。これを使うと、状態と遷移を定義するだけで上記と同等のステートマシン動作を実現でき、さらにPlantUML形式の状態図を自動生成する機能も提供されています。興味がある方は下記の記事などを参照してください。

https://qiita.com/noca/items/a132bb5e1ad4bf4eff6a


# PlantUML文法の具体例と図別の書き方のまとめ
## **アクティビティ図（処理フローを描く）**

### 主な文法ルール

| 記法                                             | 意味    | 表示される図形 |
| ---------------------------------------------- | ----- | ------- |
| `start` / `stop`                               | 開始/終了 | ● → ●   |
| `:処理;`                                         | アクション | 長方形     |
| `if (...) then (...)` / `else (...)` / `endif` | 条件分岐  | ひし形     |
| `repeat` / `repeat while (...)`                | 繰り返し  | ループ構造   |

### 🔸 具体例：ログイン処理のフロー

``` bash:login.pu
@startuml
start

:ログイン画面を表示;
:ユーザーがIDとパスワードを入力;

if (認証成功？) then (yes)
  :ホーム画面を表示;
else (no)
  :エラーメッセージを表示;
endif

stop
@enduml
```


```plantuml
@startuml
start

:ログイン画面を表示;
:ユーザーがIDとパスワードを入力;

if (認証成功？) then (yes)
  :ホーム画面を表示;
else (no)
  :エラーメッセージを表示;
endif

stop
@enduml
```

---

## **シーケンス図（時系列のやり取り）**

### 主な文法ルール

| 記法                       | 意味          |
| ------------------------ | ----------- |
| `participant`, `actor`   | 登場人物またはシステム |
| `A -> B: メッセージ`          | 通常の呼び出し     |
| `A --> B: 応答`            | 戻り（非同期）     |
| `activate`, `deactivate` | ライフラインの強調   |

### 具体例：WebアプリのAPI呼び出し

``` bash:webapp.pu
@startuml
actor User
participant "Web App" as Web
participant "DB Server" as DB

User -> Web: GET /user/123
activate Web
Web -> DB: SELECT * FROM users
activate DB
DB --> Web: ユーザーデータ
deactivate DB
Web --> User: JSONレスポンス
deactivate Web
@enduml
```

```plantuml
@startuml
actor User
participant "Web App" as Web
participant "DB Server" as DB

User -> Web: GET /user/123
activate Web
Web -> DB: SELECT * FROM users
activate DB
DB --> Web: ユーザーデータ
deactivate DB
Web --> User: JSONレスポンス
deactivate Web
@enduml
```

---

## **クラス図（オブジェクトの構造）**

### 主な文法ルール

| 記法              | 意味                                |      |
| --------------- | --------------------------------- | ---- |
| `class クラス名`    | クラス定義                             |      |
| `+`, `-`, `#`   | アクセス修飾子（public/private/protected） |      |
| `extends` / \`< | --\`                              | 継承関係 |

### 具体例：動物と犬の継承

``` bash:dog.pu
@startuml
class Animal {
  +name: String
  +speak(): void
}

class Dog extends Animal {
  +breed: String
  +speak(): void
}

Animal <|-- Dog
@enduml
```


```plantuml
@startuml
class Animal {
  +name: String
  +speak(): void
}

class Dog extends Animal {
  +breed: String
  +speak(): void
}

Animal <|-- Dog
@enduml
```

---

## **ユースケース図（ユーザーと機能の関係）**

### 主な文法ルール

| 記法                  | 意味          |
| ------------------- | ----------- |
| `actor`             | ユーザーや外部システム |
| `usecase`           | 機能          |
| `actor --> usecase` | 利用関係        |

### 具体例：ショッピングサイト

``` bash:shop.pu
@startuml
actor 顧客
actor 管理者

usecase "商品を検索" as UC1
usecase "商品を購入" as UC2
usecase "商品を登録" as UC3

顧客 --> UC1
顧客 --> UC2
管理者 --> UC3
@enduml
```

```plantuml
@startuml
actor 顧客
actor 管理者

usecase "商品を検索" as UC1
usecase "商品を購入" as UC2
usecase "商品を登録" as UC3

顧客 --> UC1
顧客 --> UC2
管理者 --> UC3
@enduml
```

---

## **状態遷移図（状態の変化）**

``` bash:state.pu
@startuml
[*] --> 待機中
待機中 --> 通知受信 : 新しいメール
通知受信 --> 閲覧中 : ユーザーがタップ
閲覧中 --> 待機中 : 閉じる
@enduml
```

```plantuml
@startuml
[*] --> 待機中
待機中 --> 通知受信 : 新しいメール
通知受信 --> 閲覧中 : ユーザーがタップ
閲覧中 --> 待機中 : 閉じる
@enduml
```

---

## 🎨 カスタマイズ：色やレイアウトも指定可能

``` bash:color.pu
@startuml
class Animal {
  +name: String
  +speak(): void
}

class Dog extends Animal {
  +breed: String
  +speak(): void
}

Animal <|-- Dog

skinparam backgroundColor #F5F5DC
skinparam classAttributeIconSize 0
skinparam ArrowColor Blue
skinparam DefaultFontName "Helvetica"
@enduml
```



```plantuml
@startuml
class Animal {
  +name: String
  +speak(): void
}

class Dog extends Animal {
  +breed: String
  +speak(): void
}

Animal <|-- Dog

skinparam backgroundColor #F5F5DC
skinparam classAttributeIconSize 0
skinparam ArrowColor Blue
skinparam DefaultFontName "Helvetica"
@enduml
```

---

## よく使うオプションまとめ

| 設定                    | 内容             |
| --------------------- | -------------- |
| `skinparam`           | 見た目全体のカスタマイズ   |
| `note right/left of`  | 各要素にコメントをつける   |
| `group` や `rectangle` | 図中でグループ化・枠を付ける |

---

## 補足：PlantUMLの思想

* テキストで描く → Git管理しやすい
* 自動生成もできる（CIやドキュメント自動化）
* シンプルな構文で複雑な図も表現できる

機能のまとめ

* PlantUMLの構文はシンプルで直感的
* UMLの主要な図（アクティビティ・シーケンス・クラス・ユースケース）をすべてカバー
* GUIではなく「テキストで図を書く」ことで再利用性・履歴管理がしやすい

## おわりに

本記事では、Pythonに馴染みのあるエンジニア向けに **PlantUMLによるシーケンス図と状態遷移図の描き方** を解説しました。シーケンス図ではオブジェクト間のメッセージの流れを時間順に追い、状態遷移図ではシステムの状態変化を網羅的に整理できます。どちらも設計内容の理解を深め、ドキュメントとして残すのに非常に有用な手法です。