背景
業務でシステムアクティビティ図をエクセルで作成していますが、若干非効率な気がしており、効率化の種になるかもと思い、無償ツールであるPlantUMLを触ってみました。そして、昨今話題の生成AIの一つであるChatGPTを活用し、システムアクティビティ図を自動生成してみます。
PlantUMLとは?
PlantUMLは、テキストベースでUML図を描画するためのツールです。シンプルな記法を使い、クラス図やシーケンス図、システムアクティビティ図などを生成できます。
専用の記法でスクリプトを作成すると、UML図を自動で描くことができます。
システムアクティビティ図とは?
システムアクティビティ図は、システム内のプロセスや操作の流れを視覚化するUML図です。アクティビティ(活動)やその順序、条件分岐を示し、システムの動作を理解しやすくします。
使用ソフトウェアとVersion
- VSC(Visual Stdio Code):v1.92.2
- PlantUML:v2.18.1
VSCのプラグインをインストール
VSCの拡張としてダウンロードできるようです。
サンプルコードを試してみる
以下サイトにサンプルコードがあるため、コピペしてみます。
https://plantuml.com/ja/activity-diagram-beta
しかし、ダイアグラムが表示されない。。。
と思いWebを調べているうちになぜかダイアグラムが表示されました。
ううむ。ちょっとラグがありますね(10秒くらい?)。
サンプルコードをいじってみる
サンプルコードをいじってみます。
redと書かれている部分をblueに変更してみました。
@startuml
|#lightblue|Actor_For_blue|
start
if (color?) is (blue) then
#lightblue:**action blue**;
:foo1;
else (not blue)
|#lightgray|Actor_For_no_blue|
#lightgray:**action not red**;
:foo2;
endif
|Next_Actor|
#lightblue:foo3;
:foo4;
|Final_Actor|
#palegreen:foo5;
stop
@enduml
なんと、リアルタイムにダイアグラムが更新されるではありませんか!すごい!
ChatGPTでシステムアクティビティ図を自動生成してみる
開発に利用される要求仕様書などは自然言語で記述されることが多いと思います。ChatGPTなどの生成AIは自然言語の処理が得意なため、自然言語で記述された内容をPlantUMLのフォーマットに変換する処理ができるのではと考えました。
ということで、以下要求をChatGPTに依頼してみました。
以下の要件をPlantUMLのシステムアクティビティとして記述してください。
①センターは、デバイスAに対しコマンドを送信する
②デバイスAは、センターから受信したコマンドを解析する
③デバイスAは、②の解析結果が正常な場合、デバイスBに対し操作要求を送信する
④デバイスAは、②の解析結果が正常な場合、デバイスBからの操作結果を受信する
⑤デバイスAは、②の解析結果が正常な場合、結果コード:正常をセンターへ通知する
⑥デバイスAは、②の解析結果が異常な場合、結果コード:異常をセンターへ通知する
PlantUMLのシステムアクティビティ図で上記の要件を表現するには、以下のコードを使用できます。このコードは、デバイスAがセンターからコマンドを受信し、そのコマンドを解析して、デバイスBに操作要求を送信し、操作結果を受信して、結果コードをセンターへ通知するプロセスを示しています。
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信する;
:コマンドを解析する;
alt 解析結果が正常
:デバイスBに操作要求を送信する;
:デバイスBから操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else 解析結果が異常
:結果コード:異常をセンターへ通知する;
end
stop
@enduml
VSCにコピペしてみると・・・
Error found in diagram sample
ERROR
7
Syntax Error?
Some diagram description contains errors
PlantUMLのVersionが古いのでアップデートせよという意味のようです。
しかし、PlantUMLは現時点で最新版のため、コードが怪しいと考え、サンプルコードと比較してみました。
<サンプルコード>
if (条件?) is (A) then
:処理A;
else (not A)
:処理B;
endif
<ChatGPTが作成したコード>
alt 条件
:処理
else 条件
明らかに構文が異なるので、ChatGPTへの指示を見直しました。
同様のエラーが発生しています。なお、正常に動作しているサンプルコードを以下に示しますので、この構文を参考にコードを修正してください。
@startuml
|#lightblue|Actor_For_blue|
start
if (color?) is (blue) then
lightblue:action blue;
:foo1;
else (not blue)
|#lightgray|Actor_For_no_blue|
lightgray:action not red;
:foo2;
endif
|Next_Actor|
lightblue:foo3;
:foo4;
|Final_Actor|
palegreen:foo5;
stop
@enduml
提供していただいたサンプルコードを参考にして、指定された要件を満たすように構文を修正しました。以下は、PlantUMLのアクティビティ図を正しい構文で表現したものです:
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信する;
:コマンドを解析する;
if (解析結果が正常?) then (yes)
:デバイスBに操作要求を送信する;
:デバイスBから操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else (no)
:結果コード:異常をセンターへ通知する;
endif
stop
@enduml
ダイアグラムが表示されました!
しかしながら、スイムレーンが2つしかない。。。デバイスBの存在を認識できていないようです。
アクティビティ図が生成できました。
なお、スイムレーンが以下3つになるように修正してください。
①センター
②デバイスA
③デバイスB
スイムレーンを追加するために、各アクターやデバイスに対してレーンを設定する必要があります。以下のPlantUMLコードは、スイムレーンを指定して、プロセスの流れを3つのレーンで表現しています。
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信する;
:コマンドを解析する;
if (解析結果が正常?) then (yes)
|デバイスB|
:デバイスBに操作要求を送信する;
|デバイスA|
:デバイスBから操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else (no)
:結果コード:異常をセンターへ通知する;
endif
stop
@enduml
うーん、惜しい。。。デバイスB側の要求の記述を省いてしまったためですね。でも察してほしいところではあります。
ChatGPTへの指示を具体化します。
指示が曖昧でした。要件を詳細化しますね。
①センターは、デバイスAに対しコマンドを送信する
②デバイスAは、センターから受信したコマンドを解析する
③デバイスAは、②の解析結果が正常な場合、デバイスBに対し操作要求を送信する
④デバイスBは、デバイスA操作要求を受信する
⑤デバイスBは、デバイスAに操作結果を送信する
⑥デバイスAは、②の解析結果が正常な場合、デバイスBからの操作結果を受信する
⑦デバイスAは、②の解析結果が正常な場合、結果コード:正常をセンターへ通知する
⑧デバイスAは、②の解析結果が異常な場合、結果コード:異常をセンターへ通知する
指示いただいた要件に基づいて、3つのスイムレーン(センター、デバイスA、デバイスB)を持つアクティビティ図を修正しました。以下のPlantUMLコードは、各プロセスステップとその関連するレーンを正確に反映しています。
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信する;
:コマンドを解析する;
alt 解析結果が正常
|デバイスA|
:デバイスBに操作要求を送信する;
|デバイスB|
:操作要求を受信する;
|デバイスA|
:デバイスBからの操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else 解析結果が異常
|デバイスA|
:結果コード:異常をセンターへ通知する;
end
stop
@enduml
おや、構文の話をすっかり忘れてしまったようです。。。
構文エラーが再度発生しています。構文は先に示したサンプルコードに従ってください。
>なお、正常に動作しているサンプルコードを以下に示しますので、この構文を参考にコードを修正してください。
了解しました。先に示されたサンプルコードに従って、スイムレーンの構文を使って修正します。以下は、指定された要件に基づいたPlantUMLコードです。
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信する;
:コマンドを解析する;
alt 解析結果が正常
|デバイスA|
:デバイスBに操作要求を送信する;
|デバイスB|
:操作要求を受信する;
|デバイスA|
:デバイスBからの操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else 解析結果が異常
|デバイスA|
:結果コード:異常をセンターへ通知する;
end
stop
@enduml
サンプルコードのことを忘れてしまったということなのでしょうか。。。ではこのように指示すればよいのでしょうか。
エラーが解消されません。要求を詳細化します。
■要求仕様
①センターは、デバイスAに対しコマンドを送信する
②デバイスAは、センターから受信したコマンドを解析する
③デバイスAは、②の解析結果が正常な場合、デバイスBに対し操作要求を送信する
④デバイスBは、デバイスA操作要求を受信する
⑤デバイスBは、デバイスAに操作結果を送信する
⑥デバイスAは、②の解析結果が正常な場合、デバイスBからの操作結果を受信する
⑦デバイスAは、②の解析結果が正常な場合、結果コード:正常をセンターへ通知する
⑧デバイスAは、②の解析結果が異常な場合、結果コード:異常をセンターへ通知する
■前提
スイムレーンは3つ
・センター
・デバイスA
・デバイスB
■構文
構文は以下サンプルコードに従う
@startuml
|#lightblue|Actor_For_blue|
start
if (color?) is (blue) then
lightblue:action blue;
:foo1;
else (not blue)
|#lightgray|Actor_For_no_blue|
lightgray:action not red;
:foo2;
endif
|Next_Actor|
lightblue:foo3;
:foo4;
|Final_Actor|
palegreen:foo5;
stop
@enduml
ご指摘いただいた内容に基づき、PlantUMLのスイムレーン構文を使用してアクティビティ図を修正しました。以下のコードは、指定された要件とサンプルコードの構文に従ってスイムレーンを設定しています。
改善されず。。。サンプルコードをべた書きしてもダメですか。。。分岐はこう書いてねと書くのでしょうか。
エラーが解消されません。要求を詳細化します。
■要求仕様
①センターは、デバイスAに対しコマンドを送信する
②デバイスAは、センターから受信したコマンドを解析する
③デバイスAは、②の解析結果が正常な場合、デバイスBに対し操作要求を送信する
④デバイスBは、デバイスA操作要求を受信する
⑤デバイスBは、デバイスAに操作結果を送信する
⑥デバイスAは、②の解析結果が正常な場合、デバイスBからの操作結果を受信する
⑦デバイスAは、②の解析結果が正常な場合、結果コード:正常をセンターへ通知する
⑧デバイスAは、②の解析結果が異常な場合、結果コード:異常をセンターへ通知する
■前提
スイムレーンは3つ
・センター
・デバイスA
・デバイスB
■分岐に関する構文ルール
if (条件?) is (A) then
:処理A;
else (not A)
:処理B;
endif
了解しました。提供していただいた分岐に関する構文ルールを基に、スイムレーンを使ってアクティビティ図を修正しました。以下のPlantUMLコードは、スイムレーンと条件分岐を正しく使用しています。
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信する;
:コマンドを解析する;
if (解析結果が正常?) is (yes) then
|デバイスA|
:デバイスBに操作要求を送信する;
|デバイスB|
:操作要求を受信する;
|デバイスB|
:操作結果をデバイスAに送信する;
|デバイスA|
:デバイスBからの操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else (no)
|デバイスA|
:結果コード:異常をセンターへ通知する;
endif
stop
@enduml
意図通り書けている!!!(線がクロスしているのは仕方ないか・・・)
ChatGPTへの指示内容が固まったので、新規スレッドで同じ結果が得られるか試してみます。
以下の要求仕様をPlantUMLのシステムアクティビティとして記述してください。
■要求仕様
①センターは、デバイスAに対しコマンドを送信する
②デバイスAは、センターから受信したコマンドを解析する
③デバイスAは、②の解析結果が正常な場合、デバイスBに対し操作要求を送信する
④デバイスBは、デバイスA操作要求を受信する
⑤デバイスBは、デバイスAに操作結果を送信する
⑥デバイスAは、②の解析結果が正常な場合、デバイスBからの操作結果を受信する
⑦デバイスAは、②の解析結果が正常な場合、結果コード:正常をセンターへ通知する
⑧デバイスAは、②の解析結果が異常な場合、結果コード:異常をセンターへ通知する
■前提
スイムレーンは3つ
・センター
・デバイスA
・デバイスB
■分岐に関する構文ルール
if (条件?) is (A) then
:処理A;
else (not A)
:処理B;
endif
以下は、指定された要求仕様に基づいてPlantUMLでシステムアクティビティ図を記述したものです。スイムレーンを3つ(センター、デバイスA、デバイスB)に分け、条件分岐も含めています。
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信し解析する;
if (解析結果は正常?) then (はい)
|デバイスA|
:デバイスBに操作要求を送信する;
|デバイスB|
:操作要求を受信する;
|デバイスB|
:操作結果を送信する;
|デバイスA|
:操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else (いいえ)
|デバイスA|
:結果コード:異常をセンターへ通知する;
endif
|センター|
stop
@enduml
大体同じなのですが、細かい点で差異があります。
- 2つの動詞を1つにまとめている(受信し解析する)
- 助詞の揺らぎ(~は or ~が)
- 主語がなくなっている(デバイスB側の主語の記載がなくなった)
- アクティビティ終了の位置が異なる(先ほどはデバイスAで終了していたが、今回はセンターで終了している)
クリティカルな問題ではないですが、成果物という観点で見るとレビュー指摘をいただいてしまうことでしょう。
他のシステムアクティビティ図と表現を統一してください
ということは、ChatGPTで作成したシステムアクティビティ図をChatGPTにレビューさせてみればよいのでは。
あなたは優秀なシステムエンジニアです。
以下はPlantUMLで生成したシステムアクティビティ図です。
成果物①と成果物②を比較し、表現の揺らぎを指摘してください。
■成果物①
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信し解析する;
if (解析結果は正常?) then (はい)
|デバイスA|
:デバイスBに操作要求を送信する;
|デバイスB|
:操作要求を受信する;
|デバイスB|
:操作結果を送信する;
|デバイスA|
:操作結果を受信する;
:結果コード:正常をセンターへ通知する;
else (いいえ)
|デバイスA|
:結果コード:異常をセンターへ通知する;
endif
|センター|
stop
@enduml
■成果物②
@startuml
|センター|
start
:コマンドを送信する;
|デバイスA|
:コマンドを受信する;
:コマンドを解析する;
if (解析結果が正常?) is (yes) then
|デバイスA|
:デバイスBに操作要求を送信する;|デバイスB| :操作要求を受信する; |デバイスB| :操作結果をデバイスAに送信する; |デバイスA| :デバイスBからの操作結果を受信する; :結果コード:正常をセンターへ通知する;
else (no)
|デバイスA|
:結果コード:異常をセンターへ通知する;
endif
stop
@enduml
成果物①と成果物②のシステムアクティビティ図を比較してみましょう。以下の点で表現の揺らぎがあります:
「コマンドを解析する」の位置:
成果物①: 「コマンドを解析する」が「コマンドを受信し解析する」という一連のアクションとして描かれており、受信と解析が一つのアクションとして捉えられています。
成果物②: 「コマンドを解析する」が「コマンドを受信する」と別々のアクションとして描かれています。これにより、受信と解析が個別のアクションとして明確に示されています。
条件判断の表現:
成果物①: 条件判断の表現が「解析結果は正常?」と記述されています。
成果物②: 条件判断が「解析結果が正常?」となっており、「is (yes)」および「is (no)」の表記が使われています。これにより、条件判断の表示方法が異なります。
「操作結果を送信する」の対象:
成果物①: 「操作結果を送信する」というアクションが「デバイスB」から「デバイスA」への一方向の通信として描かれています。
成果物②: 同じアクションが「デバイスBからデバイスAへ送信する」となっており、より具体的にどのデバイスからどのデバイスへの送信かが示されています。
「結果コード:正常」の表現:
成果物①: 「結果コード:正常をセンターへ通知する」と表現されています。
成果物②: 「結果コード:正常をセンターへ通知する」という表現は同じですが、成果物②ではアクションの前に「デバイスBからの操作結果を受信する」というアクションが追加されています。
全体のレイアウトと流れ:
成果物①: 全体的に簡潔な表現がされています。条件分岐の直後に「センター」へ通知するアクションがあります。
成果物②: アクションがより詳細に分けられており、各ステップが明確に分かれています。また、条件分岐の前にすでに「コマンドを解析する」というアクションが分けて示されています。
これらの違いにより、成果物①と成果物②のアクティビティ図は若干異なる視点でシステムの流れを示しており、成果物②の方が各アクションの分離が明確で詳細に描写されています。
複数の動詞を1つにまとめてしまっていたり、助詞の使い方が揺らいでいる点は同じ指摘です。
しかし、主語が抜けているという指摘ではなく、成果物①と成果物②で異なる処理であると認識した上での指摘をしている様子です。奥が深いですね。人間と同じで、レビューの前提条件を記載しないと適切な指摘ができなさそうです。
まとめ
PlantUMLとChatGPTを組み合わせて自然言語からシステムアクティビティ図を自動生成できることがわかりました。
開発現場で使用している要求仕様書を直接ChatGPTへインプットするわけにはいかないので、活用方法を別途検討してみます。生成AIに関しては不勉強でお恥ずかしいですが、ローカルLLMだったらインプットできるのかなーとか妄想しています。
ローカルLLMはとても興味深い技術です。もし、ご興味ございましたら以下記事もご覧ください!
[…] PlantUMLとChatGPTを利用してシステムアクティビティ図を自動生成してみた Gemini APIを利用してWeb UIのチャットBOTを作成してみる Googleが提供する生成AI”Gemini”を利用してみた~通常利用、API使用まで~ ChatGPTでブログ記事を書いてみた […]
[…] PlantUMLとChatGPTを利用してシステムアクティビティ図を自動生成してみた Gemini APIを利用してWeb UIのチャットBOTを作成してみる […]
[…] PlantUMLとChatGPTを利用してシステムアクティビティ図を自動生成してみた […]