Web開発でもアプリ開発でも使える状態遷移図を自動生成するツールを作りました

# 概要

先日[こちらの記事](http://qiita.com/hideshi/items/2b671033766b9602c38d)でgraphvizを使って状態遷移図を作成する方法をご紹介したのですが、これでもまだ複雑で記述量も多いのでとっつきづらいと思い、このgraphvizのソースコードを自動生成して画像を出力するコマンドラインアプリケーションを作成しました。

このアプリケーションはPyagram（ぱいあぐらむ）といい、その名前から察しがつくかと思いますがPythonを使用して開発されました。開発期間は１日でした。

このPyagramを使うことで複雑な状態遷移図を比較的簡単に作成することができるようになりますので、以下でご紹介したいと思います。

状態遷移図の描き方については[こちらの記事](http://d.hatena.ne.jp/m-hiyama/20100820/1282270208)を参考にしています。

出来上がりの図は以下のような感じになります。

![crud_ja.png](https://qiita-image-store.s3.amazonaws.com/0/249/b83151b2-a258-9a83-6262-94833f49e8ba.png)

図には幾つかのオブジェクトがあります。

- 図のタイトル（最上段）
- ビュー（二重丸）
- サーバサイドの処理（灰色の背景の一重丸）
- 画面遷移（破線の矢印）
- 処理の流れ（直線の矢印）

上記の図はWebアプリの図になりますが、スマホアプリとサーバサイドが連携するような複雑度の高いフローも工夫次第で書けると思います。


# ソースコードの書き方

まずはじめに"＠"を使って図のタイトルを設定します。

```
@[title]
画面遷移図例
```

次に"#"と"-->"を使って画面とその遷移を定義します。

この例では一覧、新規作成、エラーの３画面があり、一覧と新規作成画面ではお互いにつながっています。

また、画面遷移は１画面に複数定義することができ、画面名の下には画面のパスも定義できます。

後々サーバーサイドの処理を追加していくときのガイドラインになりますので、最初にこのような形で画面だけの遷移を先に定義しておくことをお勧めします。

```
#[一覧画面]
/index

--> 新規作成画面

#[新規作成画面]
/add

--> 一覧画面

--> 新規作成画面

#[サーバエラー画面]
```

その次に"==>"を使って画面やサーバサイドの処理をつなげていきます。

下記の例のように、一つの処理に複数の分岐を書くことができます。

また、矢印の横に表示されるラベル用の文字列も定義することができます。ここには主に処理の結果を書いたりします。

```
$[GET /index]
==> 一覧画面

$[GET /add]
==> 新規作成画面

$[POST /add]
==> バリデーション

$[バリデーション]
入力値が妥当な場合
==> 保存

入力値が不正な場合
==> 新規作成画面

$[保存]
成功
==> 一覧画面

データベースエラー
==> サーバエラー画面
```

最後に画面からのアクションを”==>”でつなげていきます。

```
#[一覧画面]
/index

--> 新規作成画面

新規作成ボタンをクリック
==> GET /add


#[新規作成画面]
/add

--> 一覧画面

--> 新規作成画面

戻るボタンをクリック
==> GET /index

登録ボタンをクリック
==> POST /add
```

[Github](https://github.com/hideshi/pyagram)には他にもサンプルがありますので、参考にしてみてください。

# インストール方法

pip3コマンドでインストールするとpyparsingのような依存ライブラリも同時にインストールしてくれます。

インストールが終わるとpyagramコマンドが/usr/local/bin/pyagramのような感じで適当なbinディレクトリに保存されます。

graphviz自体は各種OS用があるようなのですが、手元にはMacしかないため、さしあたってMacOSのみ対応とさせていただいています。他のOSでも動いたというレポートは大歓迎です。

```
pip3 install pyagram
```


# 実行方法　

pyagramコマンドは引数を２つとります。

１つ目はtオプションで、画像フォーマットを設定します。画像フォーマットにはgif、png、svgの３種類が使用できます。

２つ目はiオプションで、入力ファイルを設定します。拡張子は任意で、なくても大丈夫です。

3つ目はoオプションで、出力パスを指定します。指定がない場合は入力ファイルと同じ場所に出力されます。

4つ目はフォント名です。指定がない場合はデフォルトのフォントを使用します。フォント名にスペースが含まれる場合は""（ダブルクォーテーション）で囲んでください。

```
pyagram -t {image type} -i {source file}　-o {output path}　-f {font name} -d std
```

# 実装について

字句解析、構文解析、中間ファイル生成、画像ファイル生成の４つの処理に分かれています。

字句解析についてはpyparsingというパーサコンビネータを使用することで、複雑な正規表現を使用することなく処理できるようにしました。

構文解析では字句解析で生成したデータを使って抽象構文木を生成しています。もう少しちゃんとしたBNFを作れば構文解析はもっと単純化できそうかもと思っているのですが、これは後々の課題としたいと思います。

中間ファイル生成ではgraphvizのソースコードを出力した後に。graphvizコマンドを使用して画像ファイルを出力します。中間ファイルは使用後は削除されるようになっています。


# 今後について

業務で図を書くことが徐々に増えてきたのですが、図によって使用するツールが違ったりして面倒になってきたので、個人的に使用する図は全てPyagramで作れるようにしたいと思っています。

また何かご要望があれば時間があるときにでも追加しようと思います。


# 補足

思いがけず大きな反響をいただき驚いています。

少し補足をしますと、これを作った動機としては、仕様をもう少し分かりやすく伝えたいけど、あまり図の作成には時間をかけたくない（かけられない）というのがありました。特にテスターに結合テストをしてもらう場合、少なくとも画面遷移図がないとテストがやりづらいという事情がありました。また、私自身はマネジメント的な立場で、どちらかというと顧客や開発者とのコミュニケーションとかプロジェクト進行、設計などが業務の大半なのですが、実装にもある程度首を突っ込みたい（でないと時折メンテナンスしづらいものが出来上がってしまうことがある）という事情もあり、ある程度細かい粒度の内容も記述できるようにしています。

時間をあまりかけないというところに重点が置かれていますので、体裁は二の次になっています。Graphvizで図を生成すると毎回レイアウトが変わってしまうのですが、もしこれが気になるようでしたら何度かコマンドを実行してみてください。何度かやるとある程度納得のいくレイアウトになると思います。ちなみに私の手元にあるソースコードでは何度コマンドを実行してもレイアウトが全く変わらないものもありました。この辺りのアルゴリズムはGraphviz依存なのではっきりとしたことは言えないのですが、オブジェクトが増えてくるとレイアウトも固定化される傾向にあるように感じました。


また、スマホアプリとWebAPI連携の図を書くための新しいシンタックスを導入しました。

```
%[クライアントサイドの処理名]
```

という風に書くと背景色なしの一重丸が表示されます。スマホアプリやAngularJSに代表されるSPAフレームワークなどのクライアント側の処理を書くために使われることを想定しています。

PyPIにもアップ済みですので、上に記載したpip3コマンドで最新版がインストールされます。

もしすでにインストールされている方は以下のコマンドでアップグレードできます。

```
pip3 install pyagram --upgrade
```

ご参考までにAngularJSとCordovaを使ったハイブリッドアプリとWeb APIが連携するようなシステムを想定した図を添付します。

![mobile_app.png](https://qiita-image-store.s3.amazonaws.com/0/249/1f88083c-33d1-aacf-db3f-e59d90913bc5.png)

ソースコードの書き方については以下のリンクを参考にしてみてください。

https://github.com/hideshi/pyagram/blob/master/example/mobile_app.txt

# 補足 2016/07/28
[KAMEDA Akihiro](https://github.com/cm3)さんにWindows対応していただきました。
それに加えフォントの種類も指定できるコマンドラインオプションを追加してくださいました。
ありがとうございます。

使い方は以下のようになります。

```
pyagram -t {画像タイプ} -o {出力パス} -i {入力ファイル} -f {フォント名}
```

フォント名にスペースが含まれる場合は、以下のようにダブルクウォートで囲むと動作します。

```
pyagram -t {画像タイプ} -o {出力パス} -i {入力ファイル} -f "ヒラギノ角ゴ Pro"
```

最新版をpip3コマンドで取得できるようになっていますので、ぜひお試しください。

# 補足 2016/07/30
[YOSHIDA Katsuhiko](https://github.com/kyoshidajp)さんに幾つか改善をしていただきました。
ありがとうございます。

- 入力ファイルの拡張子が任意になりました。拡張子無しでもOKです。
- &%@$#<>?を文字に含められるようになりました。

# 補足 2016/07/31
[ER図を生成する新機能](http://qiita.com/hideshi/items/b4d83eeb4305cda76359)を追加しました。

# 補足 2016/08/14
ご要望があったこともあり、[Pyagramを使った状態遷移図を作成できるWebサービス](http://www.diagram.gq/)を公開しました。ソースコードを入力して画像生成ボタンを押すだけで状態遷移図の画像が取得できます。
ただシステムの特性上、生成された画像が一時的にサーバに保存されます。また今のところSSLを導入していないので、送信したソースコードは平文で送信されます。そのため送信しても差し支えない場合だけご利用いただき、それ以外の場合はPyagramをご利用ください。
また、継続的にサービスをご提供できるようアフィリエイトを表示しています。ご理解のほどお願いいたします。