沈思黙考：PlantUML(状態図)の書き方を考察する

## 初めに

PlantUMLは様々なUML図を簡単な書式を用いて生成する便利なツールです。
すごく便利ではあるのですが、ちょっと癖があるツールで、本格的に使うのを
ためらう方も多いのではないかと思います。
特に詳細に書かれた遷移図をメンテできるのか、という点が心配ではないかと思います。
しかし、統一した書き方を行えば、十分本格的に使えるはずと思います。
ここでは、本格的に使うためのおすすめの書き方の手順を示したいと思います。
この手順を参考にして、ぜひPlantUMLを使いこんでください。

## お勧めの書き方の手順紹介

具体的な作図を通して、お勧めの書き方を紹介します。

状態図では、状態と遷移を記述します。
状態図は、状態遷移図ともいうだけあって、遷移を書きたい気持ちはよくわかりますが、
まずは、状態を列挙しましょう。

### 状態の定義

状態を示すのは、stateコマンドで、以下のように書きます。
```
state "長い名前" as 別名
```

長い名前と別名が一致する場合は、「"長い名前" as」の部分を省略できます。
```
state 別名
```
この書式を利用して、まずは、「state 別名」の形で状態の候補を羅列しましょう。
長い名前に変更したくなった時に、「state "長い名前" as 別名」に変更します。

### 状態を列挙する

以下は携帯電話の状態の例です。
発信中、や着信中を加えてもよいでしょう。
とにかく状態を列挙しましょう。
```
state 電源OFF
state 電源ON
state 待機
state 通話中
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/d6547586-1c5a-f906-c477-e8df63ee69dd.png)


次に状態をグルーピングしましょう。PlantUMLでは合成といい、グループ化する状態を{}でくくります。
{}はネストすることができます。
合成が上手にできると、表現力がぐっと上がり、意味が伝えやすくなります。
```
state 電源OFF
state 電源ON {
 state 待機
 state 通話中
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/aae7e461-f5b0-8692-5958-ddd4a455e688.png)

### 遷移の定義

ここまで「設計」ができたら、遷移を加えます。
遷移は、-->で別名を繋げます。
```
別名1 --> 別名2
```

### 開始点と終了点

状態には、事前に定義された開始点と終了点という特別な状態があります。
どちらも[\*]と表現します。
まずは、開始点からと終了点への遷移を加えます。
```
state 電源OFF
state 電源ON {
 state 待機
 state 通話中
}
[*] --> 電源OFF
電源OFF --> [*]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/7bac90b1-1408-8893-4262-2d909e3890d4.png)

### 合成を枠と考える

次に電源が入ると待機になる遷移を考えます。
この考え方は、電源ONを枠を定義しているだけのもと、捉える考え方で、
電源ONへの遷移は考えません。

```
state 電源OFF
state 電源ON {
 state 待機
 state 通話中
}
[*] --> 電源OFF
電源OFF --> [*]
電源OFF --> 待機
待機 --> 電源OFF
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/83da2d48-9715-4197-4492-b179bcf3f64d.png)

では、残りの遷移(通話中->待機,待機->通話中)を記入していきましょう。
遷移は、合成の内側の状態かどうかにかかわらず、すべての状態の後
にまとめて記載します。
```
'状態
state 電源OFF
state 電源ON {
 state 待機
 state 通話中
}
'遷移
[*] --> 電源OFF
電源OFF --> [*]
電源OFF --> 待機
通話中 --> 待機
待機 --> 通話中
'注釈
note bottom of 電源ON : 枠を表現している
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/2cdb06f9-2926-cf67-5708-d48f543342ef.png)

### 合成に遷移する

電源が入ると電源ONになる、と考えることもできます。
この場合は、電源OFFから合成(電源ON)に遷移します。
```
state 電源OFF
state 電源ON {
 state 待機
 state 通話中
}
[*] --> 電源OFF
電源OFF --> [*]
電源OFF --> 電源ON
電源ON --> 電源OFF
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/48f067e7-ed80-6e9c-4f4c-4399b9e8d160.png)



この書き方の場合は、電源ONの中の遷移は、電源ONの中の状態間でのみ、遷移するようにします。
(電源ONの外の状態と遷移すると図が汚くなります)

そこで、電源ONの中に開始点と終了点を設けるようにします。
ここでは、開始点から待機への遷移と待機から終了点への遷移を追加します。

```
state 電源OFF
state 電源ON {
 state 待機
 state 通話中
 [*] --> 待機
 待機 --> [*]
}
[*] --> 電源OFF
電源OFF --> 電源ON
電源OFF --> [*]
電源ON --> 電源OFF
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/9be18f10-0017-2ec7-0349-6dbf0e86b5a9.png)



では、残りの遷移を記入していきましょう。
待機、通話中は、電源ONの中の状態なので、電源ONの合成の中に記載します。
```
'状態
state 電源OFF
state 電源ON {
 state 待機
 state 通話中
 [*] --> 待機
 待機 --> [*]
 待機 --> 通話中
 通話中 --> 待機
}
'遷移
[*] --> 電源OFF
電源OFF --> 電源ON
電源OFF --> [*]
電源ON --> 電源OFF
'注釈
note bottom of 電源ON : 合成の中にも開始と終了がある
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141660/95cbe462-946e-9685-e4dd-a249a6928428.png)

## まとめ

お勧めの書き方は、

- 状態を宣言する
- 状態の宣言の後に遷移を宣言する
- 合成に遷移する場合は、合成の中の状態は合成の中の状態だけで遷移する
- 合成に遷移しない場合は、すべての遷移を状態の宣言の後に行う

です。
この順に記載すると、メンテがしやすいのではないかと思います。
お試しあれ。